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:858
@ DEPENDENCY_NORMAL
Definition dependency.h:33
int errcode(int sqlerrcode)
Definition elog.c:874
int errhint(const char *fmt,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:36
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:151
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:47
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition pg_depend.c:353
END_CATALOG_STRUCT typedef FormData_pg_foreign_data_wrapper * Form_pg_foreign_data_wrapper
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
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:370
unsigned int Oid
static int fb(int x)
#define RelationGetDescr(relation)
Definition rel.h:540
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:4133
#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:227
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:1828
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:459
#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:188
#define NameStr(name)
Definition c.h:835
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 650 of file statscmds.c.

651{
652 Relation rel;
653 Oid stxoid;
659 ObjectAddress address;
660 int newtarget = 0;
662
663 /* -1 was used in previous versions for the default setting */
664 if (stmt->stxstattarget && intVal(stmt->stxstattarget) != -1)
665 {
666 newtarget = intVal(stmt->stxstattarget);
667 newtarget_default = false;
668 }
669 else
670 newtarget_default = true;
671
673 {
674 /* Limit statistics target to a sane range */
675 if (newtarget < 0)
676 {
679 errmsg("statistics target %d is too low",
680 newtarget)));
681 }
683 {
687 errmsg("lowering statistics target to %d",
688 newtarget)));
689 }
690 }
691
692 /* lookup OID of the statistics object */
693 stxoid = get_statistics_object_oid(stmt->defnames, stmt->missing_ok);
694
695 /*
696 * If we got here and the OID is not valid, it means the statistics object
697 * does not exist, but the command specified IF EXISTS. So report this as
698 * a simple NOTICE and we're done.
699 */
700 if (!OidIsValid(stxoid))
701 {
702 char *schemaname;
703 char *statname;
704
705 Assert(stmt->missing_ok);
706
707 DeconstructQualifiedName(stmt->defnames, &schemaname, &statname);
708
709 if (schemaname)
711 (errmsg("statistics object \"%s.%s\" does not exist, skipping",
712 schemaname, statname)));
713 else
715 (errmsg("statistics object \"%s\" does not exist, skipping",
716 statname)));
717
719 }
720
721 /* Search pg_statistic_ext */
723
726 elog(ERROR, "cache lookup failed for extended statistics object %u", stxoid);
727
728 /* Must be owner of the existing statistics object */
731 NameListToString(stmt->defnames));
732
733 /* Build new tuple. */
734 memset(repl_val, 0, sizeof(repl_val));
735 memset(repl_null, false, sizeof(repl_null));
736 memset(repl_repl, false, sizeof(repl_repl));
737
738 /* replace the stxstattarget column */
742 else
744
747
748 /* Update system catalog. */
749 CatalogTupleUpdate(rel, &newtup->t_self, newtup);
750
752
754
755 /*
756 * NOTE: because we only support altering the statistics target, not the
757 * other fields, there is no need to update dependencies.
758 */
759
762
764
765 return address;
766}
#define Assert(condition)
Definition c.h:943
#define NOTICE
Definition elog.h:35
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:5639
#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:426
#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 {
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:135
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:900
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 179 of file indexcmds.c.

184{
185 bool isconstraint;
186 Oid *typeIds;
192 HeapTuple tuple;
196 bool amcanorder;
197 bool amsummarizing;
199 IndexInfo *indexInfo;
201 int old_natts;
202 bool ret = true;
205 Relation irel;
206 int i;
207 Datum d;
208
209 /* Caller should already have the relation locked in some way. */
211
212 /*
213 * We can pretend isconstraint = false unconditionally. It only serves to
214 * decide the text of an error message that should never happen for us.
215 */
216 isconstraint = false;
217
221
222 /* look up the access method */
224 if (!HeapTupleIsValid(tuple))
227 errmsg("access method \"%s\" does not exist",
232 ReleaseSysCache(tuple);
233
234 amcanorder = amRoutine->amcanorder;
235 amsummarizing = amRoutine->amsummarizing;
236
237 /*
238 * Compute the operator classes, collations, and exclusion operators for
239 * the new index, so we can test whether it's compatible with the existing
240 * one. Note that ComputeIndexAttrs might fail here, but that's OK:
241 * DefineIndex would have failed later. Our attributeList contains only
242 * key attributes, thus we're filling ii_NumIndexAttrs and
243 * ii_NumIndexKeyAttrs with same value.
244 */
246 accessMethodId, NIL, NIL, false, false,
247 false, false, amsummarizing, isWithoutOverlaps);
253 ComputeIndexAttrs(NULL, indexInfo,
258 amcanorder, isconstraint, isWithoutOverlaps, InvalidOid,
259 0, NULL);
260
261 /* Get the soon-obsolete pg_index tuple. */
263 if (!HeapTupleIsValid(tuple))
264 elog(ERROR, "cache lookup failed for index %u", oldId);
266
267 /*
268 * We don't assess expressions or predicates; assume incompatibility.
269 * Also, if the index is invalid for any reason, treat it as incompatible.
270 */
273 indexForm->indisvalid))
274 {
275 ReleaseSysCache(tuple);
276 return false;
277 }
278
279 /* Any change in operator class or collation breaks compatibility. */
280 old_natts = indexForm->indnkeyatts;
282
285
288
289 ret = (memcmp(old_indclass->values, opclassIds, old_natts * sizeof(Oid)) == 0 &&
290 memcmp(old_indcollation->values, collationIds, old_natts * sizeof(Oid)) == 0);
291
292 ReleaseSysCache(tuple);
293
294 if (!ret)
295 return false;
296
297 /* For polymorphic opcintype, column type changes break compatibility. */
298 irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
299 for (i = 0; i < old_natts; i++)
300 {
302 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
303 {
304 ret = false;
305 break;
306 }
307 }
308
309 /* Any change in opclass options break compatibility. */
310 if (ret)
311 {
313
314 for (i = 0; i < old_natts; i++)
316
318
320 }
321
322 /* Any change in exclusion operator selections breaks compatibility. */
323 if (ret && indexInfo->ii_ExclusionOps != NULL)
324 {
326 *old_procs;
328
330 ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
331 old_natts * sizeof(Oid)) == 0;
332
333 /* Require an exact input type match for polymorphic operators. */
334 if (ret)
335 {
336 for (i = 0; i < old_natts && ret; i++)
337 {
338 Oid left,
339 right;
340
341 op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
342 if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
343 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
344 {
345 ret = false;
346 break;
347 }
348 }
349 }
350 }
351
352 index_close(irel, NoLock);
353 return ret;
354}
const IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition amapi.c:33
int16_t int16
Definition c.h:619
uint16_t uint16
Definition c.h:623
#define palloc_array(type, count)
Definition fe_memutils.h:76
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition heaptuple.c:456
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition index.c:3584
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:363
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:1881
#define AccessShareLock
Definition lockdefs.h:36
Oid get_opclass_input_type(Oid opclass)
Definition lsyscache.c:1384
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1089
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition lsyscache.c:1578
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:1616
#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:5644
Oid * ii_ExclusionOps
Definition execnodes.h:200
TupleDesc rd_att
Definition rel.h:112
Definition c.h:815
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 2634 of file indexcmds.c.

2637{
2638 int pass = 0;
2639 char *relname = NULL;
2640 char modlabel[NAMEDATALEN];
2643
2644 /* prepare to search pg_class with a dirty snapshot */
2647
2648 /* try the unmodified label first */
2649 strlcpy(modlabel, label, sizeof(modlabel));
2650
2651 for (;;)
2652 {
2653 ScanKeyData key[2];
2654 SysScanDesc scan;
2655 bool collides;
2656
2658
2659 /* is there any conflicting relation name? */
2660 ScanKeyInit(&key[0],
2664 ScanKeyInit(&key[1],
2668
2670 true /* indexOK */ ,
2672 2, key);
2673
2675
2676 systable_endscan(scan);
2677
2678 /* break out of loop if no conflict */
2679 if (!collides)
2680 {
2681 if (!isconstraint ||
2683 break;
2684 }
2685
2686 /* found a conflict, so try a new name component */
2687 pfree(relname);
2688 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2689 }
2690
2692
2693 return relname;
2694}
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:2546
static char * label
NameData relname
Definition pg_class.h:40
#define NAMEDATALEN
bool ConstraintNameExists(const char *conname, Oid namespaceid)
#define snprintf
Definition port.h:260
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 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:448
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:684
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:195
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:3879
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:2981
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition lsyscache.c:2491
char get_typtype(Oid typid)
Definition lsyscache.c:2851
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:748
@ COERCION_EXPLICIT
Definition primnodes.h:750
@ COERCION_IMPLICIT
Definition primnodes.h:747

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:260

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:1102

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:713
bool extension_file_exists(const char *extensionName)
Definition extension.c:2682
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:3054
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3588
void * palloc(Size size)
Definition mcxt.c:1387
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition namespace.c:3559
#define castNode(_type_, nodeptr)
Definition nodes.h:182
@ 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 /* Creating statistics on system catalogs is not allowed */
154 errmsg("permission denied: \"%s\" is a system catalog",
156 }
157
158 Assert(rel);
159 relid = RelationGetRelid(rel);
160
161 /*
162 * If the node has a name, split it up and determine creation namespace.
163 * If not, put the object in the same namespace as the relation, and cons
164 * up a name for it. (This can happen either via "CREATE STATISTICS ..."
165 * or via "CREATE TABLE ... (LIKE)".)
166 */
167 if (stmt->defnames)
169 &namestr);
170 else
171 {
175 "stat",
177 }
179
180 /*
181 * Check we have creation rights in target namespace. Skip check if
182 * caller doesn't want it.
183 */
184 if (check_rights)
185 {
187
190 if (aclresult != ACLCHECK_OK)
193 }
194
195 /*
196 * Deal with the possibility that the statistics object already exists.
197 */
201 {
202 if (stmt->if_not_exists)
203 {
204 /*
205 * Since stats objects aren't members of extensions (see comments
206 * below), no need for checkMembershipInCurrentExtension here.
207 */
210 errmsg("statistics object \"%s\" already exists, skipping",
211 namestr)));
214 }
215
218 errmsg("statistics object \"%s\" already exists", namestr)));
219 }
220
221 /*
222 * Make sure no more than STATS_MAX_DIMENSIONS columns are used. There
223 * might be duplicates and so on, but we'll deal with those later.
224 */
225 numcols = list_length(stmt->exprs);
229 errmsg("cannot have more than %d columns in statistics",
231
232 /*
233 * Convert the expression list to a simple array of attnums, but also keep
234 * a list of more complex expressions. While at it, enforce some
235 * constraints - we don't allow extended statistics on system attributes,
236 * and we require the data type to have a less-than operator, if we're
237 * building multivariate statistics.
238 *
239 * There are many ways to "mask" a simple attribute reference as an
240 * expression, for example "(a+0)" etc. We can't possibly detect all of
241 * them, but we handle at least the simple case with the attribute in
242 * parens. There'll always be a way around this, if the user is determined
243 * (like the "(a+0)" example), but this makes it somewhat consistent with
244 * how indexes treat attributes/expressions.
245 */
246 foreach(cell, stmt->exprs)
247 {
249
250 if (selem->name) /* column reference */
251 {
252 char *attname;
256
257 attname = selem->name;
258
263 errmsg("column \"%s\" does not exist",
264 attname)));
266
267 /* Disallow use of system attributes in extended stats */
268 if (attForm->attnum <= 0)
271 errmsg("statistics creation on system columns is not supported")));
272
273 /*
274 * Disallow data types without a less-than operator in
275 * multivariate statistics.
276 */
277 if (numcols > 1)
278 {
280 if (type->lt_opr == InvalidOid)
283 errmsg("column \"%s\" cannot be used in multivariate statistics because its type %s has no default btree operator class",
284 attname, format_type_be(attForm->atttypid))));
285 }
286
287 /* Treat virtual generated columns as expressions */
288 if (attForm->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
289 {
290 Node *expr;
291
292 expr = (Node *) makeVar(1,
293 attForm->attnum,
294 attForm->atttypid,
295 attForm->atttypmod,
296 attForm->attcollation,
297 0);
298 stxexprs = lappend(stxexprs, expr);
299 }
300 else
301 {
302 attnums[nattnums] = attForm->attnum;
303 nattnums++;
304 }
306 }
307 else if (IsA(selem->expr, Var)) /* column reference in parens */
308 {
309 Var *var = (Var *) selem->expr;
311
312 /* Disallow use of system attributes in extended stats */
313 if (var->varattno <= 0)
316 errmsg("statistics creation on system columns is not supported")));
317
318 /*
319 * Disallow data types without a less-than operator in
320 * multivariate statistics.
321 */
322 if (numcols > 1)
323 {
324 type = lookup_type_cache(var->vartype, TYPECACHE_LT_OPR);
325 if (type->lt_opr == InvalidOid)
328 errmsg("column \"%s\" cannot be used in multivariate statistics because its type %s has no default btree operator class",
329 get_attname(relid, var->varattno, false), format_type_be(var->vartype))));
330 }
331
332 /* Treat virtual generated columns as expressions */
333 if (get_attgenerated(relid, var->varattno) == ATTRIBUTE_GENERATED_VIRTUAL)
334 {
335 stxexprs = lappend(stxexprs, (Node *) var);
336 }
337 else
338 {
339 attnums[nattnums] = var->varattno;
340 nattnums++;
341 }
342 }
343 else /* expression */
344 {
345 Node *expr = selem->expr;
346 Oid atttype;
348 Bitmapset *attnums = NULL;
349 int k;
350
351 Assert(expr != NULL);
352
353 pull_varattnos(expr, 1, &attnums);
354
355 k = -1;
356 while ((k = bms_next_member(attnums, k)) >= 0)
357 {
359
360 /* Disallow expressions referencing system attributes. */
361 if (attnum <= 0)
364 errmsg("statistics creation on system columns is not supported")));
365 }
366
367 /*
368 * Disallow data types without a less-than operator in
369 * multivariate statistics.
370 */
371 if (numcols > 1)
372 {
373 atttype = exprType(expr);
375 if (type->lt_opr == InvalidOid)
378 errmsg("expression cannot be used in multivariate statistics because its type %s has no default btree operator class",
379 format_type_be(atttype))));
380 }
381
382 stxexprs = lappend(stxexprs, expr);
383 }
384 }
385
386 /*
387 * Check that at least two columns were specified in the statement, or
388 * that we're building statistics on a single expression (or virtual
389 * generated column).
390 */
391 if (numcols < 2 && list_length(stxexprs) != 1)
394 errmsg("cannot create extended statistics on a single non-virtual column"),
395 errdetail("Univariate statistics are already built for each individual non-virtual table column."));
396
397 /*
398 * Parse the statistics kinds (not allowed when building univariate
399 * statistics).
400 */
401 if (numcols == 1 && stmt->stat_types != NIL)
404 errmsg("cannot specify statistics kinds when building univariate statistics"));
405
406 build_ndistinct = false;
407 build_dependencies = false;
408 build_mcv = false;
409 foreach(cell, stmt->stat_types)
410 {
411 char *type = strVal(lfirst(cell));
412
413 if (strcmp(type, "ndistinct") == 0)
414 {
415 build_ndistinct = true;
416 requested_type = true;
417 }
418 else if (strcmp(type, "dependencies") == 0)
419 {
420 build_dependencies = true;
421 requested_type = true;
422 }
423 else if (strcmp(type, "mcv") == 0)
424 {
425 build_mcv = true;
426 requested_type = true;
427 }
428 else
431 errmsg("unrecognized statistics kind \"%s\"",
432 type)));
433 }
434
435 /*
436 * If no statistic type was specified, build them all (but only when the
437 * statistics is defined on more than one column/expression).
438 */
439 if ((!requested_type) && (numcols >= 2))
440 {
441 build_ndistinct = true;
442 build_dependencies = true;
443 build_mcv = true;
444 }
445
446 /*
447 * When there are non-trivial expressions, build the expression stats
448 * automatically. This allows calculating good estimates for stats that
449 * consider per-clause estimates (e.g. functional dependencies).
450 */
452
453 /*
454 * Sort the attnums, which makes detecting duplicates somewhat easier, and
455 * it does not hurt (it does not matter for the contents, unlike for
456 * indexes, for example).
457 */
458 qsort(attnums, nattnums, sizeof(int16), compare_int16);
459
460 /*
461 * Check for duplicates in the list of columns. The attnums are sorted so
462 * just check consecutive elements.
463 */
464 for (i = 1; i < nattnums; i++)
465 {
466 if (attnums[i] == attnums[i - 1])
469 errmsg("duplicate column name in statistics definition")));
470 }
471
472 /*
473 * Check for duplicate expressions. We do two loops, counting the
474 * occurrences of each expression. This is O(N^2) but we only allow small
475 * number of expressions and it's not executed often.
476 *
477 * XXX We don't cross-check attributes and expressions, because it does
478 * not seem worth it. In principle we could check that expressions don't
479 * contain trivial attribute references like "(a)", but the reasoning is
480 * similar to why we don't bother with extracting columns from
481 * expressions. It's either expensive or very easy to defeat for
482 * determined user, and there's no risk if we allow such statistics (the
483 * statistics is useless, but harmless).
484 */
485 foreach(cell, stxexprs)
486 {
487 Node *expr1 = (Node *) lfirst(cell);
488 int cnt = 0;
489
490 foreach(cell2, stxexprs)
491 {
492 Node *expr2 = (Node *) lfirst(cell2);
493
494 if (equal(expr1, expr2))
495 cnt += 1;
496 }
497
498 /* every expression should find at least itself */
499 Assert(cnt >= 1);
500
501 if (cnt > 1)
504 errmsg("duplicate expression in statistics definition")));
505 }
506
507 /* Form an int2vector representation of the sorted column list */
508 stxkeys = buildint2vector(attnums, nattnums);
509
510 /* construct the char array of enabled statistic types */
511 ntypes = 0;
512 if (build_ndistinct)
516 if (build_mcv)
520 Assert(ntypes > 0 && ntypes <= lengthof(types));
522
523 /* convert the expressions (if any) to a text datum */
524 if (stxexprs != NIL)
525 {
526 char *exprsString;
527
531 }
532 else
533 exprsDatum = (Datum) 0;
534
536
537 /*
538 * Everything seems fine, so let's build the pg_statistic_ext tuple.
539 */
540 memset(values, 0, sizeof(values));
541 memset(nulls, false, sizeof(nulls));
542
551 nulls[Anum_pg_statistic_ext_stxstattarget - 1] = true;
553
555 if (exprsDatum == (Datum) 0)
556 nulls[Anum_pg_statistic_ext_stxexprs - 1] = true;
557
558 /* insert it into pg_statistic_ext */
559 htup = heap_form_tuple(statrel->rd_att, values, nulls);
561 heap_freetuple(htup);
562
564
565 /*
566 * We used to create the pg_statistic_ext_data tuple too, but it's not
567 * clear what value should the stxdinherit flag have (it depends on
568 * whether the rel is partitioned, contains data, etc.)
569 */
570
572
573 /*
574 * Invalidate relcache so that others see the new statistics object.
575 */
577
579
580 /*
581 * Add an AUTO dependency on each column used in the stats, so that the
582 * stats object goes away if any or all of them get dropped.
583 */
585
586 /* add dependencies for plain column references */
587 for (i = 0; i < nattnums; i++)
588 {
591 }
592
593 /*
594 * If there are no dependencies on a column, give the statistics object an
595 * auto dependency on the whole table. In most cases, this will be
596 * redundant, but it might not be if the statistics expressions contain no
597 * Vars (which might seem strange but possible). This is consistent with
598 * what we do for indexes in index_create.
599 *
600 * XXX We intentionally don't consider the expressions before adding this
601 * dependency, because recordDependencyOnSingleRelExpr may not create any
602 * dependencies for whole-row Vars.
603 */
604 if (!nattnums)
605 {
608 }
609
610 /*
611 * Store dependencies on anything mentioned in statistics expressions,
612 * just like we do for index expressions.
613 */
614 if (stxexprs)
616 (Node *) stxexprs,
617 relid,
619 DEPENDENCY_AUTO, false);
620
621 /*
622 * Also add dependencies on namespace and owner. These are required
623 * because the stats object might have a different namespace and/or owner
624 * than the underlying table(s).
625 */
628
630
631 /*
632 * XXX probably there should be a recordDependencyOnCurrentExtension call
633 * here too, but we'd have to add support for ALTER EXTENSION ADD/DROP
634 * STATISTICS, which is more work than it seems worth.
635 */
636
637 /* Add any requested comment */
638 if (stmt->stxcomment != NULL)
640 stmt->stxcomment);
641
642 /* Return stats object's address */
643 return myself;
644}
int16 AttrNumber
Definition attnum.h:21
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1290
#define lengthof(array)
Definition c.h:873
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:130
int2vector * buildint2vector(const int16 *int2s, int n)
Definition int.c:114
void CacheInvalidateRelcache(Relation relation)
Definition inval.c:1635
#define ShareUpdateExclusiveLock
Definition lockdefs.h:39
char get_attgenerated(Oid relid, AttrNumber attnum)
Definition lsyscache.c:1007
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:946
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:164
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:495
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:393
#define RelationGetRelid(relation)
Definition rel.h:514
#define RelationGetRelationName(relation)
Definition rel.h:548
#define RelationGetNamespace(relation)
Definition rel.h:555
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:902
static char * ChooseExtendedStatisticName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition statscmds.c:860
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:830
#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, 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:303
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:139
int pg_strcasecmp(const char *s1, const char *s2)
char * defname
Definition parsenodes.h:860
Node * arg
Definition parsenodes.h:861

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(), 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(), 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:620

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:621
Datum int8in(PG_FUNCTION_ARGS)
Definition int8.c:50
static int64 DatumGetInt64(Datum X)
Definition postgres.h:403
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:1781
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(), 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(), 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:3096
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 545 of file indexcmds.c.

557{
558 bool concurrent;
559 char *indexRelationName;
560 char *accessMethodName;
561 Oid *typeIds;
571 Relation rel;
572 HeapTuple tuple;
575 bool amcanorder;
576 bool amissummarizing;
577 amoptions_function amoptions;
578 bool exclusion;
579 bool partitioned;
580 bool safe_index;
581 Datum reloptions;
583 IndexInfo *indexInfo;
584 uint16 flags;
589 ObjectAddress address;
590 LockRelId heaprelid;
592 LOCKMODE lockmode;
593 Snapshot snapshot;
597
599
601
602 /*
603 * Some callers need us to run with an empty default_tablespace; this is a
604 * necessary hack to be able to reproduce catalog state accurately when
605 * recreating indexes after table-rewriting ALTER TABLE.
606 */
607 if (stmt->reset_default_tblspc)
608 (void) set_config_option("default_tablespace", "",
610 GUC_ACTION_SAVE, true, 0, false);
611
612 /*
613 * Force non-concurrent build on temporary relations, even if CONCURRENTLY
614 * was requested. Other backends can't access a temporary relation, so
615 * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
616 * is more efficient. Do this before any use of the concurrent option is
617 * done.
618 */
620 concurrent = true;
621 else
622 concurrent = false;
623
624 /*
625 * Start progress report. If we're building a partition, this was already
626 * done.
627 */
629 {
632 concurrent ?
635 }
636
637 /*
638 * No index OID to report yet
639 */
641 InvalidOid);
642
643 /*
644 * count key attributes in index
645 */
646 numberOfKeyAttributes = list_length(stmt->indexParams);
647
648 /*
649 * Calculate the new list of index columns including both key columns and
650 * INCLUDE columns. Later we can determine which of these are key
651 * columns, and which are just part of the INCLUDE list by checking the
652 * list position. A list item in a position less than ii_NumIndexKeyAttrs
653 * is part of the key columns, and anything equal to and over is part of
654 * the INCLUDE columns.
655 */
656 allIndexParams = list_concat_copy(stmt->indexParams,
657 stmt->indexIncludingParams);
659
660 if (numberOfKeyAttributes <= 0)
663 errmsg("must specify at least one column")));
667 errmsg("cannot use more than %d columns in an index",
669
670 /*
671 * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
672 * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
673 * (but not VACUUM).
674 *
675 * NB: Caller is responsible for making sure that tableId refers to the
676 * relation on which the index should be built; except in bootstrap mode,
677 * this will typically require the caller to have already locked the
678 * relation. To avoid lock upgrade hazards, that lock should be at least
679 * as strong as the one we take here.
680 *
681 * NB: If the lock strength here ever changes, code that is run by
682 * parallel workers under the control of certain particular ambuild
683 * functions will need to be updated, too.
684 */
685 lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
686 rel = table_open(tableId, lockmode);
687
688 /*
689 * Switch to the table owner's userid, so that any index functions are run
690 * as that user. Also lock down security-restricted operations. We
691 * already arranged to make GUC variable changes local to this command.
692 */
694 SetUserIdAndSecContext(rel->rd_rel->relowner,
696
698
699 /*
700 * It has exclusion constraint behavior if it's an EXCLUDE constraint or a
701 * temporal PRIMARY KEY/UNIQUE constraint
702 */
703 exclusion = stmt->excludeOpNames || stmt->iswithoutoverlaps;
704
705 /* Ensure that it makes sense to index this kind of relation */
706 switch (rel->rd_rel->relkind)
707 {
708 case RELKIND_RELATION:
709 case RELKIND_MATVIEW:
711 /* OK */
712 break;
713 default:
716 errmsg("cannot create index on relation \"%s\"",
719 break;
720 }
721
722 /*
723 * Establish behavior for partitioned tables, and verify sanity of
724 * parameters.
725 *
726 * We do not build an actual index in this case; we only create a few
727 * catalog entries. The actual indexes are built by recursing for each
728 * partition.
729 */
731 if (partitioned)
732 {
733 /*
734 * Note: we check 'stmt->concurrent' rather than 'concurrent', so that
735 * the error is thrown also for temporary tables. Seems better to be
736 * consistent, even though we could do it on temporary table because
737 * we're not actually doing it concurrently.
738 */
739 if (stmt->concurrent)
742 errmsg("cannot create index on partitioned table \"%s\" concurrently",
744 }
745
746 /*
747 * Don't try to CREATE INDEX on temp tables of other backends.
748 */
749 if (RELATION_IS_OTHER_TEMP(rel))
752 errmsg("cannot create indexes on temporary tables of other sessions")));
753
754 /*
755 * Unless our caller vouches for having checked this already, insist that
756 * the table not be in use by our own session, either. Otherwise we might
757 * fail to make entries in the new index (for instance, if an INSERT or
758 * UPDATE is in progress and has already made its list of target indexes).
759 */
761 CheckTableNotInUse(rel, "CREATE INDEX");
762
763 /*
764 * Verify we (still) have CREATE rights in the rel's namespace.
765 * (Presumably we did when the rel was created, but maybe not anymore.)
766 * Skip check if caller doesn't want it. Also skip check if
767 * bootstrapping, since permissions machinery may not be working yet.
768 */
770 {
772
774 ACL_CREATE);
775 if (aclresult != ACLCHECK_OK)
778 }
779
780 /*
781 * Select tablespace to use. If not specified, use default tablespace
782 * (which may in turn default to database's default).
783 */
784 if (stmt->tableSpace)
785 {
786 tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
790 errmsg("cannot specify default tablespace for partitioned relations")));
791 }
792 else
793 {
794 tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence,
796 /* note InvalidOid is OK in this case */
797 }
798
799 /* Check tablespace permissions */
800 if (check_rights &&
802 {
804
806 ACL_CREATE);
807 if (aclresult != ACLCHECK_OK)
810 }
811
812 /*
813 * Force shared indexes into the pg_global tablespace. This is a bit of a
814 * hack but seems simpler than marking them in the BKI commands. On the
815 * other hand, if it's not shared, don't allow it to be placed there.
816 */
817 if (rel->rd_rel->relisshared)
822 errmsg("only shared relations can be placed in pg_global tablespace")));
823
824 /*
825 * Choose the index column names.
826 */
828
829 /*
830 * Select name for index if caller didn't specify
831 */
832 indexRelationName = stmt->idxname;
833 if (indexRelationName == NULL)
837 stmt->excludeOpNames,
838 stmt->primary,
839 stmt->isconstraint);
840
841 /*
842 * look up the access method, verify it can handle the requested features
843 */
844 accessMethodName = stmt->accessMethod;
846 if (!HeapTupleIsValid(tuple))
847 {
848 /*
849 * Hack to provide more-or-less-transparent updating of old RTREE
850 * indexes to GiST: if RTREE is requested and not found, use GIST.
851 */
852 if (strcmp(accessMethodName, "rtree") == 0)
853 {
855 (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
856 accessMethodName = "gist";
858 }
859
860 if (!HeapTupleIsValid(tuple))
863 errmsg("access method \"%s\" does not exist",
865 }
869
872
873 if (stmt->unique && !stmt->iswithoutoverlaps && !amRoutine->amcanunique)
876 errmsg("access method \"%s\" does not support unique indexes",
878 if (stmt->indexIncludingParams != NIL && !amRoutine->amcaninclude)
881 errmsg("access method \"%s\" does not support included columns",
883 if (numberOfKeyAttributes > 1 && !amRoutine->amcanmulticol)
886 errmsg("access method \"%s\" does not support multicolumn indexes",
888 if (exclusion && amRoutine->amgettuple == NULL)
891 errmsg("access method \"%s\" does not support exclusion constraints",
893 if (stmt->iswithoutoverlaps && strcmp(accessMethodName, "gist") != 0)
896 errmsg("access method \"%s\" does not support WITHOUT OVERLAPS constraints",
898
899 amcanorder = amRoutine->amcanorder;
900 amoptions = amRoutine->amoptions;
901 amissummarizing = amRoutine->amsummarizing;
902
903 ReleaseSysCache(tuple);
904
905 /*
906 * Validate predicate, if given
907 */
908 if (stmt->whereClause)
909 CheckPredicate((Expr *) stmt->whereClause);
910
911 /*
912 * Parse AM-specific options, convert to text array form, validate.
913 */
914 reloptions = transformRelOptions((Datum) 0, stmt->options,
915 NULL, NULL, false, false);
916
917 (void) index_reloptions(amoptions, reloptions, true);
918
919 /*
920 * Prepare arguments for index_create, primarily an IndexInfo structure.
921 * Note that predicates must be in implicit-AND format. In a concurrent
922 * build, mark it not-ready-for-inserts.
923 */
927 NIL, /* expressions, NIL for now */
928 make_ands_implicit((Expr *) stmt->whereClause),
929 stmt->unique,
930 stmt->nulls_not_distinct,
931 !concurrent,
932 concurrent,
934 stmt->iswithoutoverlaps);
935
941 ComputeIndexAttrs(pstate,
942 indexInfo,
945 stmt->excludeOpNames, tableId,
947 amcanorder, stmt->isconstraint, stmt->iswithoutoverlaps,
950
951 /*
952 * Extra checks when creating a PRIMARY KEY index.
953 */
954 if (stmt->primary)
956
957 /*
958 * If this table is partitioned and we're creating a unique index, primary
959 * key, or exclusion constraint, make sure that the partition key is a
960 * subset of the index's columns. Otherwise it would be possible to
961 * violate uniqueness by putting values that ought to be unique in
962 * different partitions.
963 *
964 * We could lift this limitation if we had global indexes, but those have
965 * their own problems, so this is a useful feature combination.
966 */
967 if (partitioned && (stmt->unique || exclusion))
968 {
970 const char *constraint_type;
971 int i;
972
973 if (stmt->primary)
974 constraint_type = "PRIMARY KEY";
975 else if (stmt->unique)
976 constraint_type = "UNIQUE";
977 else if (stmt->excludeOpNames)
978 constraint_type = "EXCLUDE";
979 else
980 {
981 elog(ERROR, "unknown constraint type");
982 constraint_type = NULL; /* keep compiler quiet */
983 }
984
985 /*
986 * Verify that all the columns in the partition key appear in the
987 * unique key definition, with the same notion of equality.
988 */
989 for (i = 0; i < key->partnatts; i++)
990 {
991 bool found = false;
992 int eq_strategy;
994 int j;
995
996 /*
997 * Identify the equality operator associated with this partkey
998 * column. For list and range partitioning, partkeys use btree
999 * operator classes; hash partitioning uses hash operator classes.
1000 * (Keep this in sync with ComputePartitionAttrs!)
1001 */
1002 if (key->strategy == PARTITION_STRATEGY_HASH)
1004 else
1006
1007 ptkey_eqop = get_opfamily_member(key->partopfamily[i],
1008 key->partopcintype[i],
1009 key->partopcintype[i],
1010 eq_strategy);
1011 if (!OidIsValid(ptkey_eqop))
1012 elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
1013 eq_strategy, key->partopcintype[i], key->partopcintype[i],
1014 key->partopfamily[i]);
1015
1016 /*
1017 * It may be possible to support UNIQUE constraints when partition
1018 * keys are expressions, but is it worth it? Give up for now.
1019 */
1020 if (key->partattrs[i] == 0)
1021 ereport(ERROR,
1023 errmsg("unsupported %s constraint with partition key definition",
1025 errdetail("%s constraints cannot be used when partition keys include expressions.",
1026 constraint_type)));
1027
1028 /* Search the index column(s) for a match */
1029 for (j = 0; j < indexInfo->ii_NumIndexKeyAttrs; j++)
1030 {
1031 if (key->partattrs[i] == indexInfo->ii_IndexAttrNumbers[j])
1032 {
1033 /*
1034 * Matched the column, now what about the collation and
1035 * equality op?
1036 */
1039
1040 if (key->partcollation[i] != collationIds[j])
1041 continue;
1042
1044 &idx_opfamily,
1045 &idx_opcintype))
1046 {
1048
1049 if (stmt->unique && !stmt->iswithoutoverlaps)
1053 COMPARE_EQ);
1054 else if (exclusion)
1055 idx_eqop = indexInfo->ii_ExclusionOps[j];
1056
1057 if (!idx_eqop)
1058 ereport(ERROR,
1060 errmsg("could not identify an equality operator for type %s", format_type_be(idx_opcintype)),
1061 errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
1063
1064 if (ptkey_eqop == idx_eqop)
1065 {
1066 found = true;
1067 break;
1068 }
1069 else if (exclusion)
1070 {
1071 /*
1072 * We found a match, but it's not an equality
1073 * operator. Instead of failing below with an
1074 * error message about a missing column, fail now
1075 * and explain that the operator is wrong.
1076 */
1077 Form_pg_attribute att = TupleDescAttr(RelationGetDescr(rel), key->partattrs[i] - 1);
1078
1079 ereport(ERROR,
1081 errmsg("cannot match partition key to index on column \"%s\" using non-equal operator \"%s\"",
1082 NameStr(att->attname),
1083 get_opname(indexInfo->ii_ExclusionOps[j]))));
1084 }
1085 }
1086 }
1087 }
1088
1089 if (!found)
1090 {
1092
1094 key->partattrs[i] - 1);
1095 ereport(ERROR,
1097 /* translator: %s is UNIQUE, PRIMARY KEY, etc */
1098 errmsg("%s constraint on partitioned table must include all partitioning columns",
1100 /* translator: first %s is UNIQUE, PRIMARY KEY, etc */
1101 errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
1103 NameStr(att->attname))));
1104 }
1105 }
1106 }
1107
1108
1109 /*
1110 * We disallow indexes on system columns. They would not necessarily get
1111 * updated correctly, and they don't seem useful anyway.
1112 *
1113 * Also disallow virtual generated columns in indexes (use expression
1114 * index instead).
1115 */
1116 for (int i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1117 {
1118 AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i];
1119
1120 if (attno < 0)
1121 ereport(ERROR,
1123 errmsg("index creation on system columns is not supported")));
1124
1125
1126 if (attno > 0 &&
1127 TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1128 ereport(ERROR,
1130 stmt->primary ?
1131 errmsg("primary keys on virtual generated columns are not supported") :
1132 stmt->isconstraint ?
1133 errmsg("unique constraints on virtual generated columns are not supported") :
1134 errmsg("indexes on virtual generated columns are not supported"));
1135 }
1136
1137 /*
1138 * Also check for system and generated columns used in expressions or
1139 * predicates.
1140 */
1141 if (indexInfo->ii_Expressions || indexInfo->ii_Predicate)
1142 {
1144 int j;
1145
1146 pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
1147 pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
1148
1149 for (int i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
1150 {
1152 indexattrs))
1153 ereport(ERROR,
1155 errmsg("index creation on system columns is not supported")));
1156 }
1157
1158 /*
1159 * XXX Virtual generated columns in index expressions or predicates
1160 * could be supported, but it needs support in
1161 * RelationGetIndexExpressions() and RelationGetIndexPredicate().
1162 */
1163 j = -1;
1164 while ((j = bms_next_member(indexattrs, j)) >= 0)
1165 {
1167
1168 if (attno > 0 &&
1169 TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1170 ereport(ERROR,
1172 stmt->isconstraint ?
1173 errmsg("unique constraints on virtual generated columns are not supported") :
1174 errmsg("indexes on virtual generated columns are not supported")));
1175 }
1176 }
1177
1178 /* Is index safe for others to ignore? See set_indexsafe_procflags() */
1179 safe_index = indexInfo->ii_Expressions == NIL &&
1180 indexInfo->ii_Predicate == NIL;
1181
1182 /*
1183 * Report index creation if appropriate (delay this till after most of the
1184 * error checks)
1185 */
1186 if (stmt->isconstraint && !quiet)
1187 {
1188 const char *constraint_type;
1189
1190 if (stmt->primary)
1191 constraint_type = "PRIMARY KEY";
1192 else if (stmt->unique)
1193 constraint_type = "UNIQUE";
1194 else if (stmt->excludeOpNames)
1195 constraint_type = "EXCLUDE";
1196 else
1197 {
1198 elog(ERROR, "unknown constraint type");
1199 constraint_type = NULL; /* keep compiler quiet */
1200 }
1201
1203 (errmsg_internal("%s %s will create implicit index \"%s\" for table \"%s\"",
1204 is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
1207 }
1208
1209 /*
1210 * A valid stmt->oldNumber implies that we already have a built form of
1211 * the index. The caller should also decline any index build.
1212 */
1213 Assert(!RelFileNumberIsValid(stmt->oldNumber) || (skip_build && !concurrent));
1214
1215 /*
1216 * Make the catalog entries for the index, including constraints. This
1217 * step also actually builds the index, except if caller requested not to
1218 * or in concurrent mode, in which case it'll be done later, or doing a
1219 * partitioned index (because those don't have storage).
1220 */
1221 flags = constr_flags = 0;
1222 if (stmt->isconstraint)
1224 if (skip_build || concurrent || partitioned)
1225 flags |= INDEX_CREATE_SKIP_BUILD;
1226 if (stmt->if_not_exists)
1228 if (concurrent)
1229 flags |= INDEX_CREATE_CONCURRENT;
1230 if (partitioned)
1231 flags |= INDEX_CREATE_PARTITIONED;
1232 if (stmt->primary)
1233 flags |= INDEX_CREATE_IS_PRIMARY;
1234
1235 /*
1236 * If the table is partitioned, and recursion was declined but partitions
1237 * exist, mark the index as invalid.
1238 */
1239 if (partitioned && stmt->relation && !stmt->relation->inh)
1240 {
1242
1243 if (pd->nparts != 0)
1244 flags |= INDEX_CREATE_INVALID;
1245 }
1246
1247 if (stmt->deferrable)
1249 if (stmt->initdeferred)
1251 if (stmt->iswithoutoverlaps)
1253
1257 stmt->oldNumber, indexInfo, indexColNames,
1260 coloptions, NULL, reloptions,
1261 flags, constr_flags,
1264
1266
1268 {
1269 /*
1270 * Roll back any GUC changes executed by index functions. Also revert
1271 * to original default_tablespace if we changed it above.
1272 */
1274
1275 /* Restore userid and security context */
1277
1278 table_close(rel, NoLock);
1279
1280 /* If this is the top-level index, we're done */
1283
1284 return address;
1285 }
1286
1287 /*
1288 * Roll back any GUC changes executed by index functions, and keep
1289 * subsequent changes local to this command. This is essential if some
1290 * index function changed a behavior-affecting GUC, e.g. search_path.
1291 */
1295
1296 /* Add any requested comment */
1297 if (stmt->idxcomment != NULL)
1299 stmt->idxcomment);
1300
1301 if (partitioned)
1302 {
1303 PartitionDesc partdesc;
1304
1305 /*
1306 * Unless caller specified to skip this step (via ONLY), process each
1307 * partition to make sure they all contain a corresponding index.
1308 *
1309 * If we're called internally (no stmt->relation), recurse always.
1310 */
1311 partdesc = RelationGetPartitionDesc(rel, true);
1312 if ((!stmt->relation || stmt->relation->inh) && partdesc->nparts > 0)
1313 {
1314 int nparts = partdesc->nparts;
1315 Oid *part_oids = palloc_array(Oid, nparts);
1316 bool invalidate_parent = false;
1319
1320 /*
1321 * Report the total number of partitions at the start of the
1322 * command; don't update it when being called recursively.
1323 */
1325 {
1326 /*
1327 * When called by ProcessUtilitySlow, the number of partitions
1328 * is passed in as an optimization; but other callers pass -1
1329 * since they don't have the value handy. This should count
1330 * partitions the same way, ie one less than the number of
1331 * relations find_all_inheritors reports.
1332 *
1333 * We assume we needn't ask find_all_inheritors to take locks,
1334 * because that should have happened already for all callers.
1335 * Even if it did not, this is safe as long as we don't try to
1336 * touch the partitions here; the worst consequence would be a
1337 * bogus progress-reporting total.
1338 */
1339 if (total_parts < 0)
1340 {
1342
1343 total_parts = list_length(children) - 1;
1344 list_free(children);
1345 }
1346
1348 total_parts);
1349 }
1350
1351 /* Make a local copy of partdesc->oids[], just for safety */
1352 memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
1353
1354 /*
1355 * We'll need an IndexInfo describing the parent index. The one
1356 * built above is almost good enough, but not quite, because (for
1357 * example) its predicate expression if any hasn't been through
1358 * expression preprocessing. The most reliable way to get an
1359 * IndexInfo that will match those for child indexes is to build
1360 * it the same way, using BuildIndexInfo().
1361 */
1363 indexInfo = BuildIndexInfo(parentIndex);
1364
1366
1367 /*
1368 * For each partition, scan all existing indexes; if one matches
1369 * our index definition and is not already attached to some other
1370 * parent index, attach it to the one we just created.
1371 *
1372 * If none matches, build a new index by calling ourselves
1373 * recursively with the same options (except for the index name).
1374 */
1375 for (int i = 0; i < nparts; i++)
1376 {
1382 List *childidxs;
1383 ListCell *cell;
1384 AttrMap *attmap;
1385 bool found = false;
1386
1387 childrel = table_open(childRelid, lockmode);
1388
1391 SetUserIdAndSecContext(childrel->rd_rel->relowner,
1395
1396 /*
1397 * Don't try to create indexes on foreign tables, though. Skip
1398 * those if a regular index, or fail if trying to create a
1399 * constraint index.
1400 */
1401 if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1402 {
1403 if (stmt->unique || stmt->primary)
1404 ereport(ERROR,
1406 errmsg("cannot create unique index on partitioned table \"%s\"",
1408 errdetail("Table \"%s\" contains partitions that are foreign tables.",
1410
1414 table_close(childrel, lockmode);
1415 continue;
1416 }
1417
1419 attmap =
1421 parentDesc,
1422 false);
1423
1424 foreach(cell, childidxs)
1425 {
1426 Oid cldidxid = lfirst_oid(cell);
1429
1430 /* this index is already partition of another one */
1432 continue;
1433
1434 cldidx = index_open(cldidxid, lockmode);
1436 if (CompareIndexInfo(cldIdxInfo, indexInfo,
1437 cldidx->rd_indcollation,
1438 parentIndex->rd_indcollation,
1439 cldidx->rd_opfamily,
1440 parentIndex->rd_opfamily,
1441 attmap))
1442 {
1444
1445 /*
1446 * Found a match.
1447 *
1448 * If this index is being created in the parent
1449 * because of a constraint, then the child needs to
1450 * have a constraint also, so look for one. If there
1451 * is no such constraint, this index is no good, so
1452 * keep looking.
1453 */
1455 {
1456 cldConstrOid =
1458 cldidxid);
1459 if (cldConstrOid == InvalidOid)
1460 {
1461 index_close(cldidx, lockmode);
1462 continue;
1463 }
1464 }
1465
1466 /* Attach index to parent and we're done. */
1471 childRelid);
1472
1473 if (!cldidx->rd_index->indisvalid)
1474 invalidate_parent = true;
1475
1476 found = true;
1477
1478 /*
1479 * Report this partition as processed. Note that if
1480 * the partition has children itself, we'd ideally
1481 * count the children and update the progress report
1482 * for all of them; but that seems unduly expensive.
1483 * Instead, the progress report will act like all such
1484 * indirect children were processed in zero time at
1485 * the end of the command.
1486 */
1488
1489 /* keep lock till commit */
1491 break;
1492 }
1493
1494 index_close(cldidx, lockmode);
1495 }
1496
1502
1503 /*
1504 * If no matching index was found, create our own.
1505 */
1506 if (!found)
1507 {
1510
1511 /*
1512 * Build an IndexStmt describing the desired child index
1513 * in the same way that we do during ATTACH PARTITION.
1514 * Notably, we rely on generateClonedIndexStmt to produce
1515 * a search-path-independent representation, which the
1516 * original IndexStmt might not be.
1517 */
1520 attmap,
1521 NULL);
1522
1523 /*
1524 * Recurse as the starting user ID. Callee will use that
1525 * for permission checks, then switch again.
1526 */
1530 childAddr =
1531 DefineIndex(NULL, /* original pstate not applicable */
1533 InvalidOid, /* no predefined OID */
1534 indexRelationId, /* this is our child */
1536 -1,
1539 skip_build, quiet);
1542
1543 /*
1544 * Check if the index just created is valid or not, as it
1545 * could be possible that it has been switched as invalid
1546 * when recursing across multiple partition levels.
1547 */
1548 if (!get_index_isvalid(childAddr.objectId))
1549 invalidate_parent = true;
1550 }
1551
1553 }
1554
1555 index_close(parentIndex, lockmode);
1556
1557 /*
1558 * The pg_index row we inserted for this index was marked
1559 * indisvalid=true. But if we attached an existing index that is
1560 * invalid, this is incorrect, so update our row to invalid too.
1561 */
1563 {
1565 HeapTuple tup,
1566 newtup;
1567
1570 if (!HeapTupleIsValid(tup))
1571 elog(ERROR, "cache lookup failed for index %u",
1579
1580 /*
1581 * CCI here to make this update visible, in case this recurses
1582 * across multiple partition levels.
1583 */
1585 }
1586 }
1587
1588 /*
1589 * Indexes on partitioned tables are not themselves built, so we're
1590 * done here.
1591 */
1594 table_close(rel, NoLock);
1597 else
1598 {
1599 /* Update progress for an intermediate partitioned index itself */
1601 }
1602
1603 return address;
1604 }
1605
1608
1609 if (!concurrent)
1610 {
1611 /* Close the heap and we're done, in the non-concurrent case */
1612 table_close(rel, NoLock);
1613
1614 /*
1615 * If this is the top-level index, the command is done overall;
1616 * otherwise, increment progress to report one child index is done.
1617 */
1620 else
1622
1623 return address;
1624 }
1625
1626 /* save lockrelid and locktag for below, then close rel */
1627 heaprelid = rel->rd_lockInfo.lockRelId;
1628 SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1629 table_close(rel, NoLock);
1630
1631 /*
1632 * For a concurrent build, it's important to make the catalog entries
1633 * visible to other transactions before we start to build the index. That
1634 * will prevent them from making incompatible HOT updates. The new index
1635 * will be marked not indisready and not indisvalid, so that no one else
1636 * tries to either insert into it or use it for queries.
1637 *
1638 * We must commit our current transaction so that the index becomes
1639 * visible; then start another. Note that all the data structures we just
1640 * built are lost in the commit. The only data we keep past here are the
1641 * relation IDs.
1642 *
1643 * Before committing, get a session-level lock on the table, to ensure
1644 * that neither it nor the index can be dropped before we finish. This
1645 * cannot block, even if someone else is waiting for access, because we
1646 * already have the same lock within our transaction.
1647 *
1648 * Note: we don't currently bother with a session lock on the index,
1649 * because there are no operations that could change its state while we
1650 * hold lock on the parent table. This might need to change later.
1651 */
1653
1657
1658 /* Tell concurrent index builds to ignore us, if index qualifies */
1659 if (safe_index)
1661
1662 /*
1663 * The index is now visible, so we can report the OID. While on it,
1664 * include the report for the beginning of phase 2.
1665 */
1666 {
1667 const int progress_cols[] = {
1670 };
1671 const int64 progress_vals[] = {
1674 };
1675
1677 }
1678
1679 /*
1680 * Phase 2 of concurrent index build (see comments for validate_index()
1681 * for an overview of how this works)
1682 *
1683 * Now we must wait until no running transaction could have the table open
1684 * with the old list of indexes. Use ShareLock to consider running
1685 * transactions that hold locks that permit writing to the table. Note we
1686 * do not need to worry about xacts that open the table for writing after
1687 * this point; they will see the new index when they open it.
1688 *
1689 * Note: the reason we use actual lock acquisition here, rather than just
1690 * checking the ProcArray and sleeping, is that deadlock is possible if
1691 * one of the transactions in question is blocked trying to acquire an
1692 * exclusive lock on our table. The lock code will detect deadlock and
1693 * error out properly.
1694 */
1696
1697 /*
1698 * At this moment we are sure that there are no transactions with the
1699 * table open for write that don't have this new index in their list of
1700 * indexes. We have waited out all the existing transactions and any new
1701 * transaction will have the new index in its list, but the index is still
1702 * marked as "not-ready-for-inserts". The index is consulted while
1703 * deciding HOT-safety though. This arrangement ensures that no new HOT
1704 * chains can be created where the new tuple and the old tuple in the
1705 * chain have different index keys.
1706 *
1707 * We now take a new snapshot, and build the index using all tuples that
1708 * are visible in this snapshot. We can be sure that any HOT updates to
1709 * these tuples will be compatible with the index, since any updates made
1710 * by transactions that didn't know about the index are now committed or
1711 * rolled back. Thus, each visible tuple is either the end of its
1712 * HOT-chain or the extension of the chain is HOT-safe for this index.
1713 */
1714
1715 /* Set ActiveSnapshot since functions in the indexes may need it */
1717
1718 /* Perform concurrent build of index */
1720
1721 /* we can do away with our snapshot */
1723
1724 /*
1725 * Commit this transaction to make the indisready update visible.
1726 */
1729
1730 /* Tell concurrent index builds to ignore us, if index qualifies */
1731 if (safe_index)
1733
1734 /*
1735 * Phase 3 of concurrent index build
1736 *
1737 * We once again wait until no transaction can have the table open with
1738 * the index marked as read-only for updates.
1739 */
1743
1744 /*
1745 * Now take the "reference snapshot" that will be used by validate_index()
1746 * to filter candidate tuples. Beware! There might still be snapshots in
1747 * use that treat some transaction as in-progress that our reference
1748 * snapshot treats as committed. If such a recently-committed transaction
1749 * deleted tuples in the table, we will not include them in the index; yet
1750 * those transactions which see the deleting one as still-in-progress will
1751 * expect such tuples to be there once we mark the index as valid.
1752 *
1753 * We solve this by waiting for all endangered transactions to exit before
1754 * we mark the index as valid.
1755 *
1756 * We also set ActiveSnapshot to this snap, since functions in indexes may
1757 * need a snapshot.
1758 */
1760 PushActiveSnapshot(snapshot);
1761
1762 /*
1763 * Scan the index and the heap, insert any missing index entries.
1764 */
1766
1767 /*
1768 * Drop the reference snapshot. We must do this before waiting out other
1769 * snapshot holders, else we will deadlock against other processes also
1770 * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
1771 * they must wait for. But first, save the snapshot's xmin to use as
1772 * limitXmin for GetCurrentVirtualXIDs().
1773 */
1774 limitXmin = snapshot->xmin;
1775
1777 UnregisterSnapshot(snapshot);
1778
1779 /*
1780 * The snapshot subsystem could still contain registered snapshots that
1781 * are holding back our process's advertised xmin; in particular, if
1782 * default_transaction_isolation = serializable, there is a transaction
1783 * snapshot that is still active. The CatalogSnapshot is likewise a
1784 * hazard. To ensure no deadlocks, we must commit and start yet another
1785 * transaction, and do our wait before any snapshot has been taken in it.
1786 */
1789
1790 /* Tell concurrent index builds to ignore us, if index qualifies */
1791 if (safe_index)
1793
1794 /* We should now definitely not be advertising any xmin. */
1796
1797 /*
1798 * The index is now valid in the sense that it contains all currently
1799 * interesting tuples. But since it might not contain tuples deleted just
1800 * before the reference snap was taken, we have to wait out any
1801 * transactions that might have older snapshots.
1802 */
1803 INJECTION_POINT("define-index-before-set-valid", NULL);
1807
1808 /*
1809 * Updating pg_index might involve TOAST table access, so ensure we have a
1810 * valid snapshot.
1811 */
1813
1814 /*
1815 * Index can now be marked valid -- update its pg_index entry
1816 */
1818
1820
1821 /*
1822 * The pg_index update will cause backends (including this one) to update
1823 * relcache entries for the index itself, but we should also send a
1824 * relcache inval on the parent table to force replanning of cached plans.
1825 * Otherwise existing sessions might fail to use the new index where it
1826 * would be useful. (Note that our earlier commits did not create reasons
1827 * to replan; so relcache flush on the index itself was sufficient.)
1828 */
1830
1831 /*
1832 * Last thing to do is release the session-level lock on the parent table.
1833 */
1835
1837
1838 return address;
1839}
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition amapi.h:165
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:510
uint32 TransactionId
Definition c.h:736
@ COMPARE_EQ
Definition cmptype.h:36
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define DEBUG1
Definition elog.h:30
Oid MyDatabaseTableSpace
Definition globals.c:96
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:727
void validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
Definition index.c:3351
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition index.c:3504
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:2538
IndexInfo * BuildIndexInfo(Relation index)
Definition index.c:2429
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:1486
#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:102
#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:98
@ INDEX_CREATE_SET_VALID
Definition index.h:33
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition index.h:99
#define INDEX_CREATE_CONCURRENT
Definition index.h:70
static void set_indexsafe_procflags(void)
Definition indexcmds.c:4643
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition indexcmds.c:4473
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition indexcmds.c:436
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:545
static void CheckPredicate(Expr *predicate)
Definition indexcmds.c:1854
static List * ChooseIndexColumnNames(const List *indexElems)
Definition indexcmds.c:2791
static char * ChooseIndexName(const char *tabname, Oid namespaceId, const List *colnames, const List *exclusionOpNames, bool primary, bool isconstraint)
Definition indexcmds.c:2702
#define INJECTION_POINT(name, arg)
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition inval.c:1691
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:2298
bool get_index_isvalid(Oid index_oid)
Definition lsyscache.c:3825
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:1407
char * get_opname(Oid opno)
Definition lsyscache.c:1530
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:1473
Oid get_opfamily_method(Oid opfid)
Definition lsyscache.c:1456
List * make_ands_implicit(Expr *clause)
Definition makefuncs.c:810
#define IsBootstrapProcessingMode()
Definition miscadmin.h:477
#define SECURITY_RESTRICTED_OPERATION
Definition miscadmin.h:319
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition miscinit.c: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:919
@ 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:115
#define PROGRESS_CREATEIDX_PHASE_WAIT_1
Definition progress.h:119
#define PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY
Definition progress.h:137
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition progress.h:109
#define PROGRESS_CREATEIDX_PHASE_WAIT_3
Definition progress.h:125
#define PROGRESS_CREATEIDX_COMMAND_CREATE
Definition progress.h:136
#define PROGRESS_CREATEIDX_PHASE_WAIT_2
Definition progress.h:121
#define PROGRESS_CREATEIDX_PHASE
Definition progress.h:110
#define PROGRESS_CREATEIDX_INDEX_OID
Definition progress.h:108
#define PROGRESS_CREATEIDX_PARTITIONS_TOTAL
Definition progress.h:114
#define PROGRESS_CREATEIDX_COMMAND
Definition progress.h:107
#define RELATION_IS_OTHER_TEMP(relation)
Definition rel.h:667
List * RelationGetIndexList(Relation relation)
Definition relcache.c:4827
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:69
#define HTEqualStrategyNumber
Definition stratnum.h:41
int ii_NumIndexAttrs
Definition execnodes.h:179
int ii_NumIndexKeyAttrs
Definition execnodes.h:181
List * ii_Expressions
Definition execnodes.h:190
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition execnodes.h:187
List * ii_Predicate
Definition execnodes.h:195
LockRelId lockRelId
Definition rel.h:46
Oid relId
Definition rel.h:40
Oid dbId
Definition rel.h:41
TransactionId xmin
Definition proc.h:241
LockInfoData rd_lockInfo
Definition rel.h:114
TransactionId xmin
Definition snapshot.h:153
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition tablecmds.c:4447
#define InvalidTransactionId
Definition transam.h:31
void StartTransactionCommand(void)
Definition xact.c:3081
void CommitTransactionCommand(void)
Definition xact.c:3179

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(), 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:75
bool IsBinaryUpgrade
Definition globals.c:121
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1505
#define makeNode(_type_)
Definition nodes.h:161
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:1875
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';
1745 result = lappend(result,
1746 buildDefItem(workspace,
1747 startvalue,
1748 true));
1749 state = CS_WAITKEY;
1750 }
1751 }
1752 else if (*ptr == '\\')
1753 {
1754 if (ptr + 1 < endptr && ptr[1] == '\\')
1755 {
1756 /* copy only one of the two backslashes */
1757 *wsptr++ = *ptr++;
1758 }
1759 else
1760 *wsptr++ = *ptr;
1761 }
1762 else
1763 {
1764 *wsptr++ = *ptr;
1765 }
1766 break;
1767 case CS_INDQVALUE:
1768 if (*ptr == '"')
1769 {
1770 if (ptr + 1 < endptr && ptr[1] == '"')
1771 {
1772 /* copy only one of the two quotes */
1773 *wsptr++ = *ptr++;
1774 }
1775 else
1776 {
1777 *wsptr++ = '\0';
1778 result = lappend(result,
1779 buildDefItem(workspace,
1780 startvalue,
1781 true));
1782 state = CS_WAITKEY;
1783 }
1784 }
1785 else
1786 {
1787 *wsptr++ = *ptr;
1788 }
1789 break;
1790 case CS_INWVALUE:
1791 if (*ptr == ',' || isspace((unsigned char) *ptr))
1792 {
1793 *wsptr++ = '\0';
1794 result = lappend(result,
1795 buildDefItem(workspace,
1796 startvalue,
1797 false));
1798 state = CS_WAITKEY;
1799 }
1800 else
1801 {
1802 *wsptr++ = *ptr;
1803 }
1804 break;
1805 default:
1806 elog(ERROR, "unrecognized deserialize_deflist state: %d",
1807 state);
1808 }
1809 }
1810
1811 if (state == CS_INWVALUE)
1812 {
1813 *wsptr++ = '\0';
1814 result = lappend(result,
1815 buildDefItem(workspace,
1816 startvalue,
1817 false));
1818 }
1819 else if (state != CS_WAITKEY)
1820 ereport(ERROR,
1822 errmsg("invalid parameter list format: \"%s\"",
1823 text_to_cstring(in))));
1824
1825 pfree(workspace);
1826
1827 return result;
1828}
#define DatumGetTextPP(X)
Definition fmgr.h:293
const void size_t len
Definition c.h:776
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(), 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 2852 of file indexcmds.c.

2853{
2854 ReindexParams params = {0};
2855 ListCell *lc;
2856 bool concurrently = false;
2857 bool verbose = false;
2858 char *tablespacename = NULL;
2859
2860 /* Parse option list */
2861 foreach(lc, stmt->params)
2862 {
2863 DefElem *opt = (DefElem *) lfirst(lc);
2864
2865 if (strcmp(opt->defname, "verbose") == 0)
2866 verbose = defGetBoolean(opt);
2867 else if (strcmp(opt->defname, "concurrently") == 0)
2869 else if (strcmp(opt->defname, "tablespace") == 0)
2870 tablespacename = defGetString(opt);
2871 else
2872 ereport(ERROR,
2874 errmsg("unrecognized %s option \"%s\"",
2875 "REINDEX", opt->defname),
2876 parser_errposition(pstate, opt->location)));
2877 }
2878
2879 if (concurrently)
2881 "REINDEX CONCURRENTLY");
2882
2883 params.options =
2884 (verbose ? REINDEXOPT_VERBOSE : 0) |
2886
2887 /*
2888 * Assign the tablespace OID to move indexes to, with InvalidOid to do
2889 * nothing.
2890 */
2891 if (tablespacename != NULL)
2892 {
2893 params.tablespaceOid = get_tablespace_oid(tablespacename, false);
2894
2895 /* Check permissions except when moving to database's default */
2896 if (OidIsValid(params.tablespaceOid) &&
2898 {
2900
2903 if (aclresult != ACLCHECK_OK)
2906 }
2907 }
2908 else
2909 params.tablespaceOid = InvalidOid;
2910
2911 switch (stmt->kind)
2912 {
2914 ReindexIndex(stmt, &params, isTopLevel);
2915 break;
2917 ReindexTable(stmt, &params, isTopLevel);
2918 break;
2922
2923 /*
2924 * This cannot run inside a user transaction block; if we were
2925 * inside a transaction, then its commit- and
2926 * start-transaction-command calls would not have the intended
2927 * effect!
2928 */
2930 (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
2931 (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
2932 "REINDEX DATABASE");
2933 ReindexMultipleTables(stmt, &params);
2934 break;
2935 default:
2936 elog(ERROR, "unrecognized object type: %d",
2937 (int) stmt->kind);
2938 break;
2939 }
2940}
#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:2947
static void ReindexMultipleTables(const ReindexStmt *stmt, const ReindexParams *params)
Definition indexcmds.c:3136
static Oid ReindexTable(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition indexcmds.c:3077
@ REINDEX_OBJECT_DATABASE
@ REINDEX_OBJECT_INDEX
@ REINDEX_OBJECT_SCHEMA
@ REINDEX_OBJECT_SYSTEM
@ REINDEX_OBJECT_TABLE
static int verbose
ParseLoc location
Definition parsenodes.h:864
Oid tablespaceOid
Definition index.h:42
uint32 options
Definition index.h:41
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition xact.c:3670

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:786
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:439
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:1760
ParamListInfo es_param_list_info
Definition execnodes.h:738
#define ReleaseTupleDesc(tupdesc)
Definition tupdesc.h:240
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition typcache.c:1947

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:1322
#define OidFunctionCall1(functionId, arg1)
Definition fmgr.h:722

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:1333

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

2372{
2373 Oid result = InvalidOid;
2374 int nexact = 0;
2375 int ncompatible = 0;
2376 int ncompatiblepreferred = 0;
2377 Relation rel;
2378 ScanKeyData skey[1];
2379 SysScanDesc scan;
2380 HeapTuple tup;
2382
2383 /* If it's a domain, look at the base type instead */
2384 type_id = getBaseType(type_id);
2385
2386 tcategory = TypeCategory(type_id);
2387
2388 /*
2389 * We scan through all the opclasses available for the access method,
2390 * looking for one that is marked default and matches the target type
2391 * (either exactly or binary-compatibly, but prefer an exact match).
2392 *
2393 * We could find more than one binary-compatible match. If just one is
2394 * for a preferred type, use that one; otherwise we fail, forcing the user
2395 * to specify which one he wants. (The preferred-type special case is a
2396 * kluge for varchar: it's binary-compatible to both text and bpchar, so
2397 * we need a tiebreaker.) If we find more than one exact match, then
2398 * someone put bogus entries in pg_opclass.
2399 */
2401
2402 ScanKeyInit(&skey[0],
2406
2408 NULL, 1, skey);
2409
2410 while (HeapTupleIsValid(tup = systable_getnext(scan)))
2411 {
2413
2414 /* ignore altogether if not a default opclass */
2415 if (!opclass->opcdefault)
2416 continue;
2417 if (opclass->opcintype == type_id)
2418 {
2419 nexact++;
2420 result = opclass->oid;
2421 }
2422 else if (nexact == 0 &&
2423 IsBinaryCoercible(type_id, opclass->opcintype))
2424 {
2425 if (IsPreferredType(tcategory, opclass->opcintype))
2426 {
2428 result = opclass->oid;
2429 }
2430 else if (ncompatiblepreferred == 0)
2431 {
2432 ncompatible++;
2433 result = opclass->oid;
2434 }
2435 }
2436 }
2437
2438 systable_endscan(scan);
2439
2441
2442 /* raise error if pg_opclass contains inconsistent data */
2443 if (nexact > 1)
2444 ereport(ERROR,
2446 errmsg("there are multiple default operator classes for data type %s",
2447 format_type_be(type_id))));
2448
2449 if (nexact == 1 ||
2450 ncompatiblepreferred == 1 ||
2451 (ncompatiblepreferred == 0 && ncompatible == 1))
2452 return result;
2453
2454 return InvalidOid;
2455}
Oid getBaseType(Oid typid)
Definition lsyscache.c:2743
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(), 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 2473 of file indexcmds.c.

2475{
2476 Oid amid;
2477 Oid opfamily;
2478 Oid opcintype;
2479
2480 Assert(cmptype == COMPARE_EQ || cmptype == COMPARE_OVERLAP || cmptype == COMPARE_CONTAINED_BY);
2481
2482 /*
2483 * Use the opclass to get the opfamily, opcintype, and access method. If
2484 * any of this fails, quit early.
2485 */
2486 if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
2487 elog(ERROR, "cache lookup failed for opclass %u", opclass);
2488
2489 amid = get_opclass_method(opclass);
2490
2491 /*
2492 * Ask the index AM to translate to its internal stratnum
2493 */
2494 *strat = IndexAmTranslateCompareType(cmptype, amid, opfamily, true);
2495 if (*strat == InvalidStrategy)
2496 ereport(ERROR,
2498 cmptype == COMPARE_EQ ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2499 cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2500 cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2501 errdetail("Could not translate compare type %d for operator family \"%s\" of access method \"%s\".",
2502 cmptype, get_opfamily_name(opfamily, false), get_am_name(amid)));
2503
2504 /*
2505 * We parameterize rhstype so foreign keys can ask for a <@ operator whose
2506 * rhs matches the aggregate function. For example range_agg returns
2507 * anymultirange.
2508 */
2509 if (!OidIsValid(rhstype))
2510 rhstype = opcintype;
2511 *opid = get_opfamily_member(opfamily, opcintype, rhstype, *strat);
2512
2513 if (!OidIsValid(*opid))
2514 ereport(ERROR,
2516 cmptype == COMPARE_EQ ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2517 cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2518 cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2519 errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
2520 get_opfamily_name(opfamily, false), get_am_name(amid)));
2521}
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:1432
#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:99
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:280
@ PLAN_STMT_INTERNAL
Definition plannodes.h:38
List * pg_parse_query(const char *query_string)
Definition postgres.c:604
struct ErrorContextCallback * previous
Definition elog.h:298
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:1417
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:290
ParseLoc location
Definition parsenodes.h:295
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 2546 of file indexcmds.c.

2547{
2548 char *name;
2549 int overhead = 0; /* chars needed for label and underscores */
2550 int availchars; /* chars available for name(s) */
2551 int name1chars; /* chars allocated to name1 */
2552 int name2chars; /* chars allocated to name2 */
2553 int ndx;
2554
2556 if (name2)
2557 {
2559 overhead++; /* allow for separating underscore */
2560 }
2561 else
2562 name2chars = 0;
2563 if (label)
2564 overhead += strlen(label) + 1;
2565
2567 Assert(availchars > 0); /* else caller chose a bad label */
2568
2569 /*
2570 * If we must truncate, preferentially truncate the longer name. This
2571 * logic could be expressed without a loop, but it's simple and obvious as
2572 * a loop.
2573 */
2574 while (name1chars + name2chars > availchars)
2575 {
2576 if (name1chars > name2chars)
2577 name1chars--;
2578 else
2579 name2chars--;
2580 }
2581
2583 if (name2)
2585
2586 /* Now construct the string using the chosen lengths */
2589 ndx = name1chars;
2590 if (name2)
2591 {
2592 name[ndx++] = '_';
2594 ndx += name2chars;
2595 }
2596 if (label)
2597 {
2598 name[ndx++] = '_';
2599 strcpy(name + ndx, label);
2600 }
2601 else
2602 name[ndx] = '\0';
2603
2604 return name;
2605}
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition mbutils.c:1211

References Assert, fb(), label, 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:2038
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 798 of file statscmds.c.

799{
800 Relation relation;
801 Relation rel;
804 Oid relid;
805
806 /*
807 * Delete the pg_statistic_ext tuple. Also send out a cache inval on the
808 * associated table, so that dependent plans will be rebuilt.
809 */
811
813
814 if (!HeapTupleIsValid(tup)) /* should not happen */
815 elog(ERROR, "cache lookup failed for statistics object %u", statsOid);
816
818 relid = statext->stxrelid;
819
820 /*
821 * Delete the pg_statistic_ext_data tuples holding the actual statistical
822 * data. There might be data with/without inheritance, so attempt deleting
823 * both. We lock the user table first, to prevent other processes (e.g.
824 * DROP STATISTICS) from removing the row concurrently.
825 */
827
830
832
833 CatalogTupleDelete(relation, &tup->t_self);
834
836
837 /* Keep lock until the end of the transaction. */
838 table_close(rel, NoLock);
839
840 table_close(relation, RowExclusiveLock);
841}
END_CATALOG_STRUCT typedef FormData_pg_statistic_ext * Form_pg_statistic_ext
void RemoveStatisticsDataById(Oid statsOid, bool inh)
Definition statscmds.c:773

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

774{
775 Relation relation;
777
779
781 BoolGetDatum(inh));
782
783 /* We don't know if the data row for inh value exists. */
785 {
786 CatalogTupleDelete(relation, &tup->t_self);
787
789 }
790
791 table_close(relation, RowExclusiveLock);
792}

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

2288{
2289 char *schemaname;
2290 char *opcname;
2291 HeapTuple tuple;
2293 Oid opClassId,
2295
2296 if (opclass == NIL)
2297 {
2298 /* no operator class specified, so find the default */
2300 if (!OidIsValid(opClassId))
2301 ereport(ERROR,
2303 errmsg("data type %s has no default operator class for access method \"%s\"",
2305 errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
2306 return opClassId;
2307 }
2308
2309 /*
2310 * Specific opclass name given, so look up the opclass.
2311 */
2312
2313 /* deconstruct the name list */
2314 DeconstructQualifiedName(opclass, &schemaname, &opcname);
2315
2316 if (schemaname)
2317 {
2318 /* Look in specific schema only */
2320
2321 namespaceId = LookupExplicitNamespace(schemaname, false);
2326 }
2327 else
2328 {
2329 /* Unqualified opclass name, so search the search path */
2331 if (!OidIsValid(opClassId))
2332 ereport(ERROR,
2334 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2337 }
2338
2339 if (!HeapTupleIsValid(tuple))
2340 ereport(ERROR,
2342 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2344
2345 /*
2346 * Verify that the index operator class accepts this datatype. Note we
2347 * will accept binary compatibility.
2348 */
2349 opform = (Form_pg_opclass) GETSTRUCT(tuple);
2350 opClassId = opform->oid;
2351 opInputType = opform->opcintype;
2352
2354 ereport(ERROR,
2356 errmsg("operator class \"%s\" does not accept data type %s",
2358
2359 ReleaseSysCache(tuple);
2360
2361 return opClassId;
2362}
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition indexcmds.c:2371
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
1608 result = cstring_to_text_with_len(buf.data, buf.len);
1609 pfree(buf.data);
1610 return result;
1611}
#define ESCAPE_STRING_SYNTAX
Definition c.h:1255
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition c.h:1252
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(), SQL_STR_DOUBLE, and val.

Referenced by AlterTSDictionary(), and DefineTSDictionary().

◆ StatisticsGetRelation()

Oid StatisticsGetRelation ( Oid  statId,
bool  missing_ok 
)
extern

Definition at line 949 of file statscmds.c.

950{
951 HeapTuple tuple;
953 Oid result;
954
956 if (!HeapTupleIsValid(tuple))
957 {
958 if (missing_ok)
959 return InvalidOid;
960 elog(ERROR, "cache lookup failed for statistics object %u", statId);
961 }
963 Assert(stx->oid == statId);
964
965 result = stx->stxrelid;
966 ReleaseSysCache(tuple);
967 return result;
968}

References Assert, elog, ERROR, fb(), Form_pg_statistic_ext, GETSTRUCT(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), ReleaseSysCache(), 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{
128 Datum result;
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 {
194 Datum valarg = result;
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:724
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:850
@ DEFELEM_DROP
Definition parsenodes.h:853
@ DEFELEM_SET
Definition parsenodes.h:851
@ DEFELEM_ADD
Definition parsenodes.h:852
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(), and untransformRelOptions().

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