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, 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 685 of file foreigncmds.c.

686{
687 Relation rel;
688 HeapTuple tp;
693 Oid fdwId;
694 bool isnull;
695 Datum datum;
696 bool handler_given;
697 bool validator_given;
698 Oid fdwhandler;
699 Oid fdwvalidator;
701
703
704 /* Must be superuser */
705 if (!superuser())
708 errmsg("permission denied to alter foreign-data wrapper \"%s\"",
709 stmt->fdwname),
710 errhint("Must be superuser to alter a foreign-data wrapper.")));
711
713 CStringGetDatum(stmt->fdwname));
714
715 if (!HeapTupleIsValid(tp))
718 errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));
719
721 fdwId = fdwForm->oid;
722
723 memset(repl_val, 0, sizeof(repl_val));
724 memset(repl_null, false, sizeof(repl_null));
725 memset(repl_repl, false, sizeof(repl_repl));
726
727 parse_func_options(pstate, stmt->func_options,
728 &handler_given, &fdwhandler,
729 &validator_given, &fdwvalidator);
730
731 if (handler_given)
732 {
735
736 /*
737 * It could be that the behavior of accessing foreign table changes
738 * with the new handler. Warn about this.
739 */
741 (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables")));
742 }
743
744 if (validator_given)
745 {
748
749 /*
750 * It could be that existing options for the FDW or dependent SERVER,
751 * USER MAPPING or FOREIGN TABLE objects are no longer valid according
752 * to the new validator. Warn about this.
753 */
754 if (OidIsValid(fdwvalidator))
756 (errmsg("changing the foreign-data wrapper validator can cause "
757 "the options for dependent objects to become invalid")));
758 }
759 else
760 {
761 /*
762 * Validator is not changed, but we need it for validating options.
763 */
764 fdwvalidator = fdwForm->fdwvalidator;
765 }
766
767 /*
768 * If options specified, validate and update.
769 */
770 if (stmt->options)
771 {
772 /* Extract the current options */
774 tp,
776 &isnull);
777 if (isnull)
778 datum = PointerGetDatum(NULL);
779
780 /* Transform the options */
782 datum,
783 stmt->options,
784 fdwvalidator);
785
786 if (DatumGetPointer(datum) != NULL)
788 else
790
792 }
793
794 /* Everything looks good - update the tuple */
797
798 CatalogTupleUpdate(rel, &tp->t_self, tp);
799
800 heap_freetuple(tp);
801
803
804 /* Update function dependencies if we changed them */
806 {
808
809 /*
810 * Flush all existing dependency records of this FDW on functions; we
811 * assume there can be none other than the ones we are fixing.
812 */
814 fdwId,
817
818 /* And build new ones. */
819
820 if (OidIsValid(fdwhandler))
821 {
823 referenced.objectId = fdwhandler;
824 referenced.objectSubId = 0;
826 }
827
828 if (OidIsValid(fdwvalidator))
829 {
831 referenced.objectId = fdwvalidator;
832 referenced.objectSubId = 0;
834 }
835 }
836
838
840
841 return myself;
842}
#define OidIsValid(objectId)
Definition c.h:788
@ DEPENDENCY_NORMAL
Definition dependency.h:33
int errhint(const char *fmt,...)
Definition elog.c:1330
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define WARNING
Definition elog.h:36
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
static void parse_func_options(ParseState *pstate, List *func_options, bool *handler_given, Oid *fdwhandler, bool *validator_given, Oid *fdwvalidator)
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:1210
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1435
#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
#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:45
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition pg_depend.c:351
FormData_pg_foreign_data_wrapper * Form_pg_foreign_data_wrapper
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342
static Datum CStringGetDatum(const char *X)
Definition postgres.h:380
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:46
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:595
#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(), 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(), 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 985 of file foreigncmds.c.

986{
987 Relation rel;
988 HeapTuple tp;
992 Oid srvId;
994 ObjectAddress address;
995
997
999 CStringGetDatum(stmt->servername));
1000
1001 if (!HeapTupleIsValid(tp))
1002 ereport(ERROR,
1004 errmsg("server \"%s\" does not exist", stmt->servername)));
1005
1007 srvId = srvForm->oid;
1008
1009 /*
1010 * Only owner or a superuser can ALTER a SERVER.
1011 */
1014 stmt->servername);
1015
1016 memset(repl_val, 0, sizeof(repl_val));
1017 memset(repl_null, false, sizeof(repl_null));
1018 memset(repl_repl, false, sizeof(repl_repl));
1019
1020 if (stmt->has_version)
1021 {
1022 /*
1023 * Change the server VERSION string.
1024 */
1025 if (stmt->version)
1027 CStringGetTextDatum(stmt->version);
1028 else
1030
1032 }
1033
1034 if (stmt->options)
1035 {
1037 Datum datum;
1038 bool isnull;
1039
1040 /* Extract the current srvoptions */
1042 tp,
1044 &isnull);
1045 if (isnull)
1046 datum = PointerGetDatum(NULL);
1047
1048 /* Prepare the options array */
1050 datum,
1051 stmt->options,
1052 fdw->fdwvalidator);
1053
1054 if (DatumGetPointer(datum) != NULL)
1056 else
1058
1060 }
1061
1062 /* Everything looks good - update the tuple */
1063 tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1065
1066 CatalogTupleUpdate(rel, &tp->t_self, tp);
1067
1069
1071
1072 heap_freetuple(tp);
1073
1075
1076 return address;
1077}
@ ACLCHECK_NOT_OWNER
Definition acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2654
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4090
#define CStringGetTextDatum(s)
Definition builtins.h:97
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition foreign.c:38
Oid GetUserId(void)
Definition miscinit.c:469
@ OBJECT_FOREIGN_SERVER
FormData_pg_foreign_server * Form_pg_foreign_server

References aclcheck_error(), ACLCHECK_NOT_OWNER, CatalogTupleUpdate(), CStringGetDatum(), CStringGetTextDatum, DatumGetPointer(), ereport, errcode(), errmsg(), ERROR, fb(), 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

Definition at line 426 of file foreigncmds.c.

427{
428 Oid servOid;
430 Relation rel;
431 ObjectAddress address;
433
435
437
438 if (!HeapTupleIsValid(tup))
441 errmsg("server \"%s\" does not exist", name)));
442
444 servOid = form->oid;
445
447
449
451
453
454 return address;
455}
static void AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)

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

Referenced by ExecAlterOwnerStmt().

◆ AlterForeignServerOwner_oid()

void AlterForeignServerOwner_oid ( Oid  srvId,
Oid  newOwnerId 
)
extern

◆ AlterFunction()

ObjectAddress AlterFunction ( ParseState pstate,
AlterFunctionStmt stmt 
)
extern

Definition at line 1363 of file functioncmds.c.

1364{
1365 HeapTuple tup;
1366 Oid funcOid;
1368 bool is_procedure;
1369 Relation rel;
1370 ListCell *l;
1375 List *set_items = NIL;
1380 ObjectAddress address;
1381
1383
1384 funcOid = LookupFuncWithArgs(stmt->objtype, stmt->func, false);
1385
1386 ObjectAddressSet(address, ProcedureRelationId, funcOid);
1387
1389 if (!HeapTupleIsValid(tup)) /* should not happen */
1390 elog(ERROR, "cache lookup failed for function %u", funcOid);
1391
1393
1394 /* Permission check: must own function */
1397 NameListToString(stmt->func->objname));
1398
1399 if (procForm->prokind == PROKIND_AGGREGATE)
1400 ereport(ERROR,
1402 errmsg("\"%s\" is an aggregate function",
1403 NameListToString(stmt->func->objname))));
1404
1405 is_procedure = (procForm->prokind == PROKIND_PROCEDURE);
1406
1407 /* Examine requested actions. */
1408 foreach(l, stmt->actions)
1409 {
1410 DefElem *defel = (DefElem *) lfirst(l);
1411
1412 if (compute_common_attribute(pstate,
1413 is_procedure,
1414 defel,
1416 &strict_item,
1419 &set_items,
1420 &cost_item,
1421 &rows_item,
1422 &support_item,
1423 &parallel_item) == false)
1424 elog(ERROR, "option \"%s\" not recognized", defel->defname);
1425 }
1426
1427 if (volatility_item)
1429 if (strict_item)
1430 procForm->proisstrict = boolVal(strict_item->arg);
1432 procForm->prosecdef = boolVal(security_def_item->arg);
1433 if (leakproof_item)
1434 {
1435 procForm->proleakproof = boolVal(leakproof_item->arg);
1436 if (procForm->proleakproof && !superuser())
1437 ereport(ERROR,
1439 errmsg("only superuser can define a leakproof function")));
1440 }
1441 if (cost_item)
1442 {
1443 procForm->procost = defGetNumeric(cost_item);
1444 if (procForm->procost <= 0)
1445 ereport(ERROR,
1447 errmsg("COST must be positive")));
1448 }
1449 if (rows_item)
1450 {
1451 procForm->prorows = defGetNumeric(rows_item);
1452 if (procForm->prorows <= 0)
1453 ereport(ERROR,
1455 errmsg("ROWS must be positive")));
1456 if (!procForm->proretset)
1457 ereport(ERROR,
1459 errmsg("ROWS is not applicable when function does not return a set")));
1460 }
1461 if (support_item)
1462 {
1463 /* interpret_func_support handles the privilege check */
1465
1466 /* Add or replace dependency on support function */
1467 if (OidIsValid(procForm->prosupport))
1468 {
1470 ProcedureRelationId, procForm->prosupport,
1471 newsupport) != 1)
1472 elog(ERROR, "could not change support dependency for function %s",
1473 get_func_name(funcOid));
1474 }
1475 else
1476 {
1478
1480 referenced.objectId = newsupport;
1481 referenced.objectSubId = 0;
1483 }
1484
1485 procForm->prosupport = newsupport;
1486 }
1487 if (parallel_item)
1489 if (set_items)
1490 {
1491 Datum datum;
1492 bool isnull;
1493 ArrayType *a;
1497
1498 /* extract existing proconfig setting */
1500 a = isnull ? NULL : DatumGetArrayTypeP(datum);
1501
1502 /* update according to each SET or RESET item, left to right */
1504
1505 /* update the tuple */
1506 memset(repl_repl, false, sizeof(repl_repl));
1508
1509 if (a == NULL)
1510 {
1513 }
1514 else
1515 {
1517 repl_null[Anum_pg_proc_proconfig - 1] = false;
1518 }
1519
1522 }
1523 /* DO NOT put more touches of procForm below here; it's now dangling. */
1524
1525 /* Do the update */
1526 CatalogTupleUpdate(rel, &tup->t_self, tup);
1527
1529
1530 table_close(rel, NoLock);
1532
1533 return address;
1534}
#define DatumGetArrayTypeP(X)
Definition array.h:261
double defGetNumeric(DefElem *def)
Definition define.c:67
#define elog(elevel,...)
Definition elog.h:226
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:1758
char * NameListToString(const List *names)
Definition namespace.c:3664
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:457
#define lfirst(lc)
Definition pg_list.h:172
#define NIL
Definition pg_list.h:68
FormData_pg_proc * Form_pg_proc
Definition pg_proc.h:136
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(), 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 462 of file operatorcmds.c.

463{
464 ObjectAddress address;
465 Oid oprId;
469 int i;
470 ListCell *pl;
472 bool nulls[Natts_pg_operator];
474 List *restrictionName = NIL; /* optional restrict. sel. function */
475 bool updateRestriction = false;
477 List *joinName = NIL; /* optional join sel. function */
478 bool updateJoin = false;
479 Oid joinOid;
480 List *commutatorName = NIL; /* optional commutator operator name */
482 List *negatorName = NIL; /* optional negator operator name */
484 bool canMerge = false;
485 bool updateMerges = false;
486 bool canHash = false;
487 bool updateHashes = false;
488
489 /* Look up the operator */
490 oprId = LookupOperWithArgs(stmt->opername, false);
493 if (!HeapTupleIsValid(tup))
494 elog(ERROR, "cache lookup failed for operator %u", oprId);
496
497 /* Process options */
498 foreach(pl, stmt->options)
499 {
500 DefElem *defel = (DefElem *) lfirst(pl);
501 List *param;
502
503 if (defel->arg == NULL)
504 param = NIL; /* NONE, removes the function */
505 else
506 param = defGetQualifiedName(defel);
507
508 if (strcmp(defel->defname, "restrict") == 0)
509 {
510 restrictionName = param;
511 updateRestriction = true;
512 }
513 else if (strcmp(defel->defname, "join") == 0)
514 {
515 joinName = param;
516 updateJoin = true;
517 }
518 else if (strcmp(defel->defname, "commutator") == 0)
519 {
521 }
522 else if (strcmp(defel->defname, "negator") == 0)
523 {
525 }
526 else if (strcmp(defel->defname, "merges") == 0)
527 {
529 updateMerges = true;
530 }
531 else if (strcmp(defel->defname, "hashes") == 0)
532 {
534 updateHashes = true;
535 }
536
537 /*
538 * The rest of the options that CREATE accepts cannot be changed.
539 * Check for them so that we can give a meaningful error message.
540 */
541 else if (strcmp(defel->defname, "leftarg") == 0 ||
542 strcmp(defel->defname, "rightarg") == 0 ||
543 strcmp(defel->defname, "function") == 0 ||
544 strcmp(defel->defname, "procedure") == 0)
545 {
548 errmsg("operator attribute \"%s\" cannot be changed",
549 defel->defname)));
550 }
551 else
554 errmsg("operator attribute \"%s\" not recognized",
555 defel->defname)));
556 }
557
558 /* Check permissions. Must be owner. */
561 NameStr(oprForm->oprname));
562
563 /*
564 * Look up OIDs for any parameters specified
565 */
566 if (restrictionName)
568 else
570 if (joinName)
572 else
574
575 if (commutatorName)
576 {
577 /* commutator has reversed arg types */
579 oprForm->oprright,
580 oprForm->oprleft);
581
582 /*
583 * We don't need to do anything extra for a self commutator as in
584 * OperatorCreate, since the operator surely exists already.
585 */
586 }
587 else
589
590 if (negatorName)
591 {
593 oprForm->oprleft,
594 oprForm->oprright);
595
596 /* Must reject self-negation */
597 if (negatorOid == oprForm->oid)
600 errmsg("operator cannot be its own negator")));
601 }
602 else
603 {
605 }
606
607 /*
608 * Check that we're not changing any attributes that might be depended on
609 * by plans, while allowing no-op updates.
610 */
611 if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
612 commutatorOid != oprForm->oprcom)
615 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
616 "commutator")));
617
618 if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
619 negatorOid != oprForm->oprnegate)
622 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
623 "negator")));
624
625 if (updateMerges && oprForm->oprcanmerge && !canMerge)
628 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
629 "merges")));
630
631 if (updateHashes && oprForm->oprcanhash && !canHash)
634 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
635 "hashes")));
636
637 /* Perform additional checks, like OperatorCreate does */
639 oprForm->oprright,
640 oprForm->oprresult,
645 canMerge,
646 canHash);
647
648 /* Update the tuple */
649 for (i = 0; i < Natts_pg_operator; ++i)
650 {
651 values[i] = (Datum) 0;
652 replaces[i] = false;
653 nulls[i] = false;
654 }
656 {
659 }
660 if (updateJoin)
661 {
664 }
666 {
669 }
671 {
674 }
675 if (updateMerges)
676 {
679 }
680 if (updateHashes)
681 {
684 }
685
687 values, nulls, replaces);
688
689 CatalogTupleUpdate(catalog, &tup->t_self, tup);
690
691 address = makeOperatorDependencies(tup, false, true);
692
695
697
699
700 return address;
701}
static Datum values[MAXATTR]
Definition bootstrap.c:155
#define NameStr(name)
Definition c.h:765
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:134
@ 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)
FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:83
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(), 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)
FormData_pg_am * Form_pg_am
Definition pg_am.h:48
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220

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

Referenced by ProcessUtilitySlow().

◆ AlterStatistics()

ObjectAddress AlterStatistics ( AlterStatsStmt stmt)
extern

Definition at line 639 of file statscmds.c.

640{
641 Relation rel;
642 Oid stxoid;
648 ObjectAddress address;
649 int newtarget = 0;
651
652 /* -1 was used in previous versions for the default setting */
653 if (stmt->stxstattarget && intVal(stmt->stxstattarget) != -1)
654 {
655 newtarget = intVal(stmt->stxstattarget);
656 newtarget_default = false;
657 }
658 else
659 newtarget_default = true;
660
662 {
663 /* Limit statistics target to a sane range */
664 if (newtarget < 0)
665 {
668 errmsg("statistics target %d is too low",
669 newtarget)));
670 }
672 {
676 errmsg("lowering statistics target to %d",
677 newtarget)));
678 }
679 }
680
681 /* lookup OID of the statistics object */
682 stxoid = get_statistics_object_oid(stmt->defnames, stmt->missing_ok);
683
684 /*
685 * If we got here and the OID is not valid, it means the statistics object
686 * does not exist, but the command specified IF EXISTS. So report this as
687 * a simple NOTICE and we're done.
688 */
689 if (!OidIsValid(stxoid))
690 {
691 char *schemaname;
692 char *statname;
693
694 Assert(stmt->missing_ok);
695
696 DeconstructQualifiedName(stmt->defnames, &schemaname, &statname);
697
698 if (schemaname)
700 (errmsg("statistics object \"%s.%s\" does not exist, skipping",
701 schemaname, statname)));
702 else
704 (errmsg("statistics object \"%s\" does not exist, skipping",
705 statname)));
706
708 }
709
710 /* Search pg_statistic_ext */
712
715 elog(ERROR, "cache lookup failed for extended statistics object %u", stxoid);
716
717 /* Must be owner of the existing statistics object */
720 NameListToString(stmt->defnames));
721
722 /* Build new tuple. */
723 memset(repl_val, 0, sizeof(repl_val));
724 memset(repl_null, false, sizeof(repl_null));
725 memset(repl_repl, false, sizeof(repl_repl));
726
727 /* replace the stxstattarget column */
731 else
733
736
737 /* Update system catalog. */
738 CatalogTupleUpdate(rel, &newtup->t_self, newtup);
739
741
743
744 /*
745 * NOTE: because we only support altering the statistics target, not the
746 * other fields, there is no need to update dependencies.
747 */
748
751
753
754 return address;
755}
#define Assert(condition)
Definition c.h:873
#define NOTICE
Definition elog.h:35
Oid get_statistics_object_oid(List *names, bool missing_ok)
Definition namespace.c:2642
void DeconstructQualifiedName(const List *names, char **nspname_p, char **objname_p)
Definition namespace.c:3371
const ObjectAddress InvalidObjectAddress
@ OBJECT_STATISTIC_EXT
static Datum Int16GetDatum(int16 X)
Definition postgres.h:182
#define MAX_STATISTICS_TARGET
Definition vacuum.h:329
#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
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(), 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:2931
@ OBJECT_TSDICTIONARY
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:391
FormData_pg_ts_dict * Form_pg_ts_dict
Definition pg_ts_dict.h:52
List * deserialize_deflist(Datum txt)
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, 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 1237 of file foreigncmds.c.

1238{
1239 Relation rel;
1240 HeapTuple tp;
1244 Oid useId;
1245 Oid umId;
1247 ObjectAddress address;
1248 RoleSpec *role = (RoleSpec *) stmt->user;
1249
1251
1252 if (role->roletype == ROLESPEC_PUBLIC)
1254 else
1255 useId = get_rolespec_oid(stmt->user, false);
1256
1257 srv = GetForeignServerByName(stmt->servername, false);
1258
1261 ObjectIdGetDatum(srv->serverid));
1262 if (!OidIsValid(umId))
1263 ereport(ERROR,
1265 errmsg("user mapping for \"%s\" does not exist for server \"%s\"",
1266 MappingUserName(useId), stmt->servername)));
1267
1268 user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1269
1271
1272 if (!HeapTupleIsValid(tp))
1273 elog(ERROR, "cache lookup failed for user mapping %u", umId);
1274
1275 memset(repl_val, 0, sizeof(repl_val));
1276 memset(repl_null, false, sizeof(repl_null));
1277 memset(repl_repl, false, sizeof(repl_repl));
1278
1279 if (stmt->options)
1280 {
1282 Datum datum;
1283 bool isnull;
1284
1285 /*
1286 * Process the options.
1287 */
1288
1289 fdw = GetForeignDataWrapper(srv->fdwid);
1290
1292 tp,
1294 &isnull);
1295 if (isnull)
1296 datum = PointerGetDatum(NULL);
1297
1298 /* Prepare the options array */
1300 datum,
1301 stmt->options,
1302 fdw->fdwvalidator);
1303
1304 if (DatumGetPointer(datum) != NULL)
1306 else
1308
1310 }
1311
1312 /* Everything looks good - update the tuple */
1313 tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1315
1316 CatalogTupleUpdate(rel, &tp->t_self, tp);
1317
1319 umId, 0);
1320
1322
1323 heap_freetuple(tp);
1324
1326
1327 return address;
1328}
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition acl.c:5586
#define ACL_ID_PUBLIC
Definition acl.h:46
ForeignServer * GetForeignServerByName(const char *srvname, bool missing_ok)
Definition foreign.c:183
#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:423
#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 2385 of file functioncmds.c.

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

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(), 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 178 of file indexcmds.c.

183{
184 bool isconstraint;
185 Oid *typeIds;
191 HeapTuple tuple;
195 bool amcanorder;
196 bool amsummarizing;
198 IndexInfo *indexInfo;
200 int old_natts;
201 bool ret = true;
204 Relation irel;
205 int i;
206 Datum d;
207
208 /* Caller should already have the relation locked in some way. */
210
211 /*
212 * We can pretend isconstraint = false unconditionally. It only serves to
213 * decide the text of an error message that should never happen for us.
214 */
215 isconstraint = false;
216
220
221 /* look up the access method */
223 if (!HeapTupleIsValid(tuple))
226 errmsg("access method \"%s\" does not exist",
231 ReleaseSysCache(tuple);
232
233 amcanorder = amRoutine->amcanorder;
234 amsummarizing = amRoutine->amsummarizing;
235
236 /*
237 * Compute the operator classes, collations, and exclusion operators for
238 * the new index, so we can test whether it's compatible with the existing
239 * one. Note that ComputeIndexAttrs might fail here, but that's OK:
240 * DefineIndex would have failed later. Our attributeList contains only
241 * key attributes, thus we're filling ii_NumIndexAttrs and
242 * ii_NumIndexKeyAttrs with same value.
243 */
245 accessMethodId, NIL, NIL, false, false,
246 false, false, amsummarizing, isWithoutOverlaps);
252 ComputeIndexAttrs(NULL, indexInfo,
257 amcanorder, isconstraint, isWithoutOverlaps, InvalidOid,
258 0, NULL);
259
260 /* Get the soon-obsolete pg_index tuple. */
262 if (!HeapTupleIsValid(tuple))
263 elog(ERROR, "cache lookup failed for index %u", oldId);
265
266 /*
267 * We don't assess expressions or predicates; assume incompatibility.
268 * Also, if the index is invalid for any reason, treat it as incompatible.
269 */
272 indexForm->indisvalid))
273 {
274 ReleaseSysCache(tuple);
275 return false;
276 }
277
278 /* Any change in operator class or collation breaks compatibility. */
279 old_natts = indexForm->indnkeyatts;
281
284
287
288 ret = (memcmp(old_indclass->values, opclassIds, old_natts * sizeof(Oid)) == 0 &&
289 memcmp(old_indcollation->values, collationIds, old_natts * sizeof(Oid)) == 0);
290
291 ReleaseSysCache(tuple);
292
293 if (!ret)
294 return false;
295
296 /* For polymorphic opcintype, column type changes break compatibility. */
297 irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
298 for (i = 0; i < old_natts; i++)
299 {
301 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
302 {
303 ret = false;
304 break;
305 }
306 }
307
308 /* Any change in opclass options break compatibility. */
309 if (ret)
310 {
312
313 for (i = 0; i < old_natts; i++)
315
317
319 }
320
321 /* Any change in exclusion operator selections breaks compatibility. */
322 if (ret && indexInfo->ii_ExclusionOps != NULL)
323 {
325 *old_procs;
327
329 ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
330 old_natts * sizeof(Oid)) == 0;
331
332 /* Require an exact input type match for polymorphic operators. */
333 if (ret)
334 {
335 for (i = 0; i < old_natts && ret; i++)
336 {
337 Oid left,
338 right;
339
340 op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
341 if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
342 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
343 {
344 ret = false;
345 break;
346 }
347 }
348 }
349 }
350
351 index_close(irel, NoLock);
352 return ret;
353}
const IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition amapi.c:33
int16_t int16
Definition c.h:541
uint16_t uint16
Definition c.h:545
#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:3581
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:133
static bool CompareOpclassOptions(const Datum *opts1, const Datum *opts2, int natts)
Definition indexcmds.c:362
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:1878
#define AccessShareLock
Definition lockdefs.h:36
Oid get_opclass_input_type(Oid opclass)
Definition lsyscache.c:1314
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1046
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition lsyscache.c:1508
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
FormData_pg_index * Form_pg_index
Definition pg_index.h:70
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition relcache.c:5648
Oid * ii_ExclusionOps
Definition execnodes.h:190
TupleDesc rd_att
Definition rel.h:112
Definition c.h:745
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625

References AccessShareLock, Assert, CompareOpclassOptions(), ComputeIndexAttrs(), DatumGetPointer(), elog, ereport, errcode(), errmsg(), ERROR, fb(), 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 2631 of file indexcmds.c.

2634{
2635 int pass = 0;
2636 char *relname = NULL;
2637 char modlabel[NAMEDATALEN];
2640
2641 /* prepare to search pg_class with a dirty snapshot */
2644
2645 /* try the unmodified label first */
2646 strlcpy(modlabel, label, sizeof(modlabel));
2647
2648 for (;;)
2649 {
2650 ScanKeyData key[2];
2651 SysScanDesc scan;
2652 bool collides;
2653
2655
2656 /* is there any conflicting relation name? */
2657 ScanKeyInit(&key[0],
2661 ScanKeyInit(&key[1],
2665
2667 true /* indexOK */ ,
2669 2, key);
2670
2672
2673 systable_endscan(scan);
2674
2675 /* break out of loop if no conflict */
2676 if (!collides)
2677 {
2678 if (!isconstraint ||
2680 break;
2681 }
2682
2683 /* found a conflict, so try a new name component */
2684 pfree(relname);
2685 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2686 }
2687
2689
2690 return relname;
2691}
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition indexcmds.c:2543
static char * label
NameData relname
Definition pg_class.h:38
#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:1117
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
Datum namein(PG_FUNCTION_ARGS)
Definition name.c:48
#define InvokeObjectPostCreateHook(classId, objectId, subId)
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition pg_depend.c:193
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 1541 of file functioncmds.c.

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

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, CastCreate(), COERCION_ASSIGNMENT, COERCION_EXPLICIT, COERCION_IMPLICIT, DEPENDENCY_NORMAL, elog, ereport, errcode(), errmsg(), ERROR, fb(), 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 569 of file foreigncmds.c.

570{
571 Relation rel;
574 HeapTuple tuple;
575 Oid fdwId;
576 bool handler_given;
577 bool validator_given;
578 Oid fdwhandler;
579 Oid fdwvalidator;
580 Datum fdwoptions;
581 Oid ownerId;
584
586
587 /* Must be superuser */
588 if (!superuser())
591 errmsg("permission denied to create foreign-data wrapper \"%s\"",
592 stmt->fdwname),
593 errhint("Must be superuser to create a foreign-data wrapper.")));
594
595 /* For now the owner cannot be specified on create. Use effective user ID. */
596 ownerId = GetUserId();
597
598 /*
599 * Check that there is no other foreign-data wrapper by this name.
600 */
601 if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
604 errmsg("foreign-data wrapper \"%s\" already exists",
605 stmt->fdwname)));
606
607 /*
608 * Insert tuple into pg_foreign_data_wrapper.
609 */
610 memset(values, 0, sizeof(values));
611 memset(nulls, false, sizeof(nulls));
612
619
620 /* Lookup handler and validator functions, if given */
621 parse_func_options(pstate, stmt->func_options,
622 &handler_given, &fdwhandler,
623 &validator_given, &fdwvalidator);
624
627
628 nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
629
632 stmt->options,
633 fdwvalidator);
634
635 if (DatumGetPointer(fdwoptions) != NULL)
637 else
639
640 tuple = heap_form_tuple(rel->rd_att, values, nulls);
641
642 CatalogTupleInsert(rel, tuple);
643
644 heap_freetuple(tuple);
645
646 /* record dependencies */
648 myself.objectId = fdwId;
649 myself.objectSubId = 0;
650
651 if (OidIsValid(fdwhandler))
652 {
654 referenced.objectId = fdwhandler;
655 referenced.objectSubId = 0;
657 }
658
659 if (OidIsValid(fdwvalidator))
660 {
662 referenced.objectId = fdwvalidator;
663 referenced.objectSubId = 0;
665 }
666
668
669 /* dependency on extension */
671
672 /* Post creation hook for new foreign data wrapper */
674
676
677 return myself;
678}
ForeignDataWrapper * GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
Definition foreign.c:97
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 849 of file foreigncmds.c.

850{
851 Relation rel;
852 Datum srvoptions;
854 bool nulls[Natts_pg_foreign_server];
855 HeapTuple tuple;
856 Oid srvId;
857 Oid ownerId;
862
864
865 /* For now the owner cannot be specified on create. Use effective user ID. */
866 ownerId = GetUserId();
867
868 /*
869 * Check that there is no other foreign server by this name. If there is
870 * one, do nothing if IF NOT EXISTS was specified.
871 */
872 srvId = get_foreign_server_oid(stmt->servername, true);
873 if (OidIsValid(srvId))
874 {
875 if (stmt->if_not_exists)
876 {
877 /*
878 * If we are in an extension script, insist that the pre-existing
879 * object be a member of the extension, to avoid security risks.
880 */
883
884 /* OK to skip */
887 errmsg("server \"%s\" already exists, skipping",
888 stmt->servername)));
891 }
892 else
895 errmsg("server \"%s\" already exists",
896 stmt->servername)));
897 }
898
899 /*
900 * Check that the FDW exists and that we have USAGE on it. Also get the
901 * actual FDW for option validation etc.
902 */
903 fdw = GetForeignDataWrapperByName(stmt->fdwname, false);
904
906 if (aclresult != ACLCHECK_OK)
908
909 /*
910 * Insert tuple into pg_foreign_server.
911 */
912 memset(values, 0, sizeof(values));
913 memset(nulls, false, sizeof(nulls));
914
922
923 /* Add server type if supplied */
924 if (stmt->servertype)
926 CStringGetTextDatum(stmt->servertype);
927 else
928 nulls[Anum_pg_foreign_server_srvtype - 1] = true;
929
930 /* Add server version if supplied */
931 if (stmt->version)
933 CStringGetTextDatum(stmt->version);
934 else
935 nulls[Anum_pg_foreign_server_srvversion - 1] = true;
936
937 /* Start with a blank acl */
938 nulls[Anum_pg_foreign_server_srvacl - 1] = true;
939
940 /* Add server options */
943 stmt->options,
944 fdw->fdwvalidator);
945
946 if (DatumGetPointer(srvoptions) != NULL)
948 else
949 nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
950
951 tuple = heap_form_tuple(rel->rd_att, values, nulls);
952
953 CatalogTupleInsert(rel, tuple);
954
955 heap_freetuple(tuple);
956
957 /* record dependencies */
959 myself.objectId = srvId;
960 myself.objectSubId = 0;
961
963 referenced.objectId = fdw->fdwid;
964 referenced.objectSubId = 0;
966
968
969 /* dependency on extension */
971
972 /* Post creation hook for new foreign server */
974
976
977 return myself;
978}
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
Definition foreign.c:705
@ OBJECT_FDW
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition pg_depend.c:258

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 1415 of file foreigncmds.c.

1416{
1420 bool nulls[Natts_pg_foreign_table];
1421 HeapTuple tuple;
1425 Oid ownerId;
1427 ForeignServer *server;
1428
1429 /*
1430 * Advance command counter to ensure the pg_attribute tuple is visible;
1431 * the tuple might be updated to add constraints in previous step.
1432 */
1434
1436
1437 /*
1438 * For now the owner cannot be specified on create. Use effective user ID.
1439 */
1440 ownerId = GetUserId();
1441
1442 /*
1443 * Check that the foreign server exists and that we have USAGE on it. Also
1444 * get the actual FDW for option validation etc.
1445 */
1446 server = GetForeignServerByName(stmt->servername, false);
1448 if (aclresult != ACLCHECK_OK)
1450
1451 fdw = GetForeignDataWrapper(server->fdwid);
1452
1453 /*
1454 * Insert tuple into pg_foreign_table.
1455 */
1456 memset(values, 0, sizeof(values));
1457 memset(nulls, false, sizeof(nulls));
1458
1461 /* Add table generic options */
1464 stmt->options,
1465 fdw->fdwvalidator);
1466
1469 else
1470 nulls[Anum_pg_foreign_table_ftoptions - 1] = true;
1471
1472 tuple = heap_form_tuple(ftrel->rd_att, values, nulls);
1473
1474 CatalogTupleInsert(ftrel, tuple);
1475
1476 heap_freetuple(tuple);
1477
1478 /* Add pg_class dependency on the server */
1479 myself.classId = RelationRelationId;
1480 myself.objectId = relid;
1481 myself.objectSubId = 0;
1482
1484 referenced.objectId = server->serverid;
1485 referenced.objectSubId = 0;
1487
1489}
char * servername
Definition foreign.h:39
void CommandCounterIncrement(void)
Definition xact.c:1101

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

1029{
1030 char *probin_str;
1031 char *prosrc_str;
1033 Oid prorettype;
1034 bool returnsSet;
1035 char *language;
1039 char *funcname;
1042 oidvector *parameterTypes;
1052 ArrayType *trftypes;
1054 bool isWindowFunc,
1055 isStrict,
1056 security,
1058 char volatility;
1065 List *as_clause;
1066 char parallel;
1067
1068 /* Convert list of names to a name and namespace */
1070 &funcname);
1071
1072 /* Check we have creation rights in target namespace */
1074 if (aclresult != ACLCHECK_OK)
1077
1078 /* Set default attributes */
1079 as_clause = NIL;
1080 language = NULL;
1081 isWindowFunc = false;
1082 isStrict = false;
1083 security = false;
1084 isLeakProof = false;
1086 proconfig = NULL;
1087 procost = -1; /* indicates not set */
1088 prorows = -1; /* indicates not set */
1091
1092 /* Extract non-default attributes from stmt->options list */
1094 stmt->is_procedure,
1095 stmt->options,
1100 &prosupport, &parallel);
1101
1102 if (!language)
1103 {
1104 if (stmt->sql_body)
1105 language = "sql";
1106 else
1107 ereport(ERROR,
1109 errmsg("no language specified")));
1110 }
1111
1112 /* Look up the language and validate permissions */
1115 ereport(ERROR,
1117 errmsg("language \"%s\" does not exist", language),
1119 errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
1120
1123
1124 if (languageStruct->lanpltrusted)
1125 {
1126 /* if trusted language, need USAGE privilege */
1128 if (aclresult != ACLCHECK_OK)
1130 NameStr(languageStruct->lanname));
1131 }
1132 else
1133 {
1134 /* if untrusted language, must be superuser */
1135 if (!superuser())
1137 NameStr(languageStruct->lanname));
1138 }
1139
1140 languageValidator = languageStruct->lanvalidator;
1141
1143
1144 /*
1145 * Only superuser is allowed to create leakproof functions because
1146 * leakproof functions can see tuples which have not yet been filtered out
1147 * by security barrier views or row-level security policies.
1148 */
1149 if (isLeakProof && !superuser())
1150 ereport(ERROR,
1152 errmsg("only superuser can define a leakproof function")));
1153
1154 if (transformDefElem)
1155 {
1156 ListCell *lc;
1157
1158 foreach(lc, castNode(List, transformDefElem))
1159 {
1160 Oid typeid = typenameTypeId(NULL,
1162 Oid elt = get_base_element_type(typeid);
1164
1165 typeid = elt ? elt : typeid;
1166 transformid = get_transform_oid(typeid, languageOid, false);
1169 }
1170 }
1171
1172 /*
1173 * Convert remaining parameters of CREATE to form wanted by
1174 * ProcedureCreate.
1175 */
1177 stmt->parameters,
1179 stmt->is_procedure ? OBJECT_PROCEDURE : OBJECT_FUNCTION,
1180 &parameterTypes,
1189
1190 if (stmt->is_procedure)
1191 {
1192 Assert(!stmt->returnType);
1194 returnsSet = false;
1195 }
1196 else if (stmt->returnType)
1197 {
1198 /* explicit RETURNS clause */
1200 &prorettype, &returnsSet);
1201 if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
1202 ereport(ERROR,
1204 errmsg("function result type must be %s because of OUT parameters",
1206 }
1208 {
1209 /* default RETURNS clause from OUT parameters */
1210 prorettype = requiredResultType;
1211 returnsSet = false;
1212 }
1213 else
1214 {
1215 ereport(ERROR,
1217 errmsg("function result type must be specified")));
1218 /* Alternative possibility: default to RETURNS VOID */
1219 prorettype = VOIDOID;
1220 returnsSet = false;
1221 }
1222
1223 if (trftypes_list != NIL)
1224 {
1225 ListCell *lc;
1226 Datum *arr;
1227 int i;
1228
1229 arr = palloc(list_length(trftypes_list) * sizeof(Datum));
1230 i = 0;
1231 foreach(lc, trftypes_list)
1232 arr[i++] = ObjectIdGetDatum(lfirst_oid(lc));
1234 }
1235 else
1236 {
1237 /* store SQL NULL instead of empty array */
1238 trftypes = NULL;
1239 }
1240
1244 pstate->p_sourcetext);
1245
1246 /*
1247 * Set default values for COST and ROWS depending on other parameters;
1248 * reject ROWS if it's not returnsSet. NB: pg_dump knows these default
1249 * values, keep it in sync if you change them.
1250 */
1251 if (procost < 0)
1252 {
1253 /* SQL and PL-language functions are assumed more expensive */
1256 procost = 1;
1257 else
1258 procost = 100;
1259 }
1260 if (prorows < 0)
1261 {
1262 if (returnsSet)
1263 prorows = 1000;
1264 else
1265 prorows = 0; /* dummy value if not returnsSet */
1266 }
1267 else if (!returnsSet)
1268 ereport(ERROR,
1270 errmsg("ROWS is not applicable when function does not return a set")));
1271
1272 /*
1273 * And now that we have all the parameters, and know we're permitted to do
1274 * so, go ahead and create the function.
1275 */
1278 stmt->replace,
1279 returnsSet,
1280 prorettype,
1281 GetUserId(),
1284 prosrc_str, /* converted to text later */
1285 probin_str, /* converted to text later */
1286 prosqlbody,
1288 security,
1290 isStrict,
1291 volatility,
1292 parallel,
1293 parameterTypes,
1298 PointerGetDatum(trftypes),
1301 prosupport,
1302 procost,
1303 prorows);
1304}
@ ACLCHECK_NO_PRIV
Definition acl.h:184
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
float float4
Definition c.h:643
bool extension_file_exists(const char *extensionName)
Definition extension.c:2551
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:2982
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3516
void * palloc(Size size)
Definition mcxt.c:1387
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition namespace.c:3557
#define castNode(_type_, nodeptr)
Definition nodes.h:182
@ OBJECT_SCHEMA
@ OBJECT_PROCEDURE
@ OBJECT_LANGUAGE
#define ACL_CREATE
Definition parsenodes.h:85
FormData_pg_language * Form_pg_language
Definition pg_language.h:65
#define lfirst_node(type, lc)
Definition pg_list.h:176
#define lfirst_oid(lc)
Definition pg_list.h:174
ObjectAddress ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, Node *prosqlbody, char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility, char parallel, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum trftypes, List *trfoids, Datum proconfig, Oid prosupport, float4 procost, float4 prorows)
Definition pg_proc.c:99
const char * p_sourcetext
Definition parse_node.h:195

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(), 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 63 of file statscmds.c.

64{
66 int nattnums = 0;
67 int numcols;
68 char *namestr;
73 HeapTuple htup;
75 bool nulls[Natts_pg_statistic_ext];
77 List *stxexprs = NIL;
80 Relation rel = NULL;
81 Oid relid;
83 myself;
84 Datum types[4]; /* one for each possible type of statistic */
85 int ntypes;
87 bool build_ndistinct;
89 bool build_mcv;
91 bool requested_type = false;
92 int i;
93 ListCell *cell;
95
97
98 /*
99 * Examine the FROM clause. Currently, we only allow it to be a single
100 * simple table, but later we'll probably allow multiple tables and JOIN
101 * syntax. The grammar is already prepared for that, so we have to check
102 * here that what we got is what we can support.
103 */
104 if (list_length(stmt->relations) != 1)
107 errmsg("only a single relation is allowed in CREATE STATISTICS")));
108
109 foreach(cell, stmt->relations)
110 {
111 Node *rln = (Node *) lfirst(cell);
112
113 if (!IsA(rln, RangeVar))
116 errmsg("only a single relation is allowed in CREATE STATISTICS")));
117
118 /*
119 * CREATE STATISTICS will influence future execution plans but does
120 * not interfere with currently executing plans. So it should be
121 * enough to take only ShareUpdateExclusiveLock on relation,
122 * conflicting with ANALYZE and other DDL that sets statistical
123 * information, but not with normal queries.
124 */
126
127 /* Restrict to allowed relation types */
128 if (rel->rd_rel->relkind != RELKIND_RELATION &&
129 rel->rd_rel->relkind != RELKIND_MATVIEW &&
130 rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
131 rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
134 errmsg("cannot define statistics for relation \"%s\"",
137
138 /*
139 * You must own the relation to create stats on it.
140 *
141 * NB: Concurrent changes could cause this function's lookup to find a
142 * different relation than a previous lookup by the caller, so we must
143 * perform this check even when check_rights == false.
144 */
148
149 /* Creating statistics on system catalogs is not allowed */
153 errmsg("permission denied: \"%s\" is a system catalog",
155 }
156
157 Assert(rel);
158 relid = RelationGetRelid(rel);
159
160 /*
161 * If the node has a name, split it up and determine creation namespace.
162 * If not, put the object in the same namespace as the relation, and cons
163 * up a name for it. (This can happen either via "CREATE STATISTICS ..."
164 * or via "CREATE TABLE ... (LIKE)".)
165 */
166 if (stmt->defnames)
168 &namestr);
169 else
170 {
174 "stat",
176 }
178
179 /*
180 * Check we have creation rights in target namespace. Skip check if
181 * caller doesn't want it.
182 */
183 if (check_rights)
184 {
186
189 if (aclresult != ACLCHECK_OK)
192 }
193
194 /*
195 * Deal with the possibility that the statistics object already exists.
196 */
200 {
201 if (stmt->if_not_exists)
202 {
203 /*
204 * Since stats objects aren't members of extensions (see comments
205 * below), no need for checkMembershipInCurrentExtension here.
206 */
209 errmsg("statistics object \"%s\" already exists, skipping",
210 namestr)));
213 }
214
217 errmsg("statistics object \"%s\" already exists", namestr)));
218 }
219
220 /*
221 * Make sure no more than STATS_MAX_DIMENSIONS columns are used. There
222 * might be duplicates and so on, but we'll deal with those later.
223 */
224 numcols = list_length(stmt->exprs);
228 errmsg("cannot have more than %d columns in statistics",
230
231 /*
232 * Convert the expression list to a simple array of attnums, but also keep
233 * a list of more complex expressions. While at it, enforce some
234 * constraints - we don't allow extended statistics on system attributes,
235 * and we require the data type to have a less-than operator.
236 *
237 * There are many ways to "mask" a simple attribute reference as an
238 * expression, for example "(a+0)" etc. We can't possibly detect all of
239 * them, but we handle at least the simple case with the attribute in
240 * parens. There'll always be a way around this, if the user is determined
241 * (like the "(a+0)" example), but this makes it somewhat consistent with
242 * how indexes treat attributes/expressions.
243 */
244 foreach(cell, stmt->exprs)
245 {
247
248 if (selem->name) /* column reference */
249 {
250 char *attname;
254
255 attname = selem->name;
256
261 errmsg("column \"%s\" does not exist",
262 attname)));
264
265 /* Disallow use of system attributes in extended stats */
266 if (attForm->attnum <= 0)
269 errmsg("statistics creation on system columns is not supported")));
270
271 /* Disallow use of virtual generated columns in extended stats */
272 if (attForm->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
275 errmsg("statistics creation on virtual generated columns is not supported")));
276
277 /* Disallow data types without a less-than operator */
279 if (type->lt_opr == InvalidOid)
282 errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class",
283 attname, format_type_be(attForm->atttypid))));
284
285 attnums[nattnums] = attForm->attnum;
286 nattnums++;
288 }
289 else if (IsA(selem->expr, Var)) /* column reference in parens */
290 {
291 Var *var = (Var *) selem->expr;
293
294 /* Disallow use of system attributes in extended stats */
295 if (var->varattno <= 0)
298 errmsg("statistics creation on system columns is not supported")));
299
300 /* Disallow use of virtual generated columns in extended stats */
301 if (get_attgenerated(relid, var->varattno) == ATTRIBUTE_GENERATED_VIRTUAL)
304 errmsg("statistics creation on virtual generated columns is not supported")));
305
306 /* Disallow data types without a less-than operator */
307 type = lookup_type_cache(var->vartype, TYPECACHE_LT_OPR);
308 if (type->lt_opr == InvalidOid)
311 errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class",
312 get_attname(relid, var->varattno, false), format_type_be(var->vartype))));
313
314 attnums[nattnums] = var->varattno;
315 nattnums++;
316 }
317 else /* expression */
318 {
319 Node *expr = selem->expr;
320 Oid atttype;
322 Bitmapset *attnums = NULL;
323 int k;
324
325 Assert(expr != NULL);
326
327 pull_varattnos(expr, 1, &attnums);
328
329 k = -1;
330 while ((k = bms_next_member(attnums, k)) >= 0)
331 {
333
334 /* Disallow expressions referencing system attributes. */
335 if (attnum <= 0)
338 errmsg("statistics creation on system columns is not supported")));
339
340 /* Disallow use of virtual generated columns in extended stats */
344 errmsg("statistics creation on virtual generated columns is not supported")));
345 }
346
347 /*
348 * Disallow data types without a less-than operator.
349 *
350 * We ignore this for statistics on a single expression, in which
351 * case we'll build the regular statistics only (and that code can
352 * deal with such data types).
353 */
354 if (list_length(stmt->exprs) > 1)
355 {
356 atttype = exprType(expr);
358 if (type->lt_opr == InvalidOid)
361 errmsg("expression cannot be used in multivariate statistics because its type %s has no default btree operator class",
362 format_type_be(atttype))));
363 }
364
365 stxexprs = lappend(stxexprs, expr);
366 }
367 }
368
369 /*
370 * Parse the statistics kinds.
371 *
372 * First check that if this is the case with a single expression, there
373 * are no statistics kinds specified (we don't allow that for the simple
374 * CREATE STATISTICS form).
375 */
376 if ((list_length(stmt->exprs) == 1) && (list_length(stxexprs) == 1))
377 {
378 /* statistics kinds not specified */
379 if (stmt->stat_types != NIL)
382 errmsg("when building statistics on a single expression, statistics kinds may not be specified")));
383 }
384
385 /* OK, let's check that we recognize the statistics kinds. */
386 build_ndistinct = false;
387 build_dependencies = false;
388 build_mcv = false;
389 foreach(cell, stmt->stat_types)
390 {
391 char *type = strVal(lfirst(cell));
392
393 if (strcmp(type, "ndistinct") == 0)
394 {
395 build_ndistinct = true;
396 requested_type = true;
397 }
398 else if (strcmp(type, "dependencies") == 0)
399 {
400 build_dependencies = true;
401 requested_type = true;
402 }
403 else if (strcmp(type, "mcv") == 0)
404 {
405 build_mcv = true;
406 requested_type = true;
407 }
408 else
411 errmsg("unrecognized statistics kind \"%s\"",
412 type)));
413 }
414
415 /*
416 * If no statistic type was specified, build them all (but only when the
417 * statistics is defined on more than one column/expression).
418 */
419 if ((!requested_type) && (numcols >= 2))
420 {
421 build_ndistinct = true;
422 build_dependencies = true;
423 build_mcv = true;
424 }
425
426 /*
427 * When there are non-trivial expressions, build the expression stats
428 * automatically. This allows calculating good estimates for stats that
429 * consider per-clause estimates (e.g. functional dependencies).
430 */
432
433 /*
434 * Check that at least two columns were specified in the statement, or
435 * that we're building statistics on a single expression.
436 */
437 if ((numcols < 2) && (list_length(stxexprs) != 1))
440 errmsg("extended statistics require at least 2 columns")));
441
442 /*
443 * Sort the attnums, which makes detecting duplicates somewhat easier, and
444 * it does not hurt (it does not matter for the contents, unlike for
445 * indexes, for example).
446 */
447 qsort(attnums, nattnums, sizeof(int16), compare_int16);
448
449 /*
450 * Check for duplicates in the list of columns. The attnums are sorted so
451 * just check consecutive elements.
452 */
453 for (i = 1; i < nattnums; i++)
454 {
455 if (attnums[i] == attnums[i - 1])
458 errmsg("duplicate column name in statistics definition")));
459 }
460
461 /*
462 * Check for duplicate expressions. We do two loops, counting the
463 * occurrences of each expression. This is O(N^2) but we only allow small
464 * number of expressions and it's not executed often.
465 *
466 * XXX We don't cross-check attributes and expressions, because it does
467 * not seem worth it. In principle we could check that expressions don't
468 * contain trivial attribute references like "(a)", but the reasoning is
469 * similar to why we don't bother with extracting columns from
470 * expressions. It's either expensive or very easy to defeat for
471 * determined user, and there's no risk if we allow such statistics (the
472 * statistics is useless, but harmless).
473 */
474 foreach(cell, stxexprs)
475 {
476 Node *expr1 = (Node *) lfirst(cell);
477 int cnt = 0;
478
479 foreach(cell2, stxexprs)
480 {
481 Node *expr2 = (Node *) lfirst(cell2);
482
483 if (equal(expr1, expr2))
484 cnt += 1;
485 }
486
487 /* every expression should find at least itself */
488 Assert(cnt >= 1);
489
490 if (cnt > 1)
493 errmsg("duplicate expression in statistics definition")));
494 }
495
496 /* Form an int2vector representation of the sorted column list */
497 stxkeys = buildint2vector(attnums, nattnums);
498
499 /* construct the char array of enabled statistic types */
500 ntypes = 0;
501 if (build_ndistinct)
505 if (build_mcv)
509 Assert(ntypes > 0 && ntypes <= lengthof(types));
511
512 /* convert the expressions (if any) to a text datum */
513 if (stxexprs != NIL)
514 {
515 char *exprsString;
516
520 }
521 else
522 exprsDatum = (Datum) 0;
523
525
526 /*
527 * Everything seems fine, so let's build the pg_statistic_ext tuple.
528 */
529 memset(values, 0, sizeof(values));
530 memset(nulls, false, sizeof(nulls));
531
540 nulls[Anum_pg_statistic_ext_stxstattarget - 1] = true;
542
544 if (exprsDatum == (Datum) 0)
545 nulls[Anum_pg_statistic_ext_stxexprs - 1] = true;
546
547 /* insert it into pg_statistic_ext */
548 htup = heap_form_tuple(statrel->rd_att, values, nulls);
550 heap_freetuple(htup);
551
553
554 /*
555 * We used to create the pg_statistic_ext_data tuple too, but it's not
556 * clear what value should the stxdinherit flag have (it depends on
557 * whether the rel is partitioned, contains data, etc.)
558 */
559
561
562 /*
563 * Invalidate relcache so that others see the new statistics object.
564 */
566
568
569 /*
570 * Add an AUTO dependency on each column used in the stats, so that the
571 * stats object goes away if any or all of them get dropped.
572 */
574
575 /* add dependencies for plain column references */
576 for (i = 0; i < nattnums; i++)
577 {
580 }
581
582 /*
583 * If there are no dependencies on a column, give the statistics object an
584 * auto dependency on the whole table. In most cases, this will be
585 * redundant, but it might not be if the statistics expressions contain no
586 * Vars (which might seem strange but possible). This is consistent with
587 * what we do for indexes in index_create.
588 *
589 * XXX We intentionally don't consider the expressions before adding this
590 * dependency, because recordDependencyOnSingleRelExpr may not create any
591 * dependencies for whole-row Vars.
592 */
593 if (!nattnums)
594 {
597 }
598
599 /*
600 * Store dependencies on anything mentioned in statistics expressions,
601 * just like we do for index expressions.
602 */
603 if (stxexprs)
605 (Node *) stxexprs,
606 relid,
608 DEPENDENCY_AUTO, false);
609
610 /*
611 * Also add dependencies on namespace and owner. These are required
612 * because the stats object might have a different namespace and/or owner
613 * than the underlying table(s).
614 */
617
619
620 /*
621 * XXX probably there should be a recordDependencyOnCurrentExtension call
622 * here too, but we'd have to add support for ALTER EXTENSION ADD/DROP
623 * STATISTICS, which is more work than it seems worth.
624 */
625
626 /* Add any requested comment */
627 if (stmt->stxcomment != NULL)
629 stmt->stxcomment);
630
631 /* Return stats object's address */
632 return myself;
633}
int16 AttrNumber
Definition attnum.h:21
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1305
#define lengthof(array)
Definition c.h:803
bool IsSystemRelation(Relation relation)
Definition catalog.c:74
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition comment.c:143
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
@ DEPENDENCY_AUTO
Definition dependency.h:34
struct typedefs * types
Definition ecpg.c:30
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
bool allowSystemTableMods
Definition globals.c: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:964
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:903
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:802
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:403
#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:205
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition relation.c:137
#define STATS_MAX_DIMENSIONS
Definition statistics.h:19
static char * ChooseExtendedStatisticNameAddition(List *exprs)
Definition statscmds.c:891
static char * ChooseExtendedStatisticName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition statscmds.c:849
static int compare_int16(const void *a, const void *b)
Definition statscmds.c:50
Form_pg_class rd_rel
Definition rel.h:111
Definition c.h:760
#define FirstLowInvalidHeapAttributeNumber
Definition sysattr.h:27
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition syscache.c:475
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition syscache.h:102
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:386
#define TYPECACHE_LT_OPR
Definition typcache.h:139
#define strVal(v)
Definition value.h:82
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition var.c:296
const char * type

References 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_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(), 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 1834 of file functioncmds.c.

1835{
1836 Oid typeid;
1837 char typtype;
1838 Oid langid;
1844 bool nulls[Natts_pg_transform] = {0};
1845 bool replaces[Natts_pg_transform] = {0};
1847 HeapTuple tuple;
1848 HeapTuple newtuple;
1849 Relation relation;
1851 referenced;
1852 ObjectAddresses *addrs;
1853 bool is_replace;
1854
1855 /*
1856 * Get the type
1857 */
1858 typeid = typenameTypeId(NULL, stmt->type_name);
1859 typtype = get_typtype(typeid);
1860
1861 if (typtype == TYPTYPE_PSEUDO)
1862 ereport(ERROR,
1864 errmsg("data type %s is a pseudo-type",
1865 TypeNameToString(stmt->type_name))));
1866
1867 if (typtype == TYPTYPE_DOMAIN)
1868 ereport(ERROR,
1870 errmsg("data type %s is a domain",
1871 TypeNameToString(stmt->type_name))));
1872
1875
1877 if (aclresult != ACLCHECK_OK)
1879
1880 /*
1881 * Get the language
1882 */
1883 langid = get_language_oid(stmt->lang, false);
1884
1886 if (aclresult != ACLCHECK_OK)
1888
1889 /*
1890 * Get the functions
1891 */
1892 if (stmt->fromsql)
1893 {
1895
1898
1900 if (aclresult != ACLCHECK_OK)
1902
1904 if (!HeapTupleIsValid(tuple))
1905 elog(ERROR, "cache lookup failed for function %u", fromsqlfuncid);
1907 if (procstruct->prorettype != INTERNALOID)
1908 ereport(ERROR,
1910 errmsg("return data type of FROM SQL function must be %s",
1911 "internal")));
1913 ReleaseSysCache(tuple);
1914 }
1915 else
1917
1918 if (stmt->tosql)
1919 {
1921
1924
1926 if (aclresult != ACLCHECK_OK)
1928
1930 if (!HeapTupleIsValid(tuple))
1931 elog(ERROR, "cache lookup failed for function %u", tosqlfuncid);
1933 if (procstruct->prorettype != typeid)
1934 ereport(ERROR,
1936 errmsg("return data type of TO SQL function must be the transform data type")));
1938 ReleaseSysCache(tuple);
1939 }
1940 else
1942
1943 /*
1944 * Ready to go
1945 */
1950
1952
1954 ObjectIdGetDatum(typeid),
1955 ObjectIdGetDatum(langid));
1956 if (HeapTupleIsValid(tuple))
1957 {
1959
1960 if (!stmt->replace)
1961 ereport(ERROR,
1963 errmsg("transform for type %s language \"%s\" already exists",
1964 format_type_be(typeid),
1965 stmt->lang)));
1966
1969
1970 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
1971 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
1972
1973 transformid = form->oid;
1974 ReleaseSysCache(tuple);
1975 is_replace = true;
1976 }
1977 else
1978 {
1982 newtuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
1983 CatalogTupleInsert(relation, newtuple);
1984 is_replace = false;
1985 }
1986
1987 if (is_replace)
1989
1990 addrs = new_object_addresses();
1991
1992 /* make dependency entries */
1994
1995 /* dependency on language */
1998
1999 /* dependency on type */
2002
2003 /* dependencies on functions */
2005 {
2008 }
2010 {
2013 }
2014
2016 free_object_addresses(addrs);
2017
2018 /* dependency on extension */
2020
2021 /* Post creation hook for new transform */
2023
2024 heap_freetuple(newtuple);
2025
2026 table_close(relation, RowExclusiveLock);
2027
2028 return myself;
2029}
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:301
FormData_pg_transform * Form_pg_transform
Oid get_language_oid(const char *langname, bool missing_ok)
Definition proclang.c:227
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition syscache.c:230

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(), 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 1111 of file foreigncmds.c.

1112{
1113 Relation rel;
1116 bool nulls[Natts_pg_user_mapping];
1117 HeapTuple tuple;
1118 Oid useId;
1119 Oid umId;
1124 RoleSpec *role = (RoleSpec *) stmt->user;
1125
1127
1128 if (role->roletype == ROLESPEC_PUBLIC)
1130 else
1131 useId = get_rolespec_oid(stmt->user, false);
1132
1133 /* Check that the server exists. */
1134 srv = GetForeignServerByName(stmt->servername, false);
1135
1136 user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1137
1138 /*
1139 * Check that the user mapping is unique within server.
1140 */
1143 ObjectIdGetDatum(srv->serverid));
1144
1145 if (OidIsValid(umId))
1146 {
1147 if (stmt->if_not_exists)
1148 {
1149 /*
1150 * Since user mappings aren't members of extensions (see comments
1151 * below), no need for checkMembershipInCurrentExtension here.
1152 */
1155 errmsg("user mapping for \"%s\" already exists for server \"%s\", skipping",
1157 stmt->servername)));
1158
1160 return InvalidObjectAddress;
1161 }
1162 else
1163 ereport(ERROR,
1165 errmsg("user mapping for \"%s\" already exists for server \"%s\"",
1167 stmt->servername)));
1168 }
1169
1170 fdw = GetForeignDataWrapper(srv->fdwid);
1171
1172 /*
1173 * Insert tuple into pg_user_mapping.
1174 */
1175 memset(values, 0, sizeof(values));
1176 memset(nulls, false, sizeof(nulls));
1177
1183
1184 /* Add user options */
1187 stmt->options,
1188 fdw->fdwvalidator);
1189
1192 else
1193 nulls[Anum_pg_user_mapping_umoptions - 1] = true;
1194
1195 tuple = heap_form_tuple(rel->rd_att, values, nulls);
1196
1197 CatalogTupleInsert(rel, tuple);
1198
1199 heap_freetuple(tuple);
1200
1201 /* Add dependency on the server */
1202 myself.classId = UserMappingRelationId;
1203 myself.objectId = umId;
1204 myself.objectSubId = 0;
1205
1207 referenced.objectId = srv->serverid;
1208 referenced.objectSubId = 0;
1210
1211 if (OidIsValid(useId))
1212 {
1213 /* Record the mapped user dependency */
1215 }
1216
1217 /*
1218 * Perhaps someday there should be a recordDependencyOnCurrentExtension
1219 * call here; but since roles aren't members of extensions, it seems like
1220 * user mappings shouldn't be either. Note that the grammar and pg_dump
1221 * would need to be extended too if we change this.
1222 */
1223
1224 /* Post creation hook for new user mapping */
1226
1228
1229 return myself;
1230}

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:844
Node * arg
Definition parsenodes.h:845

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(), cluster(), createdb(), CreateExtension(), DefineAggregate(), DefineCollation(), DefineOperator(), DefineType(), dintdict_init(), dsimple_init(), dsynonym_init(), dxsyn_init(), ExecCheckpoint(), ExecReindex(), 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(), 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:542

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

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

◆ 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:543
Datum int8in(PG_FUNCTION_ARGS)
Definition int8.c:50
static int64 DatumGetInt64(Datum X)
Definition postgres.h:413
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:252

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

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:1754
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition lsyscache.c:3024
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,
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 544 of file indexcmds.c.

556{
557 bool concurrent;
558 char *indexRelationName;
559 char *accessMethodName;
560 Oid *typeIds;
570 Relation rel;
571 HeapTuple tuple;
574 bool amcanorder;
575 bool amissummarizing;
576 amoptions_function amoptions;
577 bool exclusion;
578 bool partitioned;
579 bool safe_index;
580 Datum reloptions;
582 IndexInfo *indexInfo;
583 bits16 flags;
588 ObjectAddress address;
589 LockRelId heaprelid;
591 LOCKMODE lockmode;
592 Snapshot snapshot;
596
598
600
601 /*
602 * Some callers need us to run with an empty default_tablespace; this is a
603 * necessary hack to be able to reproduce catalog state accurately when
604 * recreating indexes after table-rewriting ALTER TABLE.
605 */
606 if (stmt->reset_default_tblspc)
607 (void) set_config_option("default_tablespace", "",
609 GUC_ACTION_SAVE, true, 0, false);
610
611 /*
612 * Force non-concurrent build on temporary relations, even if CONCURRENTLY
613 * was requested. Other backends can't access a temporary relation, so
614 * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
615 * is more efficient. Do this before any use of the concurrent option is
616 * done.
617 */
619 concurrent = true;
620 else
621 concurrent = false;
622
623 /*
624 * Start progress report. If we're building a partition, this was already
625 * done.
626 */
628 {
631 concurrent ?
634 }
635
636 /*
637 * No index OID to report yet
638 */
640 InvalidOid);
641
642 /*
643 * count key attributes in index
644 */
645 numberOfKeyAttributes = list_length(stmt->indexParams);
646
647 /*
648 * Calculate the new list of index columns including both key columns and
649 * INCLUDE columns. Later we can determine which of these are key
650 * columns, and which are just part of the INCLUDE list by checking the
651 * list position. A list item in a position less than ii_NumIndexKeyAttrs
652 * is part of the key columns, and anything equal to and over is part of
653 * the INCLUDE columns.
654 */
655 allIndexParams = list_concat_copy(stmt->indexParams,
656 stmt->indexIncludingParams);
658
659 if (numberOfKeyAttributes <= 0)
662 errmsg("must specify at least one column")));
666 errmsg("cannot use more than %d columns in an index",
668
669 /*
670 * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
671 * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
672 * (but not VACUUM).
673 *
674 * NB: Caller is responsible for making sure that tableId refers to the
675 * relation on which the index should be built; except in bootstrap mode,
676 * this will typically require the caller to have already locked the
677 * relation. To avoid lock upgrade hazards, that lock should be at least
678 * as strong as the one we take here.
679 *
680 * NB: If the lock strength here ever changes, code that is run by
681 * parallel workers under the control of certain particular ambuild
682 * functions will need to be updated, too.
683 */
684 lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
685 rel = table_open(tableId, lockmode);
686
687 /*
688 * Switch to the table owner's userid, so that any index functions are run
689 * as that user. Also lock down security-restricted operations. We
690 * already arranged to make GUC variable changes local to this command.
691 */
693 SetUserIdAndSecContext(rel->rd_rel->relowner,
695
697
698 /*
699 * It has exclusion constraint behavior if it's an EXCLUDE constraint or a
700 * temporal PRIMARY KEY/UNIQUE constraint
701 */
702 exclusion = stmt->excludeOpNames || stmt->iswithoutoverlaps;
703
704 /* Ensure that it makes sense to index this kind of relation */
705 switch (rel->rd_rel->relkind)
706 {
707 case RELKIND_RELATION:
708 case RELKIND_MATVIEW:
710 /* OK */
711 break;
712 default:
715 errmsg("cannot create index on relation \"%s\"",
718 break;
719 }
720
721 /*
722 * Establish behavior for partitioned tables, and verify sanity of
723 * parameters.
724 *
725 * We do not build an actual index in this case; we only create a few
726 * catalog entries. The actual indexes are built by recursing for each
727 * partition.
728 */
730 if (partitioned)
731 {
732 /*
733 * Note: we check 'stmt->concurrent' rather than 'concurrent', so that
734 * the error is thrown also for temporary tables. Seems better to be
735 * consistent, even though we could do it on temporary table because
736 * we're not actually doing it concurrently.
737 */
738 if (stmt->concurrent)
741 errmsg("cannot create index on partitioned table \"%s\" concurrently",
743 }
744
745 /*
746 * Don't try to CREATE INDEX on temp tables of other backends.
747 */
748 if (RELATION_IS_OTHER_TEMP(rel))
751 errmsg("cannot create indexes on temporary tables of other sessions")));
752
753 /*
754 * Unless our caller vouches for having checked this already, insist that
755 * the table not be in use by our own session, either. Otherwise we might
756 * fail to make entries in the new index (for instance, if an INSERT or
757 * UPDATE is in progress and has already made its list of target indexes).
758 */
760 CheckTableNotInUse(rel, "CREATE INDEX");
761
762 /*
763 * Verify we (still) have CREATE rights in the rel's namespace.
764 * (Presumably we did when the rel was created, but maybe not anymore.)
765 * Skip check if caller doesn't want it. Also skip check if
766 * bootstrapping, since permissions machinery may not be working yet.
767 */
769 {
771
773 ACL_CREATE);
774 if (aclresult != ACLCHECK_OK)
777 }
778
779 /*
780 * Select tablespace to use. If not specified, use default tablespace
781 * (which may in turn default to database's default).
782 */
783 if (stmt->tableSpace)
784 {
785 tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
789 errmsg("cannot specify default tablespace for partitioned relations")));
790 }
791 else
792 {
793 tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence,
795 /* note InvalidOid is OK in this case */
796 }
797
798 /* Check tablespace permissions */
799 if (check_rights &&
801 {
803
805 ACL_CREATE);
806 if (aclresult != ACLCHECK_OK)
809 }
810
811 /*
812 * Force shared indexes into the pg_global tablespace. This is a bit of a
813 * hack but seems simpler than marking them in the BKI commands. On the
814 * other hand, if it's not shared, don't allow it to be placed there.
815 */
816 if (rel->rd_rel->relisshared)
821 errmsg("only shared relations can be placed in pg_global tablespace")));
822
823 /*
824 * Choose the index column names.
825 */
827
828 /*
829 * Select name for index if caller didn't specify
830 */
831 indexRelationName = stmt->idxname;
832 if (indexRelationName == NULL)
836 stmt->excludeOpNames,
837 stmt->primary,
838 stmt->isconstraint);
839
840 /*
841 * look up the access method, verify it can handle the requested features
842 */
843 accessMethodName = stmt->accessMethod;
845 if (!HeapTupleIsValid(tuple))
846 {
847 /*
848 * Hack to provide more-or-less-transparent updating of old RTREE
849 * indexes to GiST: if RTREE is requested and not found, use GIST.
850 */
851 if (strcmp(accessMethodName, "rtree") == 0)
852 {
854 (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
855 accessMethodName = "gist";
857 }
858
859 if (!HeapTupleIsValid(tuple))
862 errmsg("access method \"%s\" does not exist",
864 }
868
871
872 if (stmt->unique && !stmt->iswithoutoverlaps && !amRoutine->amcanunique)
875 errmsg("access method \"%s\" does not support unique indexes",
877 if (stmt->indexIncludingParams != NIL && !amRoutine->amcaninclude)
880 errmsg("access method \"%s\" does not support included columns",
882 if (numberOfKeyAttributes > 1 && !amRoutine->amcanmulticol)
885 errmsg("access method \"%s\" does not support multicolumn indexes",
887 if (exclusion && amRoutine->amgettuple == NULL)
890 errmsg("access method \"%s\" does not support exclusion constraints",
892 if (stmt->iswithoutoverlaps && strcmp(accessMethodName, "gist") != 0)
895 errmsg("access method \"%s\" does not support WITHOUT OVERLAPS constraints",
897
898 amcanorder = amRoutine->amcanorder;
899 amoptions = amRoutine->amoptions;
900 amissummarizing = amRoutine->amsummarizing;
901
902 ReleaseSysCache(tuple);
903
904 /*
905 * Validate predicate, if given
906 */
907 if (stmt->whereClause)
908 CheckPredicate((Expr *) stmt->whereClause);
909
910 /*
911 * Parse AM-specific options, convert to text array form, validate.
912 */
913 reloptions = transformRelOptions((Datum) 0, stmt->options,
914 NULL, NULL, false, false);
915
916 (void) index_reloptions(amoptions, reloptions, true);
917
918 /*
919 * Prepare arguments for index_create, primarily an IndexInfo structure.
920 * Note that predicates must be in implicit-AND format. In a concurrent
921 * build, mark it not-ready-for-inserts.
922 */
926 NIL, /* expressions, NIL for now */
927 make_ands_implicit((Expr *) stmt->whereClause),
928 stmt->unique,
929 stmt->nulls_not_distinct,
930 !concurrent,
931 concurrent,
933 stmt->iswithoutoverlaps);
934
940 ComputeIndexAttrs(pstate,
941 indexInfo,
944 stmt->excludeOpNames, tableId,
946 amcanorder, stmt->isconstraint, stmt->iswithoutoverlaps,
949
950 /*
951 * Extra checks when creating a PRIMARY KEY index.
952 */
953 if (stmt->primary)
955
956 /*
957 * If this table is partitioned and we're creating a unique index, primary
958 * key, or exclusion constraint, make sure that the partition key is a
959 * subset of the index's columns. Otherwise it would be possible to
960 * violate uniqueness by putting values that ought to be unique in
961 * different partitions.
962 *
963 * We could lift this limitation if we had global indexes, but those have
964 * their own problems, so this is a useful feature combination.
965 */
966 if (partitioned && (stmt->unique || exclusion))
967 {
969 const char *constraint_type;
970 int i;
971
972 if (stmt->primary)
973 constraint_type = "PRIMARY KEY";
974 else if (stmt->unique)
975 constraint_type = "UNIQUE";
976 else if (stmt->excludeOpNames)
977 constraint_type = "EXCLUDE";
978 else
979 {
980 elog(ERROR, "unknown constraint type");
981 constraint_type = NULL; /* keep compiler quiet */
982 }
983
984 /*
985 * Verify that all the columns in the partition key appear in the
986 * unique key definition, with the same notion of equality.
987 */
988 for (i = 0; i < key->partnatts; i++)
989 {
990 bool found = false;
991 int eq_strategy;
993 int j;
994
995 /*
996 * Identify the equality operator associated with this partkey
997 * column. For list and range partitioning, partkeys use btree
998 * operator classes; hash partitioning uses hash operator classes.
999 * (Keep this in sync with ComputePartitionAttrs!)
1000 */
1001 if (key->strategy == PARTITION_STRATEGY_HASH)
1003 else
1005
1006 ptkey_eqop = get_opfamily_member(key->partopfamily[i],
1007 key->partopcintype[i],
1008 key->partopcintype[i],
1009 eq_strategy);
1010 if (!OidIsValid(ptkey_eqop))
1011 elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
1012 eq_strategy, key->partopcintype[i], key->partopcintype[i],
1013 key->partopfamily[i]);
1014
1015 /*
1016 * It may be possible to support UNIQUE constraints when partition
1017 * keys are expressions, but is it worth it? Give up for now.
1018 */
1019 if (key->partattrs[i] == 0)
1020 ereport(ERROR,
1022 errmsg("unsupported %s constraint with partition key definition",
1024 errdetail("%s constraints cannot be used when partition keys include expressions.",
1025 constraint_type)));
1026
1027 /* Search the index column(s) for a match */
1028 for (j = 0; j < indexInfo->ii_NumIndexKeyAttrs; j++)
1029 {
1030 if (key->partattrs[i] == indexInfo->ii_IndexAttrNumbers[j])
1031 {
1032 /*
1033 * Matched the column, now what about the collation and
1034 * equality op?
1035 */
1038
1039 if (key->partcollation[i] != collationIds[j])
1040 continue;
1041
1043 &idx_opfamily,
1044 &idx_opcintype))
1045 {
1047
1048 if (stmt->unique && !stmt->iswithoutoverlaps)
1052 COMPARE_EQ);
1053 else if (exclusion)
1054 idx_eqop = indexInfo->ii_ExclusionOps[j];
1055
1056 if (!idx_eqop)
1057 ereport(ERROR,
1059 errmsg("could not identify an equality operator for type %s", format_type_be(idx_opcintype)),
1060 errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
1062
1063 if (ptkey_eqop == idx_eqop)
1064 {
1065 found = true;
1066 break;
1067 }
1068 else if (exclusion)
1069 {
1070 /*
1071 * We found a match, but it's not an equality
1072 * operator. Instead of failing below with an
1073 * error message about a missing column, fail now
1074 * and explain that the operator is wrong.
1075 */
1076 Form_pg_attribute att = TupleDescAttr(RelationGetDescr(rel), key->partattrs[i] - 1);
1077
1078 ereport(ERROR,
1080 errmsg("cannot match partition key to index on column \"%s\" using non-equal operator \"%s\"",
1081 NameStr(att->attname),
1082 get_opname(indexInfo->ii_ExclusionOps[j]))));
1083 }
1084 }
1085 }
1086 }
1087
1088 if (!found)
1089 {
1091
1093 key->partattrs[i] - 1);
1094 ereport(ERROR,
1096 /* translator: %s is UNIQUE, PRIMARY KEY, etc */
1097 errmsg("%s constraint on partitioned table must include all partitioning columns",
1099 /* translator: first %s is UNIQUE, PRIMARY KEY, etc */
1100 errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
1102 NameStr(att->attname))));
1103 }
1104 }
1105 }
1106
1107
1108 /*
1109 * We disallow indexes on system columns. They would not necessarily get
1110 * updated correctly, and they don't seem useful anyway.
1111 *
1112 * Also disallow virtual generated columns in indexes (use expression
1113 * index instead).
1114 */
1115 for (int i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1116 {
1117 AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i];
1118
1119 if (attno < 0)
1120 ereport(ERROR,
1122 errmsg("index creation on system columns is not supported")));
1123
1124
1125 if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1126 ereport(ERROR,
1128 stmt->primary ?
1129 errmsg("primary keys on virtual generated columns are not supported") :
1130 stmt->isconstraint ?
1131 errmsg("unique constraints on virtual generated columns are not supported") :
1132 errmsg("indexes on virtual generated columns are not supported"));
1133 }
1134
1135 /*
1136 * Also check for system and generated columns used in expressions or
1137 * predicates.
1138 */
1139 if (indexInfo->ii_Expressions || indexInfo->ii_Predicate)
1140 {
1142 int j;
1143
1144 pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
1145 pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
1146
1147 for (int i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
1148 {
1150 indexattrs))
1151 ereport(ERROR,
1153 errmsg("index creation on system columns is not supported")));
1154 }
1155
1156 /*
1157 * XXX Virtual generated columns in index expressions or predicates
1158 * could be supported, but it needs support in
1159 * RelationGetIndexExpressions() and RelationGetIndexPredicate().
1160 */
1161 j = -1;
1162 while ((j = bms_next_member(indexattrs, j)) >= 0)
1163 {
1165
1166 if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1167 ereport(ERROR,
1169 stmt->isconstraint ?
1170 errmsg("unique constraints on virtual generated columns are not supported") :
1171 errmsg("indexes on virtual generated columns are not supported")));
1172 }
1173 }
1174
1175 /* Is index safe for others to ignore? See set_indexsafe_procflags() */
1176 safe_index = indexInfo->ii_Expressions == NIL &&
1177 indexInfo->ii_Predicate == NIL;
1178
1179 /*
1180 * Report index creation if appropriate (delay this till after most of the
1181 * error checks)
1182 */
1183 if (stmt->isconstraint && !quiet)
1184 {
1185 const char *constraint_type;
1186
1187 if (stmt->primary)
1188 constraint_type = "PRIMARY KEY";
1189 else if (stmt->unique)
1190 constraint_type = "UNIQUE";
1191 else if (stmt->excludeOpNames)
1192 constraint_type = "EXCLUDE";
1193 else
1194 {
1195 elog(ERROR, "unknown constraint type");
1196 constraint_type = NULL; /* keep compiler quiet */
1197 }
1198
1200 (errmsg_internal("%s %s will create implicit index \"%s\" for table \"%s\"",
1201 is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
1204 }
1205
1206 /*
1207 * A valid stmt->oldNumber implies that we already have a built form of
1208 * the index. The caller should also decline any index build.
1209 */
1210 Assert(!RelFileNumberIsValid(stmt->oldNumber) || (skip_build && !concurrent));
1211
1212 /*
1213 * Make the catalog entries for the index, including constraints. This
1214 * step also actually builds the index, except if caller requested not to
1215 * or in concurrent mode, in which case it'll be done later, or doing a
1216 * partitioned index (because those don't have storage).
1217 */
1218 flags = constr_flags = 0;
1219 if (stmt->isconstraint)
1221 if (skip_build || concurrent || partitioned)
1222 flags |= INDEX_CREATE_SKIP_BUILD;
1223 if (stmt->if_not_exists)
1225 if (concurrent)
1226 flags |= INDEX_CREATE_CONCURRENT;
1227 if (partitioned)
1228 flags |= INDEX_CREATE_PARTITIONED;
1229 if (stmt->primary)
1230 flags |= INDEX_CREATE_IS_PRIMARY;
1231
1232 /*
1233 * If the table is partitioned, and recursion was declined but partitions
1234 * exist, mark the index as invalid.
1235 */
1236 if (partitioned && stmt->relation && !stmt->relation->inh)
1237 {
1239
1240 if (pd->nparts != 0)
1241 flags |= INDEX_CREATE_INVALID;
1242 }
1243
1244 if (stmt->deferrable)
1246 if (stmt->initdeferred)
1248 if (stmt->iswithoutoverlaps)
1250
1254 stmt->oldNumber, indexInfo, indexColNames,
1257 coloptions, NULL, reloptions,
1258 flags, constr_flags,
1261
1263
1265 {
1266 /*
1267 * Roll back any GUC changes executed by index functions. Also revert
1268 * to original default_tablespace if we changed it above.
1269 */
1271
1272 /* Restore userid and security context */
1274
1275 table_close(rel, NoLock);
1276
1277 /* If this is the top-level index, we're done */
1280
1281 return address;
1282 }
1283
1284 /*
1285 * Roll back any GUC changes executed by index functions, and keep
1286 * subsequent changes local to this command. This is essential if some
1287 * index function changed a behavior-affecting GUC, e.g. search_path.
1288 */
1292
1293 /* Add any requested comment */
1294 if (stmt->idxcomment != NULL)
1296 stmt->idxcomment);
1297
1298 if (partitioned)
1299 {
1300 PartitionDesc partdesc;
1301
1302 /*
1303 * Unless caller specified to skip this step (via ONLY), process each
1304 * partition to make sure they all contain a corresponding index.
1305 *
1306 * If we're called internally (no stmt->relation), recurse always.
1307 */
1308 partdesc = RelationGetPartitionDesc(rel, true);
1309 if ((!stmt->relation || stmt->relation->inh) && partdesc->nparts > 0)
1310 {
1311 int nparts = partdesc->nparts;
1312 Oid *part_oids = palloc_array(Oid, nparts);
1313 bool invalidate_parent = false;
1316
1317 /*
1318 * Report the total number of partitions at the start of the
1319 * command; don't update it when being called recursively.
1320 */
1322 {
1323 /*
1324 * When called by ProcessUtilitySlow, the number of partitions
1325 * is passed in as an optimization; but other callers pass -1
1326 * since they don't have the value handy. This should count
1327 * partitions the same way, ie one less than the number of
1328 * relations find_all_inheritors reports.
1329 *
1330 * We assume we needn't ask find_all_inheritors to take locks,
1331 * because that should have happened already for all callers.
1332 * Even if it did not, this is safe as long as we don't try to
1333 * touch the partitions here; the worst consequence would be a
1334 * bogus progress-reporting total.
1335 */
1336 if (total_parts < 0)
1337 {
1339
1340 total_parts = list_length(children) - 1;
1341 list_free(children);
1342 }
1343
1345 total_parts);
1346 }
1347
1348 /* Make a local copy of partdesc->oids[], just for safety */
1349 memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
1350
1351 /*
1352 * We'll need an IndexInfo describing the parent index. The one
1353 * built above is almost good enough, but not quite, because (for
1354 * example) its predicate expression if any hasn't been through
1355 * expression preprocessing. The most reliable way to get an
1356 * IndexInfo that will match those for child indexes is to build
1357 * it the same way, using BuildIndexInfo().
1358 */
1360 indexInfo = BuildIndexInfo(parentIndex);
1361
1363
1364 /*
1365 * For each partition, scan all existing indexes; if one matches
1366 * our index definition and is not already attached to some other
1367 * parent index, attach it to the one we just created.
1368 *
1369 * If none matches, build a new index by calling ourselves
1370 * recursively with the same options (except for the index name).
1371 */
1372 for (int i = 0; i < nparts; i++)
1373 {
1379 List *childidxs;
1380 ListCell *cell;
1381 AttrMap *attmap;
1382 bool found = false;
1383
1384 childrel = table_open(childRelid, lockmode);
1385
1388 SetUserIdAndSecContext(childrel->rd_rel->relowner,
1392
1393 /*
1394 * Don't try to create indexes on foreign tables, though. Skip
1395 * those if a regular index, or fail if trying to create a
1396 * constraint index.
1397 */
1398 if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1399 {
1400 if (stmt->unique || stmt->primary)
1401 ereport(ERROR,
1403 errmsg("cannot create unique index on partitioned table \"%s\"",
1405 errdetail("Table \"%s\" contains partitions that are foreign tables.",
1407
1411 table_close(childrel, lockmode);
1412 continue;
1413 }
1414
1416 attmap =
1418 parentDesc,
1419 false);
1420
1421 foreach(cell, childidxs)
1422 {
1423 Oid cldidxid = lfirst_oid(cell);
1426
1427 /* this index is already partition of another one */
1429 continue;
1430
1431 cldidx = index_open(cldidxid, lockmode);
1433 if (CompareIndexInfo(cldIdxInfo, indexInfo,
1434 cldidx->rd_indcollation,
1435 parentIndex->rd_indcollation,
1436 cldidx->rd_opfamily,
1437 parentIndex->rd_opfamily,
1438 attmap))
1439 {
1441
1442 /*
1443 * Found a match.
1444 *
1445 * If this index is being created in the parent
1446 * because of a constraint, then the child needs to
1447 * have a constraint also, so look for one. If there
1448 * is no such constraint, this index is no good, so
1449 * keep looking.
1450 */
1452 {
1453 cldConstrOid =
1455 cldidxid);
1456 if (cldConstrOid == InvalidOid)
1457 {
1458 index_close(cldidx, lockmode);
1459 continue;
1460 }
1461 }
1462
1463 /* Attach index to parent and we're done. */
1468 childRelid);
1469
1470 if (!cldidx->rd_index->indisvalid)
1471 invalidate_parent = true;
1472
1473 found = true;
1474
1475 /*
1476 * Report this partition as processed. Note that if
1477 * the partition has children itself, we'd ideally
1478 * count the children and update the progress report
1479 * for all of them; but that seems unduly expensive.
1480 * Instead, the progress report will act like all such
1481 * indirect children were processed in zero time at
1482 * the end of the command.
1483 */
1485
1486 /* keep lock till commit */
1488 break;
1489 }
1490
1491 index_close(cldidx, lockmode);
1492 }
1493
1499
1500 /*
1501 * If no matching index was found, create our own.
1502 */
1503 if (!found)
1504 {
1507
1508 /*
1509 * Build an IndexStmt describing the desired child index
1510 * in the same way that we do during ATTACH PARTITION.
1511 * Notably, we rely on generateClonedIndexStmt to produce
1512 * a search-path-independent representation, which the
1513 * original IndexStmt might not be.
1514 */
1517 attmap,
1518 NULL);
1519
1520 /*
1521 * Recurse as the starting user ID. Callee will use that
1522 * for permission checks, then switch again.
1523 */
1527 childAddr =
1528 DefineIndex(NULL, /* original pstate not applicable */
1530 InvalidOid, /* no predefined OID */
1531 indexRelationId, /* this is our child */
1533 -1,
1536 skip_build, quiet);
1539
1540 /*
1541 * Check if the index just created is valid or not, as it
1542 * could be possible that it has been switched as invalid
1543 * when recursing across multiple partition levels.
1544 */
1545 if (!get_index_isvalid(childAddr.objectId))
1546 invalidate_parent = true;
1547 }
1548
1550 }
1551
1552 index_close(parentIndex, lockmode);
1553
1554 /*
1555 * The pg_index row we inserted for this index was marked
1556 * indisvalid=true. But if we attached an existing index that is
1557 * invalid, this is incorrect, so update our row to invalid too.
1558 */
1560 {
1562 HeapTuple tup,
1563 newtup;
1564
1567 if (!HeapTupleIsValid(tup))
1568 elog(ERROR, "cache lookup failed for index %u",
1576
1577 /*
1578 * CCI here to make this update visible, in case this recurses
1579 * across multiple partition levels.
1580 */
1582 }
1583 }
1584
1585 /*
1586 * Indexes on partitioned tables are not themselves built, so we're
1587 * done here.
1588 */
1591 table_close(rel, NoLock);
1594 else
1595 {
1596 /* Update progress for an intermediate partitioned index itself */
1598 }
1599
1600 return address;
1601 }
1602
1605
1606 if (!concurrent)
1607 {
1608 /* Close the heap and we're done, in the non-concurrent case */
1609 table_close(rel, NoLock);
1610
1611 /*
1612 * If this is the top-level index, the command is done overall;
1613 * otherwise, increment progress to report one child index is done.
1614 */
1617 else
1619
1620 return address;
1621 }
1622
1623 /* save lockrelid and locktag for below, then close rel */
1624 heaprelid = rel->rd_lockInfo.lockRelId;
1625 SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1626 table_close(rel, NoLock);
1627
1628 /*
1629 * For a concurrent build, it's important to make the catalog entries
1630 * visible to other transactions before we start to build the index. That
1631 * will prevent them from making incompatible HOT updates. The new index
1632 * will be marked not indisready and not indisvalid, so that no one else
1633 * tries to either insert into it or use it for queries.
1634 *
1635 * We must commit our current transaction so that the index becomes
1636 * visible; then start another. Note that all the data structures we just
1637 * built are lost in the commit. The only data we keep past here are the
1638 * relation IDs.
1639 *
1640 * Before committing, get a session-level lock on the table, to ensure
1641 * that neither it nor the index can be dropped before we finish. This
1642 * cannot block, even if someone else is waiting for access, because we
1643 * already have the same lock within our transaction.
1644 *
1645 * Note: we don't currently bother with a session lock on the index,
1646 * because there are no operations that could change its state while we
1647 * hold lock on the parent table. This might need to change later.
1648 */
1650
1654
1655 /* Tell concurrent index builds to ignore us, if index qualifies */
1656 if (safe_index)
1658
1659 /*
1660 * The index is now visible, so we can report the OID. While on it,
1661 * include the report for the beginning of phase 2.
1662 */
1663 {
1664 const int progress_cols[] = {
1667 };
1668 const int64 progress_vals[] = {
1671 };
1672
1674 }
1675
1676 /*
1677 * Phase 2 of concurrent index build (see comments for validate_index()
1678 * for an overview of how this works)
1679 *
1680 * Now we must wait until no running transaction could have the table open
1681 * with the old list of indexes. Use ShareLock to consider running
1682 * transactions that hold locks that permit writing to the table. Note we
1683 * do not need to worry about xacts that open the table for writing after
1684 * this point; they will see the new index when they open it.
1685 *
1686 * Note: the reason we use actual lock acquisition here, rather than just
1687 * checking the ProcArray and sleeping, is that deadlock is possible if
1688 * one of the transactions in question is blocked trying to acquire an
1689 * exclusive lock on our table. The lock code will detect deadlock and
1690 * error out properly.
1691 */
1693
1694 /*
1695 * At this moment we are sure that there are no transactions with the
1696 * table open for write that don't have this new index in their list of
1697 * indexes. We have waited out all the existing transactions and any new
1698 * transaction will have the new index in its list, but the index is still
1699 * marked as "not-ready-for-inserts". The index is consulted while
1700 * deciding HOT-safety though. This arrangement ensures that no new HOT
1701 * chains can be created where the new tuple and the old tuple in the
1702 * chain have different index keys.
1703 *
1704 * We now take a new snapshot, and build the index using all tuples that
1705 * are visible in this snapshot. We can be sure that any HOT updates to
1706 * these tuples will be compatible with the index, since any updates made
1707 * by transactions that didn't know about the index are now committed or
1708 * rolled back. Thus, each visible tuple is either the end of its
1709 * HOT-chain or the extension of the chain is HOT-safe for this index.
1710 */
1711
1712 /* Set ActiveSnapshot since functions in the indexes may need it */
1714
1715 /* Perform concurrent build of index */
1717
1718 /* we can do away with our snapshot */
1720
1721 /*
1722 * Commit this transaction to make the indisready update visible.
1723 */
1726
1727 /* Tell concurrent index builds to ignore us, if index qualifies */
1728 if (safe_index)
1730
1731 /*
1732 * Phase 3 of concurrent index build
1733 *
1734 * We once again wait until no transaction can have the table open with
1735 * the index marked as read-only for updates.
1736 */
1740
1741 /*
1742 * Now take the "reference snapshot" that will be used by validate_index()
1743 * to filter candidate tuples. Beware! There might still be snapshots in
1744 * use that treat some transaction as in-progress that our reference
1745 * snapshot treats as committed. If such a recently-committed transaction
1746 * deleted tuples in the table, we will not include them in the index; yet
1747 * those transactions which see the deleting one as still-in-progress will
1748 * expect such tuples to be there once we mark the index as valid.
1749 *
1750 * We solve this by waiting for all endangered transactions to exit before
1751 * we mark the index as valid.
1752 *
1753 * We also set ActiveSnapshot to this snap, since functions in indexes may
1754 * need a snapshot.
1755 */
1757 PushActiveSnapshot(snapshot);
1758
1759 /*
1760 * Scan the index and the heap, insert any missing index entries.
1761 */
1763
1764 /*
1765 * Drop the reference snapshot. We must do this before waiting out other
1766 * snapshot holders, else we will deadlock against other processes also
1767 * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
1768 * they must wait for. But first, save the snapshot's xmin to use as
1769 * limitXmin for GetCurrentVirtualXIDs().
1770 */
1771 limitXmin = snapshot->xmin;
1772
1774 UnregisterSnapshot(snapshot);
1775
1776 /*
1777 * The snapshot subsystem could still contain registered snapshots that
1778 * are holding back our process's advertised xmin; in particular, if
1779 * default_transaction_isolation = serializable, there is a transaction
1780 * snapshot that is still active. The CatalogSnapshot is likewise a
1781 * hazard. To ensure no deadlocks, we must commit and start yet another
1782 * transaction, and do our wait before any snapshot has been taken in it.
1783 */
1786
1787 /* Tell concurrent index builds to ignore us, if index qualifies */
1788 if (safe_index)
1790
1791 /* We should now definitely not be advertising any xmin. */
1793
1794 /*
1795 * The index is now valid in the sense that it contains all currently
1796 * interesting tuples. But since it might not contain tuples deleted just
1797 * before the reference snap was taken, we have to wait out any
1798 * transactions that might have older snapshots.
1799 */
1800 INJECTION_POINT("define-index-before-set-valid", NULL);
1804
1805 /*
1806 * Updating pg_index might involve TOAST table access, so ensure we have a
1807 * valid snapshot.
1808 */
1810
1811 /*
1812 * Index can now be marked valid -- update its pg_index entry
1813 */
1815
1817
1818 /*
1819 * The pg_index update will cause backends (including this one) to update
1820 * relcache entries for the index itself, but we should also send a
1821 * relcache inval on the parent table to force replanning of cached plans.
1822 * Otherwise existing sessions might fail to use the new index where it
1823 * would be useful. (Note that our earlier commits did not create reasons
1824 * to replan; so relcache flush on the index itself was sufficient.)
1825 */
1827
1828 /*
1829 * Last thing to do is release the session-level lock on the parent table.
1830 */
1832
1834
1835 return address;
1836}
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
uint16 bits16
Definition c.h:554
uint32 TransactionId
Definition c.h:666
@ COMPARE_EQ
Definition cmptype.h:36
int errmsg_internal(const char *fmt,...)
Definition elog.c:1170
int errdetail(const char *fmt,...)
Definition elog.c:1216
#define DEBUG1
Definition elog.h:30
Oid MyDatabaseTableSpace
Definition globals.c:96
int NewGUCNestLevel(void)
Definition guc.c:2110
void RestrictSearchPath(void)
Definition guc.c:2121
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition guc.c:2137
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:3216
@ GUC_ACTION_SAVE
Definition guc.h:205
@ PGC_S_SESSION
Definition guc.h:126
@ PGC_USERSET
Definition guc.h:79
HeapTuple heap_copytuple(HeapTuple tuple)
Definition heaptuple.c:778
void validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
Definition index.c:3348
Oid index_create(Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, RelFileNumber relFileNumber, IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, Oid tableSpaceId, const Oid *collationIds, const Oid *opclassIds, const Datum *opclassOptions, const int16 *coloptions, const NullableDatum *stattargets, Datum reloptions, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
Definition index.c:724
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition index.c:3501
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:2535
IndexInfo * BuildIndexInfo(Relation index)
Definition index.c:2426
void index_check_primary_key(Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
Definition index.c:202
void index_concurrently_build(Oid heapRelationId, Oid indexRelationId)
Definition index.c:1483
#define INDEX_CREATE_IS_PRIMARY
Definition index.h:61
#define INDEX_CREATE_IF_NOT_EXISTS
Definition index.h:65
#define INDEX_CREATE_PARTITIONED
Definition index.h:66
#define INDEX_CREATE_INVALID
Definition index.h:67
#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS
Definition index.h:96
#define INDEX_CREATE_ADD_CONSTRAINT
Definition index.h:62
#define INDEX_CREATE_SKIP_BUILD
Definition index.h:63
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition index.h:92
@ INDEX_CREATE_SET_VALID
Definition index.h:27
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition index.h:93
#define INDEX_CREATE_CONCURRENT
Definition index.h:64
static void set_indexsafe_procflags(void)
Definition indexcmds.c:4640
ObjectAddress DefineIndex(ParseState *pstate, Oid tableId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition indexcmds.c:544
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition indexcmds.c:4470
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition indexcmds.c:435
static void CheckPredicate(Expr *predicate)
Definition indexcmds.c:1851
static List * ChooseIndexColumnNames(const List *indexElems)
Definition indexcmds.c:2788
static char * ChooseIndexName(const char *tabname, Oid namespaceId, const List *colnames, const List *exclusionOpNames, bool primary, bool isconstraint)
Definition indexcmds.c:2699
#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
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition lock.h:183
int LOCKMODE
Definition lockdefs.h:26
#define ShareLock
Definition lockdefs.h:40
char get_rel_persistence(Oid relid)
Definition lsyscache.c:2228
bool get_index_isvalid(Oid index_oid)
Definition lsyscache.c:3728
Oid get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype, CompareType cmptype)
Definition lsyscache.c:197
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition lsyscache.c:1337
char * get_opname(Oid opno)
Definition lsyscache.c:1460
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition lsyscache.c:168
char * get_opfamily_name(Oid opfid, bool missing_ok)
Definition lsyscache.c:1403
Oid get_opfamily_method(Oid opfid)
Definition lsyscache.c:1386
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:612
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition miscinit.c:619
IndexStmt * generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, const AttrMap *attmap, Oid *constraintOid)
@ PARTITION_STRATEGY_HASH
Definition parsenodes.h:903
@ 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:109
#define PROGRESS_CREATEIDX_PHASE_WAIT_1
Definition progress.h:113
#define PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY
Definition progress.h:131
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition progress.h:103
#define PROGRESS_CREATEIDX_PHASE_WAIT_3
Definition progress.h:119
#define PROGRESS_CREATEIDX_COMMAND_CREATE
Definition progress.h:130
#define PROGRESS_CREATEIDX_PHASE_WAIT_2
Definition progress.h:115
#define PROGRESS_CREATEIDX_PHASE
Definition progress.h:104
#define PROGRESS_CREATEIDX_INDEX_OID
Definition progress.h:102
#define PROGRESS_CREATEIDX_PARTITIONS_TOTAL
Definition progress.h:108
#define PROGRESS_CREATEIDX_COMMAND
Definition progress.h:101
#define RELATION_IS_OTHER_TEMP(relation)
Definition rel.h:667
List * RelationGetIndexList(Relation relation)
Definition relcache.c:4831
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:67
#define HTEqualStrategyNumber
Definition stratnum.h:41
int ii_NumIndexAttrs
Definition execnodes.h:169
int ii_NumIndexKeyAttrs
Definition execnodes.h:171
List * ii_Expressions
Definition execnodes.h:180
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition execnodes.h:177
List * ii_Predicate
Definition execnodes.h:185
LockRelId lockRelId
Definition rel.h:46
Oid relId
Definition rel.h:40
Oid dbId
Definition rel.h:41
TransactionId xmin
Definition proc.h:194
LockInfoData rd_lockInfo
Definition rel.h:114
TransactionId xmin
Definition snapshot.h:153
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition tablecmds.c:4414
#define InvalidTransactionId
Definition transam.h:31
void StartTransactionCommand(void)
Definition xact.c:3080
void CommitTransactionCommand(void)
Definition xact.c:3178

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, 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 */
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
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(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:1435
#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:100
#define OPCLASS_ITEM_STORAGETYPE
#define OPCLASS_ITEM_OPERATOR
#define OPCLASS_ITEM_FUNCTION
FormData_pg_opclass * Form_pg_opclass
Definition pg_opclass.h:83
FormData_pg_opfamily * Form_pg_opfamily
Definition pg_opfamily.h:51
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(int cacheId, Datum key1, Datum key2, Datum key3)
Definition syscache.c:240
#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(), 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:1805
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:2786
Oid get_ts_config_oid(List *names, bool missing_ok)
Definition namespace.c:3222
FormData_pg_ts_config_map * Form_pg_ts_config_map
FormData_pg_ts_config_map
static Datum Int32GetDatum(int32 X)
Definition postgres.h:222
Datum * tts_values
Definition tuptable.h:124
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:457

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, BTEqualStrategyNumber, CatalogCloseIndexes(), CatalogOpenIndexes(), CatalogTupleInsert(), CatalogTuplesMultiInsertWithInfo(), defGetQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecStoreVirtualTuple(), fb(), 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:3077
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:706
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:214

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

2850{
2851 ReindexParams params = {0};
2852 ListCell *lc;
2853 bool concurrently = false;
2854 bool verbose = false;
2855 char *tablespacename = NULL;
2856
2857 /* Parse option list */
2858 foreach(lc, stmt->params)
2859 {
2860 DefElem *opt = (DefElem *) lfirst(lc);
2861
2862 if (strcmp(opt->defname, "verbose") == 0)
2863 verbose = defGetBoolean(opt);
2864 else if (strcmp(opt->defname, "concurrently") == 0)
2866 else if (strcmp(opt->defname, "tablespace") == 0)
2867 tablespacename = defGetString(opt);
2868 else
2869 ereport(ERROR,
2871 errmsg("unrecognized %s option \"%s\"",
2872 "REINDEX", opt->defname),
2873 parser_errposition(pstate, opt->location)));
2874 }
2875
2876 if (concurrently)
2878 "REINDEX CONCURRENTLY");
2879
2880 params.options =
2881 (verbose ? REINDEXOPT_VERBOSE : 0) |
2883
2884 /*
2885 * Assign the tablespace OID to move indexes to, with InvalidOid to do
2886 * nothing.
2887 */
2888 if (tablespacename != NULL)
2889 {
2890 params.tablespaceOid = get_tablespace_oid(tablespacename, false);
2891
2892 /* Check permissions except when moving to database's default */
2893 if (OidIsValid(params.tablespaceOid) &&
2895 {
2897
2900 if (aclresult != ACLCHECK_OK)
2903 }
2904 }
2905 else
2906 params.tablespaceOid = InvalidOid;
2907
2908 switch (stmt->kind)
2909 {
2911 ReindexIndex(stmt, &params, isTopLevel);
2912 break;
2914 ReindexTable(stmt, &params, isTopLevel);
2915 break;
2919
2920 /*
2921 * This cannot run inside a user transaction block; if we were
2922 * inside a transaction, then its commit- and
2923 * start-transaction-command calls would not have the intended
2924 * effect!
2925 */
2927 (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
2928 (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
2929 "REINDEX DATABASE");
2930 ReindexMultipleTables(stmt, &params);
2931 break;
2932 default:
2933 elog(ERROR, "unrecognized object type: %d",
2934 (int) stmt->kind);
2935 break;
2936 }
2937}
#define REINDEXOPT_CONCURRENTLY
Definition index.h:44
#define REINDEXOPT_VERBOSE
Definition index.h:41
static void ReindexIndex(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition indexcmds.c:2944
static void ReindexMultipleTables(const ReindexStmt *stmt, const ReindexParams *params)
Definition indexcmds.c:3133
static Oid ReindexTable(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition indexcmds.c:3074
@ REINDEX_OBJECT_DATABASE
@ REINDEX_OBJECT_INDEX
@ REINDEX_OBJECT_SCHEMA
@ REINDEX_OBJECT_SYSTEM
@ REINDEX_OBJECT_TABLE
static int verbose
ParseLoc location
Definition parsenodes.h:848
Oid tablespaceOid
Definition index.h:36
bits32 options
Definition index.h:35
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition xact.c:3669

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

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

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

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

References ACL_USAGE, aclcheck_error(), ACLCHECK_NO_PRIV, ACLCHECK_OK, arg, elog, ereport, errcode(), errhint(), errmsg(), ERROR, errorConflictingDefElem(), extension_file_exists(), fb(), 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(), 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(), 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 2039 of file functioncmds.c.

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

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

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

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

◆ GetOperatorFromCompareType()

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

Definition at line 2470 of file indexcmds.c.

2472{
2473 Oid amid;
2474 Oid opfamily;
2475 Oid opcintype;
2476
2477 Assert(cmptype == COMPARE_EQ || cmptype == COMPARE_OVERLAP || cmptype == COMPARE_CONTAINED_BY);
2478
2479 /*
2480 * Use the opclass to get the opfamily, opcintype, and access method. If
2481 * any of this fails, quit early.
2482 */
2483 if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
2484 elog(ERROR, "cache lookup failed for opclass %u", opclass);
2485
2486 amid = get_opclass_method(opclass);
2487
2488 /*
2489 * Ask the index AM to translate to its internal stratnum
2490 */
2491 *strat = IndexAmTranslateCompareType(cmptype, amid, opfamily, true);
2492 if (*strat == InvalidStrategy)
2493 ereport(ERROR,
2495 cmptype == COMPARE_EQ ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2496 cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2497 cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2498 errdetail("Could not translate compare type %d for operator family \"%s\" of access method \"%s\".",
2499 cmptype, get_opfamily_name(opfamily, false), get_am_name(amid)));
2500
2501 /*
2502 * We parameterize rhstype so foreign keys can ask for a <@ operator whose
2503 * rhs matches the aggregate function. For example range_agg returns
2504 * anymultirange.
2505 */
2506 if (!OidIsValid(rhstype))
2507 rhstype = opcintype;
2508 *opid = get_opfamily_member(opfamily, opcintype, rhstype, *strat);
2509
2510 if (!OidIsValid(*opid))
2511 ereport(ERROR,
2513 cmptype == COMPARE_EQ ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2514 cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2515 cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2516 errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
2517 get_opfamily_name(opfamily, false), get_am_name(amid)));
2518}
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:1362
#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(), and FindFKPeriodOpers().

◆ ImportForeignSchema()

void ImportForeignSchema ( ImportForeignSchemaStmt stmt)
extern

Definition at line 1495 of file foreigncmds.c.

1496{
1497 ForeignServer *server;
1501 List *cmd_list;
1502 ListCell *lc;
1503
1504 /* Check that the foreign server exists and that we have USAGE on it */
1505 server = GetForeignServerByName(stmt->server_name, false);
1507 if (aclresult != ACLCHECK_OK)
1509
1510 /* Check that the schema exists and we have CREATE permissions on it */
1511 (void) LookupCreationNamespace(stmt->local_schema);
1512
1513 /* Get the FDW and check it supports IMPORT */
1514 fdw = GetForeignDataWrapper(server->fdwid);
1515 if (!OidIsValid(fdw->fdwhandler))
1516 ereport(ERROR,
1518 errmsg("foreign-data wrapper \"%s\" has no handler",
1519 fdw->fdwname)));
1520 fdw_routine = GetFdwRoutine(fdw->fdwhandler);
1521 if (fdw_routine->ImportForeignSchema == NULL)
1522 ereport(ERROR,
1524 errmsg("foreign-data wrapper \"%s\" does not support IMPORT FOREIGN SCHEMA",
1525 fdw->fdwname)));
1526
1527 /* Call FDW to get a list of commands */
1528 cmd_list = fdw_routine->ImportForeignSchema(stmt, server->serverid);
1529
1530 /* Parse and execute each command */
1531 foreach(lc, cmd_list)
1532 {
1533 char *cmd = (char *) lfirst(lc);
1534 import_error_callback_arg callback_arg;
1537 ListCell *lc2;
1538
1539 /*
1540 * Setup error traceback support for ereport(). This is so that any
1541 * error in the generated SQL will be displayed nicely.
1542 */
1543 callback_arg.tablename = NULL; /* not known yet */
1544 callback_arg.cmd = cmd;
1546 sqlerrcontext.arg = &callback_arg;
1549
1550 /*
1551 * Parse the SQL string into a list of raw parse trees.
1552 */
1554
1555 /*
1556 * Process each parse tree (we allow the FDW to put more than one
1557 * command per string, though this isn't really advised).
1558 */
1559 foreach(lc2, raw_parsetree_list)
1560 {
1563 PlannedStmt *pstmt;
1564
1565 /*
1566 * Because we only allow CreateForeignTableStmt, we can skip parse
1567 * analysis, rewrite, and planning steps here.
1568 */
1570 elog(ERROR,
1571 "foreign-data wrapper \"%s\" returned incorrect statement type %d",
1572 fdw->fdwname, (int) nodeTag(cstmt));
1573
1574 /* Ignore commands for tables excluded by filter options */
1575 if (!IsImportableForeignTable(cstmt->base.relation->relname, stmt))
1576 continue;
1577
1578 /* Enable reporting of current table's name on error */
1579 callback_arg.tablename = cstmt->base.relation->relname;
1580
1581 /* Ensure creation schema is the one given in IMPORT statement */
1582 cstmt->base.relation->schemaname = pstrdup(stmt->local_schema);
1583
1584 /* No planning needed, just make a wrapper PlannedStmt */
1585 pstmt = makeNode(PlannedStmt);
1586 pstmt->commandType = CMD_UTILITY;
1587 pstmt->canSetTag = false;
1588 pstmt->utilityStmt = (Node *) cstmt;
1589 pstmt->stmt_location = rs->stmt_location;
1590 pstmt->stmt_len = rs->stmt_len;
1592
1593 /* Execute statement */
1594 ProcessUtility(pstmt, cmd, false,
1597
1598 /* Be sure to advance the command counter between subcommands */
1600
1601 callback_arg.tablename = NULL;
1602 }
1603
1605 }
1606}
DestReceiver * None_Receiver
Definition dest.c:96
ErrorContextCallback * error_context_stack
Definition elog.c:95
bool IsImportableForeignTable(const char *tablename, ImportForeignSchemaStmt *stmt)
Definition foreign.c:483
FdwRoutine * GetFdwRoutine(Oid fdwhandler)
Definition foreign.c:326
static void import_error_callback(void *arg)
Oid LookupCreationNamespace(const char *nspname)
Definition namespace.c:3498
@ CMD_UTILITY
Definition nodes.h:280
@ PLAN_STMT_INTERNAL
Definition plannodes.h:40
List * pg_parse_query(const char *query_string)
Definition postgres.c:604
struct ErrorContextCallback * previous
Definition elog.h:297
bool canSetTag
Definition plannodes.h:86
ParseLoc stmt_len
Definition plannodes.h:165
PlannedStmtOrigin planOrigin
Definition plannodes.h:77
ParseLoc stmt_location
Definition plannodes.h:163
CmdType commandType
Definition plannodes.h:68
Node * utilityStmt
Definition plannodes.h:150
Node * stmt
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition utility.c:501
@ 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 185 of file functioncmds.c.

198{
199 int parameterCount = list_length(parameters);
200 Oid *inTypes;
201 int inCount = 0;
205 int outCount = 0;
206 int varCount = 0;
207 bool have_names = false;
208 bool have_defaults = false;
209 ListCell *x;
210 int i;
211
212 *variadicArgType = InvalidOid; /* default result */
213 *requiredResultType = InvalidOid; /* default result */
214
215 inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
216 allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
217 paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
220
221 /* Scan the list and extract data into work arrays */
222 i = 0;
223 foreach(x, parameters)
224 {
226 TypeName *t = fp->argType;
228 bool isinput = false;
229 Oid toid;
230 Type typtup;
232
233 /* For our purposes here, a defaulted mode spec is identical to IN */
236
237 typtup = LookupTypeName(pstate, t, NULL, false);
238 if (typtup)
239 {
241 {
242 /* As above, hard error if language is SQL */
246 errmsg("SQL function cannot accept shell type %s",
248 parser_errposition(pstate, t->location)));
249 /* We don't allow creating aggregates on shell types either */
250 else if (objtype == OBJECT_AGGREGATE)
253 errmsg("aggregate cannot accept shell type %s",
255 parser_errposition(pstate, t->location)));
256 else
259 errmsg("argument type %s is only a shell",
261 parser_errposition(pstate, t->location)));
262 }
265 }
266 else
267 {
270 errmsg("type %s does not exist",
272 parser_errposition(pstate, t->location)));
273 toid = InvalidOid; /* keep compiler quiet */
274 }
275
277 if (aclresult != ACLCHECK_OK)
279
280 if (t->setof)
281 {
282 if (objtype == OBJECT_AGGREGATE)
285 errmsg("aggregates cannot accept set arguments"),
286 parser_errposition(pstate, fp->location)));
287 else if (objtype == OBJECT_PROCEDURE)
290 errmsg("procedures cannot accept set arguments"),
291 parser_errposition(pstate, fp->location)));
292 else
295 errmsg("functions cannot accept set arguments"),
296 parser_errposition(pstate, fp->location)));
297 }
298
299 /* handle input parameters */
301 {
302 /* other input parameters can't follow a VARIADIC parameter */
303 if (varCount > 0)
306 errmsg("VARIADIC parameter must be the last input parameter"),
307 parser_errposition(pstate, fp->location)));
308 inTypes[inCount++] = toid;
309 isinput = true;
312 }
313
314 /* handle output parameters */
316 {
317 if (objtype == OBJECT_PROCEDURE)
318 {
319 /*
320 * We disallow OUT-after-VARIADIC only for procedures. While
321 * such a case causes no confusion in ordinary function calls,
322 * it would cause confusion in a CALL statement.
323 */
324 if (varCount > 0)
327 errmsg("VARIADIC parameter must be the last parameter"),
328 parser_errposition(pstate, fp->location)));
329 /* Procedures with output parameters always return RECORD */
331 }
332 else if (outCount == 0) /* save first output param's type */
334 outCount++;
335 }
336
338 {
340 varCount++;
341 /* validate variadic parameter type */
342 switch (toid)
343 {
344 case ANYARRAYOID:
346 case ANYOID:
347 /* okay */
348 break;
349 default:
353 errmsg("VARIADIC parameter must be an array"),
354 parser_errposition(pstate, fp->location)));
355 break;
356 }
357 }
358
360
362
363 if (fp->name && fp->name[0])
364 {
365 ListCell *px;
366
367 /*
368 * As of Postgres 9.0 we disallow using the same name for two
369 * input or two output function parameters. Depending on the
370 * function's language, conflicting input and output names might
371 * be bad too, but we leave it to the PL to complain if so.
372 */
373 foreach(px, parameters)
374 {
377
378 if (prevfp == fp)
379 break;
380 /* as above, default mode is IN */
384 /* pure in doesn't conflict with pure out */
385 if ((fpmode == FUNC_PARAM_IN ||
389 continue;
390 if ((prevfpmode == FUNC_PARAM_IN ||
394 continue;
395 if (prevfp->name && prevfp->name[0] &&
396 strcmp(prevfp->name, fp->name) == 0)
399 errmsg("parameter name \"%s\" used more than once",
400 fp->name),
401 parser_errposition(pstate, fp->location)));
402 }
403
405 have_names = true;
406 }
407
410
411 if (fp->defexpr)
412 {
413 Node *def;
414
415 if (!isinput)
418 errmsg("only input parameters can have default values"),
419 parser_errposition(pstate, fp->location)));
420
421 def = transformExpr(pstate, fp->defexpr,
423 def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
424 assign_expr_collations(pstate, def);
425
426 /*
427 * Make sure no variables are referred to (this is probably dead
428 * code now that add_missing_from is history).
429 */
430 if (pstate->p_rtable != NIL ||
434 errmsg("cannot use table references in parameter default value"),
435 parser_errposition(pstate, fp->location)));
436
437 /*
438 * transformExpr() should have already rejected subqueries,
439 * aggregates, and window functions, based on the EXPR_KIND_ for a
440 * default expression.
441 *
442 * It can't return a set either --- but coerce_to_specific_type
443 * already checked that for us.
444 *
445 * Note: the point of these restrictions is to ensure that an
446 * expression that, on its face, hasn't got subplans, aggregates,
447 * etc cannot suddenly have them after function default arguments
448 * are inserted.
449 */
450
452 have_defaults = true;
453 }
454 else
455 {
456 if (isinput && have_defaults)
459 errmsg("input parameters after one with a default value must also have defaults"),
460 parser_errposition(pstate, fp->location)));
461
462 /*
463 * For procedures, we also can't allow OUT parameters after one
464 * with a default, because the same sort of confusion arises in a
465 * CALL statement.
466 */
467 if (objtype == OBJECT_PROCEDURE && have_defaults)
470 errmsg("procedure OUT parameters cannot appear after one with a default value"),
471 parser_errposition(pstate, fp->location)));
472 }
473
474 i++;
475 }
476
477 /* Now construct the proper outputs as needed */
478 *parameterTypes = buildoidvector(inTypes, inCount);
479
480 if (outCount > 0 || varCount > 0)
481 {
484 if (outCount > 1)
486 /* otherwise we set requiredResultType correctly above */
487 }
488 else
489 {
492 }
493
494 if (have_names)
495 {
496 for (i = 0; i < parameterCount; i++)
497 {
500 }
502 }
503 else
505}
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:120
@ EXPR_KIND_FUNCTION_DEFAULT
Definition parse_node.h:71
Type LookupTypeName(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, bool missing_ok)
Definition parse_type.c:38
Oid typeTypeId(Type tp)
Definition parse_type.c:590
FunctionParameterMode
@ FUNC_PARAM_IN
@ FUNC_PARAM_DEFAULT
@ FUNC_PARAM_OUT
@ FUNC_PARAM_TABLE
@ FUNC_PARAM_VARIADIC
FormData_pg_type * Form_pg_type
Definition pg_type.h:261
TypeName * argType
FunctionParameterMode mode
List * p_rtable
Definition parse_node.h:196
bool setof
Definition parsenodes.h:287
ParseLoc location
Definition parsenodes.h:292
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(), 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 2063 of file functioncmds.c.

2065{
2066 /* check for duplicate name (more friendly than unique-index failure) */
2071 ereport(ERROR,
2073 errmsg("function %s already exists in schema \"%s\"",
2075 NIL, proargtypes->values),
2077}
const char * funcname_signature_string(const char *funcname, int nargs, List *argnames, const Oid *argtypes)
int16 pronargs
Definition pg_proc.h:81
NameData proname
Definition pg_proc.h:35

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

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

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

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

References CatalogTupleDelete(), elog, ERROR, fb(), 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:383
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:1968
bool isTempNamespace(Oid namespaceId)
Definition namespace.c:3719
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:137
#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 413 of file operatorcmds.c.

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

References CatalogTupleDelete(), elog, ERROR, fb(), 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 787 of file statscmds.c.

788{
789 Relation relation;
790 Relation rel;
793 Oid relid;
794
795 /*
796 * Delete the pg_statistic_ext tuple. Also send out a cache inval on the
797 * associated table, so that dependent plans will be rebuilt.
798 */
800
802
803 if (!HeapTupleIsValid(tup)) /* should not happen */
804 elog(ERROR, "cache lookup failed for statistics object %u", statsOid);
805
807 relid = statext->stxrelid;
808
809 /*
810 * Delete the pg_statistic_ext_data tuples holding the actual statistical
811 * data. There might be data with/without inheritance, so attempt deleting
812 * both. We lock the user table first, to prevent other processes (e.g.
813 * DROP STATISTICS) from removing the row concurrently.
814 */
816
819
821
822 CatalogTupleDelete(relation, &tup->t_self);
823
825
826 /* Keep lock until the end of the transaction. */
827 table_close(rel, NoLock);
828
829 table_close(relation, RowExclusiveLock);
830}
FormData_pg_statistic_ext * Form_pg_statistic_ext
void RemoveStatisticsDataById(Oid statsOid, bool inh)
Definition statscmds.c:762

References CacheInvalidateRelcacheByRelid(), CatalogTupleDelete(), elog, ERROR, fb(), 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 762 of file statscmds.c.

763{
764 Relation relation;
766
768
770 BoolGetDatum(inh));
771
772 /* We don't know if the data row for inh value exists. */
774 {
775 CatalogTupleDelete(relation, &tup->t_self);
776
778 }
779
780 table_close(relation, RowExclusiveLock);
781}

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 1335 of file foreigncmds.c.

1336{
1337 ObjectAddress object;
1338 Oid useId;
1339 Oid umId;
1341 RoleSpec *role = (RoleSpec *) stmt->user;
1342
1343 if (role->roletype == ROLESPEC_PUBLIC)
1345 else
1346 {
1347 useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
1348 if (!OidIsValid(useId))
1349 {
1350 /*
1351 * IF EXISTS specified, role not found and not public. Notice this
1352 * and leave.
1353 */
1354 elog(NOTICE, "role \"%s\" does not exist, skipping",
1355 role->rolename);
1356 return InvalidOid;
1357 }
1358 }
1359
1360 srv = GetForeignServerByName(stmt->servername, true);
1361
1362 if (!srv)
1363 {
1364 if (!stmt->missing_ok)
1365 ereport(ERROR,
1367 errmsg("server \"%s\" does not exist",
1368 stmt->servername)));
1369 /* IF EXISTS, just note it */
1371 (errmsg("server \"%s\" does not exist, skipping",
1372 stmt->servername)));
1373 return InvalidOid;
1374 }
1375
1378 ObjectIdGetDatum(srv->serverid));
1379
1380 if (!OidIsValid(umId))
1381 {
1382 if (!stmt->missing_ok)
1383 ereport(ERROR,
1385 errmsg("user mapping for \"%s\" does not exist for server \"%s\"",
1386 MappingUserName(useId), stmt->servername)));
1387
1388 /* IF EXISTS specified, just note it */
1390 (errmsg("user mapping for \"%s\" does not exist for server \"%s\", skipping",
1391 MappingUserName(useId), stmt->servername)));
1392 return InvalidOid;
1393 }
1394
1395 user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);
1396
1397 /*
1398 * Do the deletion
1399 */
1400 object.classId = UserMappingRelationId;
1401 object.objectId = umId;
1402 object.objectSubId = 0;
1403
1404 performDeletion(&object, DROP_CASCADE, 0);
1405
1406 return umId;
1407}
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition dependency.c:274
@ 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 2283 of file indexcmds.c.

2285{
2286 char *schemaname;
2287 char *opcname;
2288 HeapTuple tuple;
2290 Oid opClassId,
2292
2293 if (opclass == NIL)
2294 {
2295 /* no operator class specified, so find the default */
2297 if (!OidIsValid(opClassId))
2298 ereport(ERROR,
2300 errmsg("data type %s has no default operator class for access method \"%s\"",
2302 errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
2303 return opClassId;
2304 }
2305
2306 /*
2307 * Specific opclass name given, so look up the opclass.
2308 */
2309
2310 /* deconstruct the name list */
2311 DeconstructQualifiedName(opclass, &schemaname, &opcname);
2312
2313 if (schemaname)
2314 {
2315 /* Look in specific schema only */
2317
2318 namespaceId = LookupExplicitNamespace(schemaname, false);
2323 }
2324 else
2325 {
2326 /* Unqualified opclass name, so search the search path */
2328 if (!OidIsValid(opClassId))
2329 ereport(ERROR,
2331 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2334 }
2335
2336 if (!HeapTupleIsValid(tuple))
2337 ereport(ERROR,
2339 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2341
2342 /*
2343 * Verify that the index operator class accepts this datatype. Note we
2344 * will accept binary compatibility.
2345 */
2346 opform = (Form_pg_opclass) GETSTRUCT(tuple);
2347 opClassId = opform->oid;
2348 opInputType = opform->opcintype;
2349
2351 ereport(ERROR,
2353 errmsg("operator class \"%s\" does not accept data type %s",
2355
2356 ReleaseSysCache(tuple);
2357
2358 return opClassId;
2359}
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition indexcmds.c:2368
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition namespace.c:2188
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition namespace.c:3455

References DeconstructQualifiedName(), ereport, errcode(), errhint(), errmsg(), ERROR, fb(), 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:1155
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition c.h:1152
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:343
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:193

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

939{
940 HeapTuple tuple;
942 Oid result;
943
945 if (!HeapTupleIsValid(tuple))
946 {
947 if (missing_ok)
948 return InvalidOid;
949 elog(ERROR, "cache lookup failed for statistics object %u", statId);
950 }
952 Assert(stx->oid == statId);
953
954 result = stx->stxrelid;
955 ReleaseSysCache(tuple);
956 return result;
957}

References Assert, elog, ERROR, fb(), 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:834
@ DEFELEM_DROP
Definition parsenodes.h:837
@ DEFELEM_SET
Definition parsenodes.h:835
@ DEFELEM_ADD
Definition parsenodes.h:836
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().