#include "nodes/parsenodes.h"

Go to the source code of this file.
| Oid AlterForeignDataWrapper | ( | AlterFdwStmt * | stmt | ) |
Definition at line 620 of file foreigncmds.c.
References Anum_pg_foreign_data_wrapper_fdwhandler, Anum_pg_foreign_data_wrapper_fdwoptions, Anum_pg_foreign_data_wrapper_fdwvalidator, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetDatum, DatumGetPointer, deleteDependencyRecordsForClass(), DEPENDENCY_NORMAL, ereport, errcode(), errhint(), errmsg(), ERROR, AlterFdwStmt::fdwname, FOREIGNDATAWRAPPERNAME, FOREIGNDATAWRAPPEROID, ForeignDataWrapperRelationId, AlterFdwStmt::func_options, GETSTRUCT, heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, AlterFdwStmt::options, parse_func_options(), PointerGetDatum, PointerIsValid, ProcedureRelationId, recordDependencyOn(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), superuser(), SysCacheGetAttr(), HeapTupleData::t_self, transformGenericOptions(), and WARNING.
Referenced by ProcessUtilitySlow().
{
Relation rel;
HeapTuple tp;
Form_pg_foreign_data_wrapper fdwForm;
Datum repl_val[Natts_pg_foreign_data_wrapper];
bool repl_null[Natts_pg_foreign_data_wrapper];
bool repl_repl[Natts_pg_foreign_data_wrapper];
Oid fdwId;
bool isnull;
Datum datum;
bool handler_given;
bool validator_given;
Oid fdwhandler;
Oid fdwvalidator;
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
/* Must be super user */
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to alter foreign-data wrapper \"%s\"",
stmt->fdwname),
errhint("Must be superuser to alter a foreign-data wrapper.")));
tp = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME,
CStringGetDatum(stmt->fdwname));
if (!HeapTupleIsValid(tp))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));
fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
fdwId = HeapTupleGetOid(tp);
memset(repl_val, 0, sizeof(repl_val));
memset(repl_null, false, sizeof(repl_null));
memset(repl_repl, false, sizeof(repl_repl));
parse_func_options(stmt->func_options,
&handler_given, &fdwhandler,
&validator_given, &fdwvalidator);
if (handler_given)
{
repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true;
/*
* It could be that the behavior of accessing foreign table changes
* with the new handler. Warn about this.
*/
ereport(WARNING,
(errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables")));
}
if (validator_given)
{
repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true;
/*
* It could be that the options for the FDW, SERVER and USER MAPPING
* are no longer valid with the new validator. Warn about this.
*/
if (OidIsValid(fdwvalidator))
ereport(WARNING,
(errmsg("changing the foreign-data wrapper validator can cause "
"the options for dependent objects to become invalid")));
}
else
{
/*
* Validator is not changed, but we need it for validating options.
*/
fdwvalidator = fdwForm->fdwvalidator;
}
/*
* If options specified, validate and update.
*/
if (stmt->options)
{
/* Extract the current options */
datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
tp,
Anum_pg_foreign_data_wrapper_fdwoptions,
&isnull);
if (isnull)
datum = PointerGetDatum(NULL);
/* Transform the options */
datum = transformGenericOptions(ForeignDataWrapperRelationId,
datum,
stmt->options,
fdwvalidator);
if (PointerIsValid(DatumGetPointer(datum)))
repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
else
repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
}
/* Everything looks good - update the tuple */
tp = heap_modify_tuple(tp, RelationGetDescr(rel),
repl_val, repl_null, repl_repl);
simple_heap_update(rel, &tp->t_self, tp);
CatalogUpdateIndexes(rel, tp);
heap_freetuple(tp);
/* Update function dependencies if we changed them */
if (handler_given || validator_given)
{
ObjectAddress myself;
ObjectAddress referenced;
/*
* Flush all existing dependency records of this FDW on functions; we
* assume there can be none other than the ones we are fixing.
*/
deleteDependencyRecordsForClass(ForeignDataWrapperRelationId,
fdwId,
ProcedureRelationId,
DEPENDENCY_NORMAL);
/* And build new ones. */
myself.classId = ForeignDataWrapperRelationId;
myself.objectId = fdwId;
myself.objectSubId = 0;
if (OidIsValid(fdwhandler))
{
referenced.classId = ProcedureRelationId;
referenced.objectId = fdwhandler;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
if (OidIsValid(fdwvalidator))
{
referenced.classId = ProcedureRelationId;
referenced.objectId = fdwvalidator;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
}
InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);
heap_close(rel, RowExclusiveLock);
return fdwId;
}
Definition at line 255 of file foreigncmds.c.
References AlterForeignDataWrapperOwner_internal(), CStringGetDatum, ereport, errcode(), errmsg(), ERROR, FOREIGNDATAWRAPPERNAME, ForeignDataWrapperRelationId, heap_close, heap_freetuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, RowExclusiveLock, and SearchSysCacheCopy1.
Referenced by ExecAlterOwnerStmt().
{
Oid fdwId;
HeapTuple tup;
Relation rel;
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(name));
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("foreign-data wrapper \"%s\" does not exist", name)));
fdwId = HeapTupleGetOid(tup);
AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);
return fdwId;
}
Definition at line 287 of file foreigncmds.c.
References AlterForeignDataWrapperOwner_internal(), ereport, errcode(), errmsg(), ERROR, FOREIGNDATAWRAPPEROID, ForeignDataWrapperRelationId, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, ObjectIdGetDatum, RowExclusiveLock, and SearchSysCacheCopy1.
Referenced by shdepReassignOwned().
{
HeapTuple tup;
Relation rel;
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fwdId));
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("foreign-data wrapper with OID %u does not exist", fwdId)));
AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);
}
| Oid AlterForeignServer | ( | AlterForeignServerStmt * | stmt | ) |
Definition at line 922 of file foreigncmds.c.
References ACL_KIND_FOREIGN_SERVER, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_foreign_server_srvoptions, Anum_pg_foreign_server_srvversion, CatalogUpdateIndexes(), CStringGetDatum, CStringGetTextDatum, DatumGetPointer, ereport, errcode(), errmsg(), ERROR, ForeignDataWrapper::fdwvalidator, FOREIGNSERVERNAME, FOREIGNSERVEROID, ForeignServerRelationId, GetForeignDataWrapper(), GETSTRUCT, GetUserId(), AlterForeignServerStmt::has_version, heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, NULL, AlterForeignServerStmt::options, pg_foreign_server_ownercheck(), PointerGetDatum, PointerIsValid, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, AlterForeignServerStmt::servername, simple_heap_update(), SysCacheGetAttr(), HeapTupleData::t_self, transformGenericOptions(), and AlterForeignServerStmt::version.
Referenced by ProcessUtilitySlow().
{
Relation rel;
HeapTuple tp;
Datum repl_val[Natts_pg_foreign_server];
bool repl_null[Natts_pg_foreign_server];
bool repl_repl[Natts_pg_foreign_server];
Oid srvId;
Form_pg_foreign_server srvForm;
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
tp = SearchSysCacheCopy1(FOREIGNSERVERNAME,
CStringGetDatum(stmt->servername));
if (!HeapTupleIsValid(tp))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("server \"%s\" does not exist", stmt->servername)));
srvId = HeapTupleGetOid(tp);
srvForm = (Form_pg_foreign_server) GETSTRUCT(tp);
/*
* Only owner or a superuser can ALTER a SERVER.
*/
if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
stmt->servername);
memset(repl_val, 0, sizeof(repl_val));
memset(repl_null, false, sizeof(repl_null));
memset(repl_repl, false, sizeof(repl_repl));
if (stmt->has_version)
{
/*
* Change the server VERSION string.
*/
if (stmt->version)
repl_val[Anum_pg_foreign_server_srvversion - 1] =
CStringGetTextDatum(stmt->version);
else
repl_null[Anum_pg_foreign_server_srvversion - 1] = true;
repl_repl[Anum_pg_foreign_server_srvversion - 1] = true;
}
if (stmt->options)
{
ForeignDataWrapper *fdw = GetForeignDataWrapper(srvForm->srvfdw);
Datum datum;
bool isnull;
/* Extract the current srvoptions */
datum = SysCacheGetAttr(FOREIGNSERVEROID,
tp,
Anum_pg_foreign_server_srvoptions,
&isnull);
if (isnull)
datum = PointerGetDatum(NULL);
/* Prepare the options array */
datum = transformGenericOptions(ForeignServerRelationId,
datum,
stmt->options,
fdw->fdwvalidator);
if (PointerIsValid(DatumGetPointer(datum)))
repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
else
repl_null[Anum_pg_foreign_server_srvoptions - 1] = true;
repl_repl[Anum_pg_foreign_server_srvoptions - 1] = true;
}
/* Everything looks good - update the tuple */
tp = heap_modify_tuple(tp, RelationGetDescr(rel),
repl_val, repl_null, repl_repl);
simple_heap_update(rel, &tp->t_self, tp);
CatalogUpdateIndexes(rel, tp);
InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);
heap_freetuple(tp);
heap_close(rel, RowExclusiveLock);
return srvId;
}
Definition at line 364 of file foreigncmds.c.
References AlterForeignServerOwner_internal(), CStringGetDatum, ereport, errcode(), errmsg(), ERROR, FOREIGNSERVERNAME, ForeignServerRelationId, heap_close, heap_freetuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, RowExclusiveLock, and SearchSysCacheCopy1.
Referenced by ExecAlterOwnerStmt().
{
Oid servOid;
HeapTuple tup;
Relation rel;
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy1(FOREIGNSERVERNAME, CStringGetDatum(name));
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("server \"%s\" does not exist", name)));
servOid = HeapTupleGetOid(tup);
AlterForeignServerOwner_internal(rel, tup, newOwnerId);
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);
return servOid;
}
Definition at line 394 of file foreigncmds.c.
References AlterForeignServerOwner_internal(), ereport, errcode(), errmsg(), ERROR, FOREIGNSERVEROID, ForeignServerRelationId, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, ObjectIdGetDatum, RowExclusiveLock, and SearchSysCacheCopy1.
Referenced by shdepReassignOwned().
{
HeapTuple tup;
Relation rel;
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy1(FOREIGNSERVEROID, ObjectIdGetDatum(srvId));
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("foreign server with OID %u does not exist", srvId)));
AlterForeignServerOwner_internal(rel, tup, newOwnerId);
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);
}
| Oid AlterFunction | ( | AlterFunctionStmt * | stmt | ) |
Definition at line 1045 of file functioncmds.c.
References ACL_KIND_PROC, aclcheck_error(), ACLCHECK_NOT_OWNER, AlterFunctionStmt::actions, Anum_pg_proc_proconfig, DefElem::arg, CatalogUpdateIndexes(), compute_common_attribute(), DatumGetArrayTypeP, defGetNumeric(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, AlterFunctionStmt::func, FuncWithArgs::funcargs, FuncWithArgs::funcname, GETSTRUCT, GetUserId(), heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, interpret_func_volatility(), intVal, InvokeObjectPostAlterHook, lfirst, LookupFuncNameTypeNames(), NameListToString(), NoLock, NULL, ObjectIdGetDatum, pg_proc_ownercheck(), PointerGetDatum, ProcedureRelationId, PROCOID, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), superuser(), SysCacheGetAttr(), HeapTupleData::t_self, and update_proconfig_value().
Referenced by ProcessUtilitySlow().
{
HeapTuple tup;
Oid funcOid;
Form_pg_proc procForm;
Relation rel;
ListCell *l;
DefElem *volatility_item = NULL;
DefElem *strict_item = NULL;
DefElem *security_def_item = NULL;
DefElem *leakproof_item = NULL;
List *set_items = NIL;
DefElem *cost_item = NULL;
DefElem *rows_item = NULL;
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
funcOid = LookupFuncNameTypeNames(stmt->func->funcname,
stmt->func->funcargs,
false);
tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for function %u", funcOid);
procForm = (Form_pg_proc) GETSTRUCT(tup);
/* Permission check: must own function */
if (!pg_proc_ownercheck(funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(stmt->func->funcname));
if (procForm->proisagg)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function",
NameListToString(stmt->func->funcname))));
/* Examine requested actions. */
foreach(l, stmt->actions)
{
DefElem *defel = (DefElem *) lfirst(l);
if (compute_common_attribute(defel,
&volatility_item,
&strict_item,
&security_def_item,
&leakproof_item,
&set_items,
&cost_item,
&rows_item) == false)
elog(ERROR, "option \"%s\" not recognized", defel->defname);
}
if (volatility_item)
procForm->provolatile = interpret_func_volatility(volatility_item);
if (strict_item)
procForm->proisstrict = intVal(strict_item->arg);
if (security_def_item)
procForm->prosecdef = intVal(security_def_item->arg);
if (leakproof_item)
{
if (intVal(leakproof_item->arg) && !superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("only superuser can define a leakproof function")));
procForm->proleakproof = intVal(leakproof_item->arg);
}
if (cost_item)
{
procForm->procost = defGetNumeric(cost_item);
if (procForm->procost <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("COST must be positive")));
}
if (rows_item)
{
procForm->prorows = defGetNumeric(rows_item);
if (procForm->prorows <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ROWS must be positive")));
if (!procForm->proretset)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ROWS is not applicable when function does not return a set")));
}
if (set_items)
{
Datum datum;
bool isnull;
ArrayType *a;
Datum repl_val[Natts_pg_proc];
bool repl_null[Natts_pg_proc];
bool repl_repl[Natts_pg_proc];
/* extract existing proconfig setting */
datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
a = isnull ? NULL : DatumGetArrayTypeP(datum);
/* update according to each SET or RESET item, left to right */
a = update_proconfig_value(a, set_items);
/* update the tuple */
memset(repl_repl, false, sizeof(repl_repl));
repl_repl[Anum_pg_proc_proconfig - 1] = true;
if (a == NULL)
{
repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
repl_null[Anum_pg_proc_proconfig - 1] = true;
}
else
{
repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
repl_null[Anum_pg_proc_proconfig - 1] = false;
}
tup = heap_modify_tuple(tup, RelationGetDescr(rel),
repl_val, repl_null, repl_repl);
}
/* Do the update */
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
heap_close(rel, NoLock);
heap_freetuple(tup);
return funcOid;
}
| Oid AlterOpFamily | ( | AlterOpFamilyStmt * | stmt | ) |
Definition at line 770 of file opclasscmds.c.
References AlterOpFamilyAdd(), AlterOpFamilyDrop(), AlterOpFamilyStmt::amname, AMNAME, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_opfamily_oid(), GETSTRUCT, HeapTupleGetOid, HeapTupleIsValid, AlterOpFamilyStmt::isDrop, AlterOpFamilyStmt::items, AlterOpFamilyStmt::opfamilyname, ReleaseSysCache(), SearchSysCache1, and superuser().
Referenced by ProcessUtilitySlow().
{
Oid amoid, /* our AM's oid */
opfamilyoid; /* oid of opfamily */
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
Form_pg_am pg_am;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
stmt->amname)));
amoid = HeapTupleGetOid(tup);
pg_am = (Form_pg_am) GETSTRUCT(tup);
maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
ReleaseSysCache(tup);
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
/*
* Currently, we require superuser privileges to alter an opfamily.
*
* XXX re-enable NOT_USED code sections below if you remove this test.
*/
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter an operator family")));
/*
* ADD and DROP cases need separate code from here on down.
*/
if (stmt->isDrop)
AlterOpFamilyDrop(stmt->opfamilyname, amoid, opfamilyoid,
maxOpNumber, maxProcNumber,
stmt->items);
else
AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid,
maxOpNumber, maxProcNumber,
stmt->items);
return opfamilyoid;
}
| Oid AlterTSConfiguration | ( | AlterTSConfigurationStmt * | stmt | ) |
Definition at line 1157 of file tsearchcmds.c.
References ACL_KIND_TSCONFIGURATION, aclcheck_error(), ACLCHECK_NOT_OWNER, AlterTSConfigurationStmt::cfgname, AlterTSConfigurationStmt::dicts, DropConfigurationMapping(), ereport, errcode(), errmsg(), ERROR, GetTSConfigTuple(), GetUserId(), heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, makeConfigurationDependencies(), MakeConfigurationMapping(), NameListToString(), pg_ts_config_ownercheck(), ReleaseSysCache(), RowExclusiveLock, AlterTSConfigurationStmt::tokentype, and TSConfigMapRelationId.
Referenced by ProcessUtilitySlow().
{
HeapTuple tup;
Oid cfgId;
Relation relMap;
/* Find the configuration */
tup = GetTSConfigTuple(stmt->cfgname);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("text search configuration \"%s\" does not exist",
NameListToString(stmt->cfgname))));
cfgId = HeapTupleGetOid(tup);
/* must be owner */
if (!pg_ts_config_ownercheck(HeapTupleGetOid(tup), GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
NameListToString(stmt->cfgname));
relMap = heap_open(TSConfigMapRelationId, RowExclusiveLock);
/* Add or drop mappings */
if (stmt->dicts)
MakeConfigurationMapping(stmt, tup, relMap);
else if (stmt->tokentype)
DropConfigurationMapping(stmt, tup, relMap);
/* Update dependencies */
makeConfigurationDependencies(tup, true, relMap);
InvokeObjectPostAlterHook(TSConfigMapRelationId,
HeapTupleGetOid(tup), 0);
heap_close(relMap, RowExclusiveLock);
ReleaseSysCache(tup);
return cfgId;
}
| Oid AlterTSDictionary | ( | AlterTSDictionaryStmt * | stmt | ) |
Definition at line 518 of file tsearchcmds.c.
References ACL_KIND_TSDICTIONARY, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_ts_dict_dictinitoption, DefElem::arg, CatalogUpdateIndexes(), DefElem::defname, deserialize_deflist(), AlterTSDictionaryStmt::dictname, elog, ERROR, get_ts_dict_oid(), GETSTRUCT, GetUserId(), heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, InvokeObjectPostAlterHook, lappend(), lfirst, list_delete_cell(), list_head(), lnext, NameListToString(), ObjectIdGetDatum, AlterTSDictionaryStmt::options, pg_strcasecmp(), pg_ts_dict_ownercheck(), PointerGetDatum, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, serialize_deflist(), simple_heap_update(), SysCacheGetAttr(), HeapTupleData::t_self, TSDictionaryRelationId, TSDICTOID, and verify_dictoptions().
Referenced by ProcessUtilitySlow().
{
HeapTuple tup,
newtup;
Relation rel;
Oid dictId;
ListCell *pl;
List *dictoptions;
Datum opt;
bool isnull;
Datum repl_val[Natts_pg_ts_dict];
bool repl_null[Natts_pg_ts_dict];
bool repl_repl[Natts_pg_ts_dict];
dictId = get_ts_dict_oid(stmt->dictname, false);
rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search dictionary %u",
dictId);
/* must be owner */
if (!pg_ts_dict_ownercheck(dictId, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
NameListToString(stmt->dictname));
/* deserialize the existing set of options */
opt = SysCacheGetAttr(TSDICTOID, tup,
Anum_pg_ts_dict_dictinitoption,
&isnull);
if (isnull)
dictoptions = NIL;
else
dictoptions = deserialize_deflist(opt);
/*
* Modify the options list as per specified changes
*/
foreach(pl, stmt->options)
{
DefElem *defel = (DefElem *) lfirst(pl);
ListCell *cell;
ListCell *prev;
ListCell *next;
/*
* Remove any matches ...
*/
prev = NULL;
for (cell = list_head(dictoptions); cell; cell = next)
{
DefElem *oldel = (DefElem *) lfirst(cell);
next = lnext(cell);
if (pg_strcasecmp(oldel->defname, defel->defname) == 0)
dictoptions = list_delete_cell(dictoptions, cell, prev);
else
prev = cell;
}
/*
* and add new value if it's got one
*/
if (defel->arg)
dictoptions = lappend(dictoptions, defel);
}
/*
* Validate
*/
verify_dictoptions(((Form_pg_ts_dict) GETSTRUCT(tup))->dicttemplate,
dictoptions);
/*
* Looks good, update
*/
memset(repl_val, 0, sizeof(repl_val));
memset(repl_null, false, sizeof(repl_null));
memset(repl_repl, false, sizeof(repl_repl));
if (dictoptions)
repl_val[Anum_pg_ts_dict_dictinitoption - 1] =
PointerGetDatum(serialize_deflist(dictoptions));
else
repl_null[Anum_pg_ts_dict_dictinitoption - 1] = true;
repl_repl[Anum_pg_ts_dict_dictinitoption - 1] = true;
newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
repl_val, repl_null, repl_repl);
simple_heap_update(rel, &newtup->t_self, newtup);
CatalogUpdateIndexes(rel, newtup);
InvokeObjectPostAlterHook(TSDictionaryRelationId, dictId, 0);
/*
* NOTE: because we only support altering the options, not the template,
* there is no need to update dependencies. This might have to change if
* the options ever reference inside-the-database objects.
*/
heap_freetuple(newtup);
ReleaseSysCache(tup);
heap_close(rel, RowExclusiveLock);
return dictId;
}
| Oid AlterUserMapping | ( | AlterUserMappingStmt * | stmt | ) |
Definition at line 1168 of file foreigncmds.c.
References Anum_pg_user_mapping_umoptions, CatalogUpdateIndexes(), DatumGetPointer, elog, ereport, errcode(), errmsg(), ERROR, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, GetForeignDataWrapper(), GetForeignServerByName(), GetSysCacheOid2, GetUserOidFromMapping(), heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, MappingUserName, NULL, ObjectIdGetDatum, OidIsValid, AlterUserMappingStmt::options, PointerGetDatum, PointerIsValid, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, ForeignServer::serverid, AlterUserMappingStmt::servername, simple_heap_update(), SysCacheGetAttr(), HeapTupleData::t_self, transformGenericOptions(), user_mapping_ddl_aclcheck(), USERMAPPINGOID, UserMappingRelationId, USERMAPPINGUSERSERVER, and AlterUserMappingStmt::username.
Referenced by ProcessUtilitySlow().
{
Relation rel;
HeapTuple tp;
Datum repl_val[Natts_pg_user_mapping];
bool repl_null[Natts_pg_user_mapping];
bool repl_repl[Natts_pg_user_mapping];
Oid useId;
Oid umId;
ForeignServer *srv;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
useId = GetUserOidFromMapping(stmt->username, false);
srv = GetForeignServerByName(stmt->servername, false);
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
ObjectIdGetDatum(useId),
ObjectIdGetDatum(srv->serverid));
if (!OidIsValid(umId))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("user mapping \"%s\" does not exist for the server",
MappingUserName(useId))));
user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
tp = SearchSysCacheCopy1(USERMAPPINGOID, ObjectIdGetDatum(umId));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for user mapping %u", umId);
memset(repl_val, 0, sizeof(repl_val));
memset(repl_null, false, sizeof(repl_null));
memset(repl_repl, false, sizeof(repl_repl));
if (stmt->options)
{
ForeignDataWrapper *fdw;
Datum datum;
bool isnull;
/*
* Process the options.
*/
fdw = GetForeignDataWrapper(srv->fdwid);
datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
tp,
Anum_pg_user_mapping_umoptions,
&isnull);
if (isnull)
datum = PointerGetDatum(NULL);
/* Prepare the options array */
datum = transformGenericOptions(UserMappingRelationId,
datum,
stmt->options,
fdw->fdwvalidator);
if (PointerIsValid(DatumGetPointer(datum)))
repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
else
repl_null[Anum_pg_user_mapping_umoptions - 1] = true;
repl_repl[Anum_pg_user_mapping_umoptions - 1] = true;
}
/* Everything looks good - update the tuple */
tp = heap_modify_tuple(tp, RelationGetDescr(rel),
repl_val, repl_null, repl_repl);
simple_heap_update(rel, &tp->t_self, tp);
CatalogUpdateIndexes(rel, tp);
heap_freetuple(tp);
heap_close(rel, RowExclusiveLock);
return umId;
}
| bool CheckIndexCompatible | ( | Oid | oldId, | |
| RangeVar * | heapRelation, | |||
| char * | accessMethodName, | |||
| List * | attributeList, | |||
| List * | exclusionOpNames | |||
| ) |
Definition at line 114 of file indexcmds.c.
References AccessShareLock, AMNAME, Anum_pg_index_indclass, Anum_pg_index_indcollation, Anum_pg_index_indexprs, Anum_pg_index_indpred, Assert, tupleDesc::attrs, ComputeIndexAttrs(), DatumGetPointer, elog, ereport, errcode(), errmsg(), ERROR, get_opclass_input_type(), GETSTRUCT, heap_attisnull(), HeapTupleGetOid, HeapTupleIsValid, i, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_Expressions, IndexInfo::ii_ExpressionsState, IndexInfo::ii_PredicateState, index_close(), INDEX_MAX_KEYS, index_open(), IndexIsValid, INDEXRELID, IsPolymorphicType, list_length(), makeNode, memcmp(), NoLock, NULL, ObjectIdGetDatum, op_input_types(), palloc(), PointerGetDatum, RangeVarGetRelid, RelationData::rd_att, RelationGetExclusionInfo(), ReleaseSysCache(), SearchSysCache1, SysCacheGetAttr(), and oidvector::values.
Referenced by TryReuseIndex().
{
bool isconstraint;
Oid *typeObjectId;
Oid *collationObjectId;
Oid *classObjectId;
Oid accessMethodId;
Oid relationId;
HeapTuple tuple;
Form_pg_index indexForm;
Form_pg_am accessMethodForm;
bool amcanorder;
int16 *coloptions;
IndexInfo *indexInfo;
int numberOfAttributes;
int old_natts;
bool isnull;
bool ret = true;
oidvector *old_indclass;
oidvector *old_indcollation;
Relation irel;
int i;
Datum d;
/* Caller should already have the relation locked in some way. */
relationId = RangeVarGetRelid(heapRelation, NoLock, false);
/*
* We can pretend isconstraint = false unconditionally. It only serves to
* decide the text of an error message that should never happen for us.
*/
isconstraint = false;
numberOfAttributes = list_length(attributeList);
Assert(numberOfAttributes > 0);
Assert(numberOfAttributes <= INDEX_MAX_KEYS);
/* look up the access method */
tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
accessMethodName)));
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
amcanorder = accessMethodForm->amcanorder;
ReleaseSysCache(tuple);
/*
* Compute the operator classes, collations, and exclusion operators for
* the new index, so we can test whether it's compatible with the existing
* one. Note that ComputeIndexAttrs might fail here, but that's OK:
* DefineIndex would have called this function with the same arguments
* later on, and it would have failed then anyway.
*/
indexInfo = makeNode(IndexInfo);
indexInfo->ii_Expressions = NIL;
indexInfo->ii_ExpressionsState = NIL;
indexInfo->ii_PredicateState = NIL;
indexInfo->ii_ExclusionOps = NULL;
indexInfo->ii_ExclusionProcs = NULL;
indexInfo->ii_ExclusionStrats = NULL;
typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
ComputeIndexAttrs(indexInfo,
typeObjectId, collationObjectId, classObjectId,
coloptions, attributeList,
exclusionOpNames, relationId,
accessMethodName, accessMethodId,
amcanorder, isconstraint);
/* Get the soon-obsolete pg_index tuple. */
tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldId));
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for index %u", oldId);
indexForm = (Form_pg_index) GETSTRUCT(tuple);
/*
* We don't assess expressions or predicates; assume incompatibility.
* Also, if the index is invalid for any reason, treat it as incompatible.
*/
if (!(heap_attisnull(tuple, Anum_pg_index_indpred) &&
heap_attisnull(tuple, Anum_pg_index_indexprs) &&
IndexIsValid(indexForm)))
{
ReleaseSysCache(tuple);
return false;
}
/* Any change in operator class or collation breaks compatibility. */
old_natts = indexForm->indnatts;
Assert(old_natts == numberOfAttributes);
d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indcollation, &isnull);
Assert(!isnull);
old_indcollation = (oidvector *) DatumGetPointer(d);
d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indclass, &isnull);
Assert(!isnull);
old_indclass = (oidvector *) DatumGetPointer(d);
ret = (memcmp(old_indclass->values, classObjectId,
old_natts * sizeof(Oid)) == 0 &&
memcmp(old_indcollation->values, collationObjectId,
old_natts * sizeof(Oid)) == 0);
ReleaseSysCache(tuple);
if (!ret)
return false;
/* For polymorphic opcintype, column type changes break compatibility. */
irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
for (i = 0; i < old_natts; i++)
{
if (IsPolymorphicType(get_opclass_input_type(classObjectId[i])) &&
irel->rd_att->attrs[i]->atttypid != typeObjectId[i])
{
ret = false;
break;
}
}
/* Any change in exclusion operator selections breaks compatibility. */
if (ret && indexInfo->ii_ExclusionOps != NULL)
{
Oid *old_operators,
*old_procs;
uint16 *old_strats;
RelationGetExclusionInfo(irel, &old_operators, &old_procs, &old_strats);
ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
old_natts * sizeof(Oid)) == 0;
/* Require an exact input type match for polymorphic operators. */
if (ret)
{
for (i = 0; i < old_natts && ret; i++)
{
Oid left,
right;
op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
irel->rd_att->attrs[i]->atttypid != typeObjectId[i])
{
ret = false;
break;
}
}
}
}
index_close(irel, NoLock);
return ret;
}
| char* ChooseRelationName | ( | const char * | name1, | |
| const char * | name2, | |||
| const char * | label, | |||
| Oid | namespaceid | |||
| ) |
Definition at line 1512 of file indexcmds.c.
References get_relname_relid(), makeObjectName(), OidIsValid, pfree(), snprintf(), and StrNCpy.
Referenced by ChooseIndexName(), and transformColumnDefinition().
{
int pass = 0;
char *relname = NULL;
char modlabel[NAMEDATALEN];
/* try the unmodified label first */
StrNCpy(modlabel, label, sizeof(modlabel));
for (;;)
{
relname = makeObjectName(name1, name2, modlabel);
if (!OidIsValid(get_relname_relid(relname, namespaceid)))
break;
/* found a conflict, so try a new name component */
pfree(relname);
snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
}
return relname;
}
| Oid CreateCast | ( | CreateCastStmt * | stmt | ) |
Definition at line 1256 of file functioncmds.c.
References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, Anum_pg_cast_castcontext, Anum_pg_cast_castfunc, Anum_pg_cast_castmethod, Anum_pg_cast_castsource, Anum_pg_cast_casttarget, BOOLOID, CastRelationId, CASTSOURCETARGET, CatalogUpdateIndexes(), CharGetDatum, ObjectAddress::classId, COERCION_ASSIGNMENT, COERCION_EXPLICIT, COERCION_IMPLICIT, COERCION_METHOD_BINARY, COERCION_METHOD_FUNCTION, CreateCastStmt::context, DEPENDENCY_NORMAL, elog, ereport, errcode(), errmsg(), ERROR, format_type_be(), CreateCastStmt::func, FuncWithArgs::funcargs, FuncWithArgs::funcname, get_element_type(), get_typlenbyvalalign(), get_typtype(), GETSTRUCT, GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), HeapTupleIsValid, CreateCastStmt::inout, INT4OID, InvokeObjectPostCreateHook, IsBinaryCoercible(), LookupFuncNameTypeNames(), MemSet, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, pg_type_aclcheck(), pg_type_ownercheck(), PROCOID, PROVOLATILE_VOLATILE, recordDependencyOn(), recordDependencyOnCurrentExtension(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, SearchSysCache2, simple_heap_insert(), CreateCastStmt::sourcetype, superuser(), CreateCastStmt::targettype, TypeNameToString(), typenameTypeId(), TYPTYPE_COMPOSITE, TYPTYPE_DOMAIN, TYPTYPE_ENUM, TYPTYPE_PSEUDO, values, and WARNING.
Referenced by ProcessUtilitySlow().
{
Oid sourcetypeid;
Oid targettypeid;
char sourcetyptype;
char targettyptype;
Oid funcid;
Oid castid;
int nargs;
char castcontext;
char castmethod;
Relation relation;
HeapTuple tuple;
Datum values[Natts_pg_cast];
bool nulls[Natts_pg_cast];
ObjectAddress myself,
referenced;
AclResult aclresult;
sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
targettypeid = typenameTypeId(NULL, stmt->targettype);
sourcetyptype = get_typtype(sourcetypeid);
targettyptype = get_typtype(targettypeid);
/* No pseudo-types allowed */
if (sourcetyptype == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("source data type %s is a pseudo-type",
TypeNameToString(stmt->sourcetype))));
if (targettyptype == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("target data type %s is a pseudo-type",
TypeNameToString(stmt->targettype))));
/* Permission check */
if (!pg_type_ownercheck(sourcetypeid, GetUserId())
&& !pg_type_ownercheck(targettypeid, GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be owner of type %s or type %s",
format_type_be(sourcetypeid),
format_type_be(targettypeid))));
aclresult = pg_type_aclcheck(sourcetypeid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error_type(aclresult, sourcetypeid);
aclresult = pg_type_aclcheck(targettypeid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error_type(aclresult, targettypeid);
/* Domains are allowed for historical reasons, but we warn */
if (sourcetyptype == TYPTYPE_DOMAIN)
ereport(WARNING,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cast will be ignored because the source data type is a domain")));
else if (targettyptype == TYPTYPE_DOMAIN)
ereport(WARNING,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cast will be ignored because the target data type is a domain")));
/* Detemine the cast method */
if (stmt->func != NULL)
castmethod = COERCION_METHOD_FUNCTION;
else if (stmt->inout)
castmethod = COERCION_METHOD_INOUT;
else
castmethod = COERCION_METHOD_BINARY;
if (castmethod == COERCION_METHOD_FUNCTION)
{
Form_pg_proc procstruct;
funcid = LookupFuncNameTypeNames(stmt->func->funcname,
stmt->func->funcargs,
false);
tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for function %u", funcid);
procstruct = (Form_pg_proc) GETSTRUCT(tuple);
nargs = procstruct->pronargs;
if (nargs < 1 || nargs > 3)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cast function must take one to three arguments")));
if (!IsBinaryCoercible(sourcetypeid, procstruct->proargtypes.values[0]))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("argument of cast function must match or be binary-coercible from source data type")));
if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("second argument of cast function must be type integer")));
if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("third argument of cast function must be type boolean")));
if (!IsBinaryCoercible(procstruct->prorettype, targettypeid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("return data type of cast function must match or be binary-coercible to target data type")));
/*
* Restricting the volatility of a cast function may or may not be a
* good idea in the abstract, but it definitely breaks many old
* user-defined types. Disable this check --- tgl 2/1/03
*/
#ifdef NOT_USED
if (procstruct->provolatile == PROVOLATILE_VOLATILE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cast function must not be volatile")));
#endif
if (procstruct->proisagg)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cast function must not be an aggregate function")));
if (procstruct->proiswindow)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cast function must not be a window function")));
if (procstruct->proretset)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cast function must not return a set")));
ReleaseSysCache(tuple);
}
else
{
funcid = InvalidOid;
nargs = 0;
}
if (castmethod == COERCION_METHOD_BINARY)
{
int16 typ1len;
int16 typ2len;
bool typ1byval;
bool typ2byval;
char typ1align;
char typ2align;
/*
* Must be superuser to create binary-compatible casts, since
* erroneous casts can easily crash the backend.
*/
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to create a cast WITHOUT FUNCTION")));
/*
* Also, insist that the types match as to size, alignment, and
* pass-by-value attributes; this provides at least a crude check that
* they have similar representations. A pair of types that fail this
* test should certainly not be equated.
*/
get_typlenbyvalalign(sourcetypeid, &typ1len, &typ1byval, &typ1align);
get_typlenbyvalalign(targettypeid, &typ2len, &typ2byval, &typ2align);
if (typ1len != typ2len ||
typ1byval != typ2byval ||
typ1align != typ2align)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("source and target data types are not physically compatible")));
/*
* We know that composite, enum and array types are never binary-
* compatible with each other. They all have OIDs embedded in them.
*
* Theoretically you could build a user-defined base type that is
* binary-compatible with a composite, enum, or array type. But we
* disallow that too, as in practice such a cast is surely a mistake.
* You can always work around that by writing a cast function.
*/
if (sourcetyptype == TYPTYPE_COMPOSITE ||
targettyptype == TYPTYPE_COMPOSITE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("composite data types are not binary-compatible")));
if (sourcetyptype == TYPTYPE_ENUM ||
targettyptype == TYPTYPE_ENUM)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("enum data types are not binary-compatible")));
if (OidIsValid(get_element_type(sourcetypeid)) ||
OidIsValid(get_element_type(targettypeid)))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("array data types are not binary-compatible")));
/*
* We also disallow creating binary-compatibility casts involving
* domains. Casting from a domain to its base type is already
* allowed, and casting the other way ought to go through domain
* coercion to permit constraint checking. Again, if you're intent on
* having your own semantics for that, create a no-op cast function.
*
* NOTE: if we were to relax this, the above checks for composites
* etc. would have to be modified to look through domains to their
* base types.
*/
if (sourcetyptype == TYPTYPE_DOMAIN ||
targettyptype == TYPTYPE_DOMAIN)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("domain data types must not be marked binary-compatible")));
}
/*
* Allow source and target types to be same only for length coercion
* functions. We assume a multi-arg function does length coercion.
*/
if (sourcetypeid == targettypeid && nargs < 2)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("source data type and target data type are the same")));
/* convert CoercionContext enum to char value for castcontext */
switch (stmt->context)
{
case COERCION_IMPLICIT:
castcontext = COERCION_CODE_IMPLICIT;
break;
case COERCION_ASSIGNMENT:
castcontext = COERCION_CODE_ASSIGNMENT;
break;
case COERCION_EXPLICIT:
castcontext = COERCION_CODE_EXPLICIT;
break;
default:
elog(ERROR, "unrecognized CoercionContext: %d", stmt->context);
castcontext = 0; /* keep compiler quiet */
break;
}
relation = heap_open(CastRelationId, RowExclusiveLock);
/*
* Check for duplicate. This is just to give a friendly error message,
* the unique index would catch it anyway (so no need to sweat about race
* conditions).
*/
tuple = SearchSysCache2(CASTSOURCETARGET,
ObjectIdGetDatum(sourcetypeid),
ObjectIdGetDatum(targettypeid));
if (HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("cast from type %s to type %s already exists",
format_type_be(sourcetypeid),
format_type_be(targettypeid))));
/* ready to go */
values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
values[Anum_pg_cast_castmethod - 1] = CharGetDatum(castmethod);
MemSet(nulls, false, sizeof(nulls));
tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
castid = simple_heap_insert(relation, tuple);
CatalogUpdateIndexes(relation, tuple);
/* make dependency entries */
myself.classId = CastRelationId;
myself.objectId = castid;
myself.objectSubId = 0;
/* dependency on source type */
referenced.classId = TypeRelationId;
referenced.objectId = sourcetypeid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on target type */
referenced.classId = TypeRelationId;
referenced.objectId = targettypeid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on function */
if (OidIsValid(funcid))
{
referenced.classId = ProcedureRelationId;
referenced.objectId = funcid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* dependency on extension */
recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new cast */
InvokeObjectPostCreateHook(CastRelationId, castid, 0);
heap_freetuple(tuple);
heap_close(relation, RowExclusiveLock);
return castid;
}
| Oid CreateForeignDataWrapper | ( | CreateFdwStmt * | stmt | ) |
Definition at line 506 of file foreigncmds.c.
References Anum_pg_foreign_data_wrapper_fdwacl, Anum_pg_foreign_data_wrapper_fdwhandler, Anum_pg_foreign_data_wrapper_fdwname, Anum_pg_foreign_data_wrapper_fdwoptions, Anum_pg_foreign_data_wrapper_fdwowner, Anum_pg_foreign_data_wrapper_fdwvalidator, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetDatum, DatumGetPointer, DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), errhint(), errmsg(), ERROR, CreateFdwStmt::fdwname, ForeignDataWrapperRelationId, CreateFdwStmt::func_options, GetForeignDataWrapperByName(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, namein(), NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, CreateFdwStmt::options, parse_func_options(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, simple_heap_insert(), superuser(), transformGenericOptions(), and values.
Referenced by ProcessUtilitySlow().
{
Relation rel;
Datum values[Natts_pg_foreign_data_wrapper];
bool nulls[Natts_pg_foreign_data_wrapper];
HeapTuple tuple;
Oid fdwId;
bool handler_given;
bool validator_given;
Oid fdwhandler;
Oid fdwvalidator;
Datum fdwoptions;
Oid ownerId;
ObjectAddress myself;
ObjectAddress referenced;
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
/* Must be super user */
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create foreign-data wrapper \"%s\"",
stmt->fdwname),
errhint("Must be superuser to create a foreign-data wrapper.")));
/* For now the owner cannot be specified on create. Use effective user ID. */
ownerId = GetUserId();
/*
* Check that there is no other foreign-data wrapper by this name.
*/
if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("foreign-data wrapper \"%s\" already exists",
stmt->fdwname)));
/*
* Insert tuple into pg_foreign_data_wrapper.
*/
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname));
values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);
/* Lookup handler and validator functions, if given */
parse_func_options(stmt->func_options,
&handler_given, &fdwhandler,
&validator_given, &fdwvalidator);
values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
fdwoptions = transformGenericOptions(ForeignDataWrapperRelationId,
PointerGetDatum(NULL),
stmt->options,
fdwvalidator);
if (PointerIsValid(DatumGetPointer(fdwoptions)))
values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
else
nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
tuple = heap_form_tuple(rel->rd_att, values, nulls);
fdwId = simple_heap_insert(rel, tuple);
CatalogUpdateIndexes(rel, tuple);
heap_freetuple(tuple);
/* record dependencies */
myself.classId = ForeignDataWrapperRelationId;
myself.objectId = fdwId;
myself.objectSubId = 0;
if (OidIsValid(fdwhandler))
{
referenced.classId = ProcedureRelationId;
referenced.objectId = fdwhandler;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
if (OidIsValid(fdwvalidator))
{
referenced.classId = ProcedureRelationId;
referenced.objectId = fdwvalidator;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
/* dependency on extension */
recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new foreign data wrapper */
InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);
heap_close(rel, RowExclusiveLock);
return fdwId;
}
| Oid CreateForeignServer | ( | CreateForeignServerStmt * | stmt | ) |
Definition at line 809 of file foreigncmds.c.
References ACL_KIND_FDW, ACL_USAGE, aclcheck_error(), ACLCHECK_OK, Anum_pg_foreign_server_srvacl, Anum_pg_foreign_server_srvfdw, Anum_pg_foreign_server_srvname, Anum_pg_foreign_server_srvoptions, Anum_pg_foreign_server_srvowner, Anum_pg_foreign_server_srvtype, Anum_pg_foreign_server_srvversion, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetDatum, CStringGetTextDatum, DatumGetPointer, DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), errmsg(), ERROR, ForeignDataWrapper::fdwid, ForeignDataWrapper::fdwname, CreateForeignServerStmt::fdwname, ForeignDataWrapper::fdwvalidator, ForeignServerRelationId, GetForeignDataWrapperByName(), GetForeignServerByName(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, namein(), NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, CreateForeignServerStmt::options, pg_foreign_data_wrapper_aclcheck(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, CreateForeignServerStmt::servername, CreateForeignServerStmt::servertype, simple_heap_insert(), transformGenericOptions(), values, and CreateForeignServerStmt::version.
Referenced by ProcessUtilitySlow().
{
Relation rel;
Datum srvoptions;
Datum values[Natts_pg_foreign_server];
bool nulls[Natts_pg_foreign_server];
HeapTuple tuple;
Oid srvId;
Oid ownerId;
AclResult aclresult;
ObjectAddress myself;
ObjectAddress referenced;
ForeignDataWrapper *fdw;
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
/* For now the owner cannot be specified on create. Use effective user ID. */
ownerId = GetUserId();
/*
* Check that there is no other foreign server by this name.
*/
if (GetForeignServerByName(stmt->servername, true) != NULL)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("server \"%s\" already exists",
stmt->servername)));
/*
* Check that the FDW exists and that we have USAGE on it. Also get the
* actual FDW for option validation etc.
*/
fdw = GetForeignDataWrapperByName(stmt->fdwname, false);
aclresult = pg_foreign_data_wrapper_aclcheck(fdw->fdwid, ownerId, ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
/*
* Insert tuple into pg_foreign_server.
*/
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
values[Anum_pg_foreign_server_srvname - 1] =
DirectFunctionCall1(namein, CStringGetDatum(stmt->servername));
values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);
values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);
/* Add server type if supplied */
if (stmt->servertype)
values[Anum_pg_foreign_server_srvtype - 1] =
CStringGetTextDatum(stmt->servertype);
else
nulls[Anum_pg_foreign_server_srvtype - 1] = true;
/* Add server version if supplied */
if (stmt->version)
values[Anum_pg_foreign_server_srvversion - 1] =
CStringGetTextDatum(stmt->version);
else
nulls[Anum_pg_foreign_server_srvversion - 1] = true;
/* Start with a blank acl */
nulls[Anum_pg_foreign_server_srvacl - 1] = true;
/* Add server options */
srvoptions = transformGenericOptions(ForeignServerRelationId,
PointerGetDatum(NULL),
stmt->options,
fdw->fdwvalidator);
if (PointerIsValid(DatumGetPointer(srvoptions)))
values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
else
nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
tuple = heap_form_tuple(rel->rd_att, values, nulls);
srvId = simple_heap_insert(rel, tuple);
CatalogUpdateIndexes(rel, tuple);
heap_freetuple(tuple);
/* record dependencies */
myself.classId = ForeignServerRelationId;
myself.objectId = srvId;
myself.objectSubId = 0;
referenced.classId = ForeignDataWrapperRelationId;
referenced.objectId = fdw->fdwid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
/* dependency on extension */
recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new foreign server */
InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
heap_close(rel, RowExclusiveLock);
return srvId;
}
| void CreateForeignTable | ( | CreateForeignTableStmt * | stmt, | |
| Oid | relid | |||
| ) |
Definition at line 1350 of file foreigncmds.c.
References ACL_KIND_FOREIGN_SERVER, ACL_USAGE, aclcheck_error(), ACLCHECK_OK, Anum_pg_foreign_table_ftoptions, Anum_pg_foreign_table_ftrelid, Anum_pg_foreign_table_ftserver, CatalogUpdateIndexes(), ObjectAddress::classId, CommandCounterIncrement(), DatumGetPointer, DEPENDENCY_NORMAL, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, ForeignTableRelationId, GetForeignDataWrapper(), GetForeignServerByName(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, CreateForeignTableStmt::options, pg_foreign_server_aclcheck(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), RowExclusiveLock, ForeignServer::serverid, ForeignServer::servername, CreateForeignTableStmt::servername, simple_heap_insert(), transformGenericOptions(), and values.
Referenced by ProcessUtilitySlow().
{
Relation ftrel;
Datum ftoptions;
Datum values[Natts_pg_foreign_table];
bool nulls[Natts_pg_foreign_table];
HeapTuple tuple;
AclResult aclresult;
ObjectAddress myself;
ObjectAddress referenced;
Oid ownerId;
ForeignDataWrapper *fdw;
ForeignServer *server;
/*
* Advance command counter to ensure the pg_attribute tuple is visible;
* the tuple might be updated to add constraints in previous step.
*/
CommandCounterIncrement();
ftrel = heap_open(ForeignTableRelationId, RowExclusiveLock);
/*
* For now the owner cannot be specified on create. Use effective user ID.
*/
ownerId = GetUserId();
/*
* Check that the foreign server exists and that we have USAGE on it. Also
* get the actual FDW for option validation etc.
*/
server = GetForeignServerByName(stmt->servername, false);
aclresult = pg_foreign_server_aclcheck(server->serverid, ownerId, ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, server->servername);
fdw = GetForeignDataWrapper(server->fdwid);
/*
* Insert tuple into pg_foreign_table.
*/
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
values[Anum_pg_foreign_table_ftrelid - 1] = ObjectIdGetDatum(relid);
values[Anum_pg_foreign_table_ftserver - 1] = ObjectIdGetDatum(server->serverid);
/* Add table generic options */
ftoptions = transformGenericOptions(ForeignTableRelationId,
PointerGetDatum(NULL),
stmt->options,
fdw->fdwvalidator);
if (PointerIsValid(DatumGetPointer(ftoptions)))
values[Anum_pg_foreign_table_ftoptions - 1] = ftoptions;
else
nulls[Anum_pg_foreign_table_ftoptions - 1] = true;
tuple = heap_form_tuple(ftrel->rd_att, values, nulls);
simple_heap_insert(ftrel, tuple);
CatalogUpdateIndexes(ftrel, tuple);
heap_freetuple(tuple);
/* Add pg_class dependency on the server */
myself.classId = RelationRelationId;
myself.objectId = relid;
myself.objectSubId = 0;
referenced.classId = ForeignServerRelationId;
referenced.objectId = server->serverid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
heap_close(ftrel, RowExclusiveLock);
}
| Oid CreateFunction | ( | CreateFunctionStmt * | stmt, | |
| const char * | queryString | |||
| ) |
Definition at line 788 of file functioncmds.c.
References ACL_CREATE, ACL_KIND_LANGUAGE, ACL_KIND_NAMESPACE, ACL_USAGE, aclcheck_error(), ACLCHECK_NO_PRIV, ACLCHECK_OK, ClanguageId, compute_attributes_sql_style(), compute_attributes_with_style(), compute_return_type(), ereport, errcode(), errhint(), errmsg(), ERROR, examine_parameter_list(), format_type_be(), CreateFunctionStmt::funcname, get_namespace_name(), GETSTRUCT, GetUserId(), HeapTupleGetOid, HeapTupleIsValid, INTERNALlanguageId, interpret_AS_clause(), LANGNAME, NameStr, OidIsValid, CreateFunctionStmt::options, CreateFunctionStmt::parameters, pg_language_aclcheck(), pg_namespace_aclcheck(), PLTemplateExists(), PointerGetDatum, ProcedureCreate(), QualifiedNameGetCreationNamespace(), ReleaseSysCache(), CreateFunctionStmt::replace, CreateFunctionStmt::returnType, SearchSysCache1, superuser(), and CreateFunctionStmt::withClause.
Referenced by ProcessUtilitySlow().
{
char *probin_str;
char *prosrc_str;
Oid prorettype;
bool returnsSet;
char *language;
Oid languageOid;
Oid languageValidator;
char *funcname;
Oid namespaceId;
AclResult aclresult;
oidvector *parameterTypes;
ArrayType *allParameterTypes;
ArrayType *parameterModes;
ArrayType *parameterNames;
List *parameterDefaults;
Oid requiredResultType;
bool isWindowFunc,
isStrict,
security,
isLeakProof;
char volatility;
ArrayType *proconfig;
float4 procost;
float4 prorows;
HeapTuple languageTuple;
Form_pg_language languageStruct;
List *as_clause;
/* Convert list of names to a name and namespace */
namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
&funcname);
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceId));
/* default attributes */
isWindowFunc = false;
isStrict = false;
security = false;
isLeakProof = false;
volatility = PROVOLATILE_VOLATILE;
proconfig = NULL;
procost = -1; /* indicates not set */
prorows = -1; /* indicates not set */
/* override attributes from explicit list */
compute_attributes_sql_style(stmt->options,
&as_clause, &language,
&isWindowFunc, &volatility,
&isStrict, &security, &isLeakProof,
&proconfig, &procost, &prorows);
/* Look up the language and validate permissions */
languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
if (!HeapTupleIsValid(languageTuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("language \"%s\" does not exist", language),
(PLTemplateExists(language) ?
errhint("Use CREATE LANGUAGE to load the language into the database.") : 0)));
languageOid = HeapTupleGetOid(languageTuple);
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
if (languageStruct->lanpltrusted)
{
/* if trusted language, need USAGE privilege */
AclResult aclresult;
aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
NameStr(languageStruct->lanname));
}
else
{
/* if untrusted language, must be superuser */
if (!superuser())
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
NameStr(languageStruct->lanname));
}
languageValidator = languageStruct->lanvalidator;
ReleaseSysCache(languageTuple);
/*
* Only superuser is allowed to create leakproof functions because it
* possibly allows unprivileged users to reference invisible tuples to be
* filtered out using views for row-level security.
*/
if (isLeakProof && !superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("only superuser can define a leakproof function")));
/*
* Convert remaining parameters of CREATE to form wanted by
* ProcedureCreate.
*/
examine_parameter_list(stmt->parameters, languageOid, queryString,
¶meterTypes,
&allParameterTypes,
¶meterModes,
¶meterNames,
¶meterDefaults,
&requiredResultType);
if (stmt->returnType)
{
/* explicit RETURNS clause */
compute_return_type(stmt->returnType, languageOid,
&prorettype, &returnsSet);
if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("function result type must be %s because of OUT parameters",
format_type_be(requiredResultType))));
}
else if (OidIsValid(requiredResultType))
{
/* default RETURNS clause from OUT parameters */
prorettype = requiredResultType;
returnsSet = false;
}
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("function result type must be specified")));
/* Alternative possibility: default to RETURNS VOID */
prorettype = VOIDOID;
returnsSet = false;
}
compute_attributes_with_style(stmt->withClause, &isStrict, &volatility);
interpret_AS_clause(languageOid, language, funcname, as_clause,
&prosrc_str, &probin_str);
/*
* Set default values for COST and ROWS depending on other parameters;
* reject ROWS if it's not returnsSet. NB: pg_dump knows these default
* values, keep it in sync if you change them.
*/
if (procost < 0)
{
/* SQL and PL-language functions are assumed more expensive */
if (languageOid == INTERNALlanguageId ||
languageOid == ClanguageId)
procost = 1;
else
procost = 100;
}
if (prorows < 0)
{
if (returnsSet)
prorows = 1000;
else
prorows = 0; /* dummy value if not returnsSet */
}
else if (!returnsSet)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ROWS is not applicable when function does not return a set")));
/*
* And now that we have all the parameters, and know we're permitted to do
* so, go ahead and create the function.
*/
return ProcedureCreate(funcname,
namespaceId,
stmt->replace,
returnsSet,
prorettype,
GetUserId(),
languageOid,
languageValidator,
prosrc_str, /* converted to text later */
probin_str, /* converted to text later */
false, /* not an aggregate */
isWindowFunc,
security,
isLeakProof,
isStrict,
volatility,
parameterTypes,
PointerGetDatum(allParameterTypes),
PointerGetDatum(parameterModes),
PointerGetDatum(parameterNames),
parameterDefaults,
PointerGetDatum(proconfig),
procost,
prorows);
}
| Oid CreateUserMapping | ( | CreateUserMappingStmt * | stmt | ) |
Definition at line 1070 of file foreigncmds.c.
References Anum_pg_user_mapping_umoptions, Anum_pg_user_mapping_umserver, Anum_pg_user_mapping_umuser, CatalogUpdateIndexes(), ObjectAddress::classId, DatumGetPointer, DEPENDENCY_NORMAL, ereport, errcode(), errmsg(), ERROR, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, GetForeignDataWrapper(), GetForeignServerByName(), GetSysCacheOid2, GetUserOidFromMapping(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, MappingUserName, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, CreateUserMappingStmt::options, PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, ForeignServer::serverid, CreateUserMappingStmt::servername, simple_heap_insert(), transformGenericOptions(), user_mapping_ddl_aclcheck(), UserMappingRelationId, USERMAPPINGUSERSERVER, CreateUserMappingStmt::username, and values.
Referenced by ProcessUtilitySlow().
{
Relation rel;
Datum useoptions;
Datum values[Natts_pg_user_mapping];
bool nulls[Natts_pg_user_mapping];
HeapTuple tuple;
Oid useId;
Oid umId;
ObjectAddress myself;
ObjectAddress referenced;
ForeignServer *srv;
ForeignDataWrapper *fdw;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
useId = GetUserOidFromMapping(stmt->username, false);
/* Check that the server exists. */
srv = GetForeignServerByName(stmt->servername, false);
user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
/*
* Check that the user mapping is unique within server.
*/
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
ObjectIdGetDatum(useId),
ObjectIdGetDatum(srv->serverid));
if (OidIsValid(umId))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("user mapping \"%s\" already exists for server %s",
MappingUserName(useId),
stmt->servername)));
fdw = GetForeignDataWrapper(srv->fdwid);
/*
* Insert tuple into pg_user_mapping.
*/
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);
/* Add user options */
useoptions = transformGenericOptions(UserMappingRelationId,
PointerGetDatum(NULL),
stmt->options,
fdw->fdwvalidator);
if (PointerIsValid(DatumGetPointer(useoptions)))
values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
else
nulls[Anum_pg_user_mapping_umoptions - 1] = true;
tuple = heap_form_tuple(rel->rd_att, values, nulls);
umId = simple_heap_insert(rel, tuple);
CatalogUpdateIndexes(rel, tuple);
heap_freetuple(tuple);
/* Add dependency on the server */
myself.classId = UserMappingRelationId;
myself.objectId = umId;
myself.objectSubId = 0;
referenced.classId = ForeignServerRelationId;
referenced.objectId = srv->serverid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
if (OidIsValid(useId))
{
/* Record the mapped user dependency */
recordDependencyOnOwner(UserMappingRelationId, umId, useId);
}
/* dependency on extension */
recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new user mapping */
InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);
heap_close(rel, RowExclusiveLock);
return umId;
}
Definition at line 116 of file define.c.
References DefElem::arg, defGetString(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, intVal, nodeTag, NULL, pg_strcasecmp(), and T_Integer.
Referenced by compute_attributes_with_style(), DefineOperator(), DefineType(), dintdict_init(), dsimple_init(), dsynonym_init(), dxsyn_init(), ExplainQuery(), file_fdw_validator(), get_file_fdw_attribute_options(), GetCommandLogLevel(), interpretOidsOption(), postgres_fdw_validator(), postgresGetForeignRelSize(), and ProcessCopyOptions().
{
/*
* If no parameter given, assume "true" is meant.
*/
if (def->arg == NULL)
return true;
/*
* Allow 0, 1, "true", "false", "on", "off"
*/
switch (nodeTag(def->arg))
{
case T_Integer:
switch (intVal(def->arg))
{
case 0:
return false;
case 1:
return true;
default:
/* otherwise, error out below */
break;
}
break;
default:
{
char *sval = defGetString(def);
/*
* The set of strings accepted here should match up with the
* grammar's opt_boolean production.
*/
if (pg_strcasecmp(sval, "true") == 0)
return true;
if (pg_strcasecmp(sval, "false") == 0)
return false;
if (pg_strcasecmp(sval, "on") == 0)
return true;
if (pg_strcasecmp(sval, "off") == 0)
return false;
}
break;
}
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires a Boolean value",
def->defname)));
return false; /* keep compiler quiet */
}
| int64 defGetInt64 | ( | DefElem * | def | ) |
Definition at line 171 of file define.c.
References DefElem::arg, CStringGetDatum, DatumGetInt64, DefElem::defname, DirectFunctionCall1, ereport, errcode(), errmsg(), ERROR, int8in(), intVal, nodeTag, NULL, strVal, T_Float, and T_Integer.
Referenced by init_params().
{
if (def->arg == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires a numeric value",
def->defname)));
switch (nodeTag(def->arg))
{
case T_Integer:
return (int64) intVal(def->arg);
case T_Float:
/*
* Values too large for int4 will be represented as Float
* constants by the lexer. Accept these if they are valid int8
* strings.
*/
return DatumGetInt64(DirectFunctionCall1(int8in,
CStringGetDatum(strVal(def->arg))));
default:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires a numeric value",
def->defname)));
}
return 0; /* keep compiler quiet */
}
| double defGetNumeric | ( | DefElem * | def | ) |
Definition at line 90 of file define.c.
References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg(), ERROR, floatVal, intVal, nodeTag, NULL, T_Float, and T_Integer.
Referenced by AlterFunction().
{
if (def->arg == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires a numeric value",
def->defname)));
switch (nodeTag(def->arg))
{
case T_Integer:
return (double) intVal(def->arg);
case T_Float:
return floatVal(def->arg);
default:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires a numeric value",
def->defname)));
}
return 0; /* keep compiler quiet */
}
Definition at line 204 of file define.c.
References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg(), ERROR, list_make1, nodeTag, NULL, T_List, T_String, and T_TypeName.
Referenced by DefineAggregate(), DefineCollation(), DefineOperator(), DefineRange(), DefineTSConfiguration(), DefineTSDictionary(), DefineType(), get_ts_parser_func(), get_ts_template_func(), and init_params().
{
if (def->arg == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires a parameter",
def->defname)));
switch (nodeTag(def->arg))
{
case T_TypeName:
return ((TypeName *) def->arg)->names;
case T_List:
return (List *) def->arg;
case T_String:
/* Allow quoted name for backwards compatibility */
return list_make1(def->arg);
default:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("argument of %s must be a name",
def->defname)));
}
return NIL; /* keep compiler quiet */
}
| char* defGetString | ( | DefElem * | def | ) |
Definition at line 49 of file define.c.
References DefElem::arg, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, intVal, NameListToString(), nodeTag, NULL, palloc(), pstrdup(), snprintf(), strVal, T_A_Star, T_Float, T_Integer, T_List, T_String, T_TypeName, and TypeNameToString().
Referenced by check_selective_binary_conversion(), defGetBoolean(), defGetTypeLength(), DefineAggregate(), DefineCollation(), DefineType(), deparseAnalyzeSql(), deparseColumnRef(), deparseRelation(), dintdict_init(), dispell_init(), dsimple_init(), dsnowball_init(), dsynonym_init(), dxsyn_init(), ExplainQuery(), ExplainResultDesc(), ExtractConnectionOptions(), file_fdw_validator(), fileGetOptions(), optionListToArray(), postgres_fdw_validator(), postgresGetForeignRelSize(), ProcessCopyOptions(), prsd_headline(), serialize_deflist(), thesaurus_init(), transformRelOptions(), and unaccent_init().
{
if (def->arg == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires a parameter",
def->defname)));
switch (nodeTag(def->arg))
{
case T_Integer:
{
char *str = palloc(32);
snprintf(str, 32, "%ld", (long) intVal(def->arg));
return str;
}
case T_Float:
/*
* T_Float values are kept in string form, so this type cheat
* works (and doesn't risk losing precision)
*/
return strVal(def->arg);
case T_String:
return strVal(def->arg);
case T_TypeName:
return TypeNameToString((TypeName *) def->arg);
case T_List:
return NameListToString((List *) def->arg);
case T_A_Star:
return pstrdup("*");
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
}
return NULL; /* keep compiler quiet */
}
| int defGetTypeLength | ( | DefElem * | def | ) |
Definition at line 264 of file define.c.
References DefElem::arg, defGetString(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, intVal, nodeTag, NULL, pg_strcasecmp(), strVal, T_Float, T_Integer, T_List, T_String, T_TypeName, and TypeNameToString().
Referenced by DefineType().
{
if (def->arg == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires a parameter",
def->defname)));
switch (nodeTag(def->arg))
{
case T_Integer:
return intVal(def->arg);
case T_Float:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires an integer value",
def->defname)));
break;
case T_String:
if (pg_strcasecmp(strVal(def->arg), "variable") == 0)
return -1; /* variable length */
break;
case T_TypeName:
/* cope if grammar chooses to believe "variable" is a typename */
if (pg_strcasecmp(TypeNameToString((TypeName *) def->arg),
"variable") == 0)
return -1; /* variable length */
break;
case T_List:
/* must be an operator name */
break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
}
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid argument for %s: \"%s\"",
def->defname, defGetString(def))));
return 0; /* keep compiler quiet */
}
Definition at line 236 of file define.c.
References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg(), ERROR, list_make1, makeTypeNameFromNameList(), nodeTag, NULL, T_String, and T_TypeName.
Referenced by DefineAggregate(), DefineOperator(), DefineRange(), and DefineType().
{
if (def->arg == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires a parameter",
def->defname)));
switch (nodeTag(def->arg))
{
case T_TypeName:
return (TypeName *) def->arg;
case T_String:
/* Allow quoted typename for backwards compatibility */
return makeTypeNameFromNameList(list_make1(def->arg));
default:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("argument of %s must be a type name",
def->defname)));
}
return NULL; /* keep compiler quiet */
}
Definition at line 51 of file aggregatecmds.c.
References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, AggregateCreate(), defGetQualifiedName(), defGetString(), defGetTypeName(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, format_type_be(), get_namespace_name(), get_typtype(), getTypeInputInfo(), GetUserId(), i, INTERNALOID, IsPolymorphicType, lfirst, list_length(), NIL, NULL, OidInputFunctionCall(), palloc(), pg_namespace_aclcheck(), pg_strcasecmp(), QualifiedNameGetCreationNamespace(), superuser(), TypeNameToString(), typenameTypeId(), TYPTYPE_PSEUDO, and WARNING.
Referenced by ProcessUtilitySlow().
{
char *aggName;
Oid aggNamespace;
AclResult aclresult;
List *transfuncName = NIL;
List *finalfuncName = NIL;
List *sortoperatorName = NIL;
TypeName *baseType = NULL;
TypeName *transType = NULL;
char *initval = NULL;
Oid *aggArgTypes;
int numArgs;
Oid transTypeId;
char transTypeType;
ListCell *pl;
/* Convert list of names to a name and namespace */
aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(aggNamespace));
foreach(pl, parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
/*
* sfunc1, stype1, and initcond1 are accepted as obsolete spellings
* for sfunc, stype, initcond.
*/
if (pg_strcasecmp(defel->defname, "sfunc") == 0)
transfuncName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
transfuncName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
finalfuncName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "sortop") == 0)
sortoperatorName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "basetype") == 0)
baseType = defGetTypeName(defel);
else if (pg_strcasecmp(defel->defname, "stype") == 0)
transType = defGetTypeName(defel);
else if (pg_strcasecmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
else if (pg_strcasecmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
initval = defGetString(defel);
else
ereport(WARNING,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("aggregate attribute \"%s\" not recognized",
defel->defname)));
}
/*
* make sure we have our required definitions
*/
if (transType == NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregate stype must be specified")));
if (transfuncName == NIL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregate sfunc must be specified")));
/*
* look up the aggregate's input datatype(s).
*/
if (oldstyle)
{
/*
* Old style: use basetype parameter. This supports aggregates of
* zero or one input, with input type ANY meaning zero inputs.
*
* Historically we allowed the command to look like basetype = 'ANY'
* so we must do a case-insensitive comparison for the name ANY. Ugh.
*/
if (baseType == NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregate input type must be specified")));
if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
{
numArgs = 0;
aggArgTypes = NULL;
}
else
{
numArgs = 1;
aggArgTypes = (Oid *) palloc(sizeof(Oid));
aggArgTypes[0] = typenameTypeId(NULL, baseType);
}
}
else
{
/*
* New style: args is a list of TypeNames (possibly zero of 'em).
*/
ListCell *lc;
int i = 0;
if (baseType != NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("basetype is redundant with aggregate input type specification")));
numArgs = list_length(args);
aggArgTypes = (Oid *) palloc(sizeof(Oid) * numArgs);
foreach(lc, args)
{
TypeName *curTypeName = (TypeName *) lfirst(lc);
aggArgTypes[i++] = typenameTypeId(NULL, curTypeName);
}
}
/*
* look up the aggregate's transtype.
*
* transtype can't be a pseudo-type, since we need to be able to store
* values of the transtype. However, we can allow polymorphic transtype
* in some cases (AggregateCreate will check). Also, we allow "internal"
* for functions that want to pass pointers to private data structures;
* but allow that only to superusers, since you could crash the system (or
* worse) by connecting up incompatible internal-using functions in an
* aggregate.
*/
transTypeId = typenameTypeId(NULL, transType);
transTypeType = get_typtype(transTypeId);
if (transTypeType == TYPTYPE_PSEUDO &&
!IsPolymorphicType(transTypeId))
{
if (transTypeId == INTERNALOID && superuser())
/* okay */ ;
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregate transition data type cannot be %s",
format_type_be(transTypeId))));
}
/*
* If we have an initval, and it's not for a pseudotype (particularly a
* polymorphic type), make sure it's acceptable to the type's input
* function. We will store the initval as text, because the input
* function isn't necessarily immutable (consider "now" for timestamp),
* and we want to use the runtime not creation-time interpretation of the
* value. However, if it's an incorrect value it seems much more
* user-friendly to complain at CREATE AGGREGATE time.
*/
if (initval && transTypeType != TYPTYPE_PSEUDO)
{
Oid typinput,
typioparam;
getTypeInputInfo(transTypeId, &typinput, &typioparam);
(void) OidInputFunctionCall(typinput, initval, typioparam, -1);
}
/*
* Most of the argument-checking is done inside of AggregateCreate
*/
return AggregateCreate(aggName, /* aggregate name */
aggNamespace, /* namespace */
aggArgTypes, /* input data type(s) */
numArgs,
transfuncName, /* step function name */
finalfuncName, /* final function name */
sortoperatorName, /* sort operator name */
transTypeId, /* transition data type */
initval); /* initial condition */
}
| Oid DefineIndex | ( | IndexStmt * | stmt, | |
| Oid | indexRelationId, | |||
| bool | is_alter_table, | |||
| bool | check_rights, | |||
| bool | skip_build, | |||
| bool | quiet | |||
| ) |
Definition at line 296 of file indexcmds.c.
References IndexStmt::accessMethod, ACL_CREATE, ACL_KIND_NAMESPACE, ACL_KIND_TABLESPACE, aclcheck_error(), ACLCHECK_OK, allowSystemTableMods, AMNAME, Assert, BuildIndexInfo(), CacheInvalidateRelcacheByRelid(), CheckPredicate(), ChooseIndexColumnNames(), ChooseIndexName(), CommitTransactionCommand(), ComputeIndexAttrs(), IndexStmt::concurrent, CreateComments(), LockRelId::dbId, DEBUG1, IndexStmt::deferrable, elog, ereport, errcode(), errmsg(), ERROR, IndexStmt::excludeOpNames, get_namespace_name(), get_tablespace_name(), get_tablespace_oid(), GetCurrentVirtualXIDs(), GetDefaultTablespace(), GetLockConflicts(), GETSTRUCT, GetTransactionSnapshot(), GetUserId(), GLOBALTABLESPACE_OID, heap_close, heap_openrv(), HeapTupleGetOid, HeapTupleIsValid, i, IndexStmt::idxcomment, IndexStmt::idxname, IndexInfo::ii_BrokenHotChain, IndexInfo::ii_Concurrent, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_Expressions, IndexInfo::ii_ExpressionsState, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, IndexInfo::ii_ReadyForInserts, IndexInfo::ii_Unique, index_build(), index_check_primary_key(), index_close(), index_create(), INDEX_CREATE_SET_READY, INDEX_CREATE_SET_VALID, INDEX_MAX_KEYS, index_open(), index_reloptions(), index_set_state_flags(), IndexStmt::indexParams, IndexStmt::initdeferred, IsBootstrapProcessingMode, IndexStmt::isconstraint, list_length(), LockRelationIdForSession(), LockInfoData::lockRelId, make_ands_implicit(), makeNode, MyDatabaseTableSpace, NIL, NoLock, NOTICE, NULL, OidIsValid, IndexStmt::oldNode, IndexStmt::options, palloc(), pfree(), pg_namespace_aclcheck(), pg_tablespace_aclcheck(), PointerGetDatum, PopActiveSnapshot(), IndexStmt::primary, PROC_IN_VACUUM, PROC_IS_AUTOVACUUM, PushActiveSnapshot(), RelationData::rd_lockInfo, RelationData::rd_rel, RegisterSnapshot(), IndexStmt::relation, RELATION_IS_OTHER_TEMP, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RelationRelationId, ReleaseSysCache(), LockRelId::relId, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_RELATION, RowExclusiveLock, SearchSysCache1, SET_LOCKTAG_RELATION, SetInvalidVirtualTransactionId, ShareLock, ShareUpdateExclusiveLock, StartTransactionCommand(), IndexStmt::tableSpace, transformRelOptions(), IndexStmt::unique, UnlockRelationIdForSession(), UnregisterSnapshot(), validate_index(), VirtualTransactionIdEquals, VirtualTransactionIdIsValid, VirtualXactLock(), IndexStmt::whereClause, and SnapshotData::xmin.
Referenced by ATExecAddIndex(), and ProcessUtilitySlow().
{
char *indexRelationName;
char *accessMethodName;
Oid *typeObjectId;
Oid *collationObjectId;
Oid *classObjectId;
Oid accessMethodId;
Oid relationId;
Oid namespaceId;
Oid tablespaceId;
List *indexColNames;
Relation rel;
Relation indexRelation;
HeapTuple tuple;
Form_pg_am accessMethodForm;
bool amcanorder;
RegProcedure amoptions;
Datum reloptions;
int16 *coloptions;
IndexInfo *indexInfo;
int numberOfAttributes;
TransactionId limitXmin;
VirtualTransactionId *old_lockholders;
VirtualTransactionId *old_snapshots;
int n_old_snapshots;
LockRelId heaprelid;
LOCKTAG heaplocktag;
Snapshot snapshot;
int i;
/*
* count attributes in index
*/
numberOfAttributes = list_length(stmt->indexParams);
if (numberOfAttributes <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("must specify at least one column")));
if (numberOfAttributes > INDEX_MAX_KEYS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_COLUMNS),
errmsg("cannot use more than %d columns in an index",
INDEX_MAX_KEYS)));
/*
* Open heap relation, acquire a suitable lock on it, remember its OID
*
* Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
* index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
* (but not VACUUM).
*/
rel = heap_openrv(stmt->relation,
(stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock));
relationId = RelationGetRelid(rel);
namespaceId = RelationGetNamespace(rel);
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_MATVIEW)
{
if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
/*
* Custom error message for FOREIGN TABLE since the term is close
* to a regular table and can confuse the user.
*/
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot create index on foreign table \"%s\"",
RelationGetRelationName(rel))));
else
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a table",
RelationGetRelationName(rel))));
}
/*
* Don't try to CREATE INDEX on temp tables of other backends.
*/
if (RELATION_IS_OTHER_TEMP(rel))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot create indexes on temporary tables of other sessions")));
/*
* Verify we (still) have CREATE rights in the rel's namespace.
* (Presumably we did when the rel was created, but maybe not anymore.)
* Skip check if caller doesn't want it. Also skip check if
* bootstrapping, since permissions machinery may not be working yet.
*/
if (check_rights && !IsBootstrapProcessingMode())
{
AclResult aclresult;
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceId));
}
/*
* Select tablespace to use. If not specified, use default tablespace
* (which may in turn default to database's default).
*/
if (stmt->tableSpace)
{
tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
}
else
{
tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence);
/* note InvalidOid is OK in this case */
}
/* Check permissions except when using database's default */
if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
{
AclResult aclresult;
aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
get_tablespace_name(tablespaceId));
}
/*
* Force shared indexes into the pg_global tablespace. This is a bit of a
* hack but seems simpler than marking them in the BKI commands. On the
* other hand, if it's not shared, don't allow it to be placed there.
*/
if (rel->rd_rel->relisshared)
tablespaceId = GLOBALTABLESPACE_OID;
else if (tablespaceId == GLOBALTABLESPACE_OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("only shared relations can be placed in pg_global tablespace")));
/*
* Choose the index column names.
*/
indexColNames = ChooseIndexColumnNames(stmt->indexParams);
/*
* Select name for index if caller didn't specify
*/
indexRelationName = stmt->idxname;
if (indexRelationName == NULL)
indexRelationName = ChooseIndexName(RelationGetRelationName(rel),
namespaceId,
indexColNames,
stmt->excludeOpNames,
stmt->primary,
stmt->isconstraint);
/*
* look up the access method, verify it can handle the requested features
*/
accessMethodName = stmt->accessMethod;
tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
if (!HeapTupleIsValid(tuple))
{
/*
* Hack to provide more-or-less-transparent updating of old RTREE
* indexes to GiST: if RTREE is requested and not found, use GIST.
*/
if (strcmp(accessMethodName, "rtree") == 0)
{
ereport(NOTICE,
(errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
accessMethodName = "gist";
tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
}
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
accessMethodName)));
}
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
if (stmt->unique && !accessMethodForm->amcanunique)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("access method \"%s\" does not support unique indexes",
accessMethodName)));
if (numberOfAttributes > 1 && !accessMethodForm->amcanmulticol)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("access method \"%s\" does not support multicolumn indexes",
accessMethodName)));
if (stmt->excludeOpNames && !OidIsValid(accessMethodForm->amgettuple))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("access method \"%s\" does not support exclusion constraints",
accessMethodName)));
amcanorder = accessMethodForm->amcanorder;
amoptions = accessMethodForm->amoptions;
ReleaseSysCache(tuple);
/*
* Validate predicate, if given
*/
if (stmt->whereClause)
CheckPredicate((Expr *) stmt->whereClause);
/*
* Parse AM-specific options, convert to text array form, validate.
*/
reloptions = transformRelOptions((Datum) 0, stmt->options,
NULL, NULL, false, false);
(void) index_reloptions(amoptions, reloptions, true);
/*
* Prepare arguments for index_create, primarily an IndexInfo structure.
* Note that ii_Predicate must be in implicit-AND format.
*/
indexInfo = makeNode(IndexInfo);
indexInfo->ii_NumIndexAttrs = numberOfAttributes;
indexInfo->ii_Expressions = NIL; /* for now */
indexInfo->ii_ExpressionsState = NIL;
indexInfo->ii_Predicate = make_ands_implicit((Expr *) stmt->whereClause);
indexInfo->ii_PredicateState = NIL;
indexInfo->ii_ExclusionOps = NULL;
indexInfo->ii_ExclusionProcs = NULL;
indexInfo->ii_ExclusionStrats = NULL;
indexInfo->ii_Unique = stmt->unique;
/* In a concurrent build, mark it not-ready-for-inserts */
indexInfo->ii_ReadyForInserts = !stmt->concurrent;
indexInfo->ii_Concurrent = stmt->concurrent;
indexInfo->ii_BrokenHotChain = false;
typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
ComputeIndexAttrs(indexInfo,
typeObjectId, collationObjectId, classObjectId,
coloptions, stmt->indexParams,
stmt->excludeOpNames, relationId,
accessMethodName, accessMethodId,
amcanorder, stmt->isconstraint);
/*
* Extra checks when creating a PRIMARY KEY index.
*/
if (stmt->primary)
index_check_primary_key(rel, indexInfo, is_alter_table);
/*
* Report index creation if appropriate (delay this till after most of the
* error checks)
*/
if (stmt->isconstraint && !quiet)
{
const char *constraint_type;
if (stmt->primary)
constraint_type = "PRIMARY KEY";
else if (stmt->unique)
constraint_type = "UNIQUE";
else if (stmt->excludeOpNames != NIL)
constraint_type = "EXCLUDE";
else
{
elog(ERROR, "unknown constraint type");
constraint_type = NULL; /* keep compiler quiet */
}
ereport(DEBUG1,
(errmsg("%s %s will create implicit index \"%s\" for table \"%s\"",
is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
constraint_type,
indexRelationName, RelationGetRelationName(rel))));
}
/*
* A valid stmt->oldNode implies that we already have a built form of the
* index. The caller should also decline any index build.
*/
Assert(!OidIsValid(stmt->oldNode) || (skip_build && !stmt->concurrent));
/*
* Make the catalog entries for the index, including constraints. Then, if
* not skip_build || concurrent, actually build the index.
*/
indexRelationId =
index_create(rel, indexRelationName, indexRelationId, stmt->oldNode,
indexInfo, indexColNames,
accessMethodId, tablespaceId,
collationObjectId, classObjectId,
coloptions, reloptions, stmt->primary,
stmt->isconstraint, stmt->deferrable, stmt->initdeferred,
allowSystemTableMods,
skip_build || stmt->concurrent,
stmt->concurrent, !check_rights);
/* Add any requested comment */
if (stmt->idxcomment != NULL)
CreateComments(indexRelationId, RelationRelationId, 0,
stmt->idxcomment);
if (!stmt->concurrent)
{
/* Close the heap and we're done, in the non-concurrent case */
heap_close(rel, NoLock);
return indexRelationId;
}
/* save lockrelid and locktag for below, then close rel */
heaprelid = rel->rd_lockInfo.lockRelId;
SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
heap_close(rel, NoLock);
/*
* For a concurrent build, it's important to make the catalog entries
* visible to other transactions before we start to build the index. That
* will prevent them from making incompatible HOT updates. The new index
* will be marked not indisready and not indisvalid, so that no one else
* tries to either insert into it or use it for queries.
*
* We must commit our current transaction so that the index becomes
* visible; then start another. Note that all the data structures we just
* built are lost in the commit. The only data we keep past here are the
* relation IDs.
*
* Before committing, get a session-level lock on the table, to ensure
* that neither it nor the index can be dropped before we finish. This
* cannot block, even if someone else is waiting for access, because we
* already have the same lock within our transaction.
*
* Note: we don't currently bother with a session lock on the index,
* because there are no operations that could change its state while we
* hold lock on the parent table. This might need to change later.
*/
LockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
PopActiveSnapshot();
CommitTransactionCommand();
StartTransactionCommand();
/*
* Phase 2 of concurrent index build (see comments for validate_index()
* for an overview of how this works)
*
* Now we must wait until no running transaction could have the table open
* with the old list of indexes. To do this, inquire which xacts
* currently would conflict with ShareLock on the table -- ie, which ones
* have a lock that permits writing the table. Then wait for each of
* these xacts to commit or abort. Note we do not need to worry about
* xacts that open the table for writing after this point; they will see
* the new index when they open it.
*
* Note: the reason we use actual lock acquisition here, rather than just
* checking the ProcArray and sleeping, is that deadlock is possible if
* one of the transactions in question is blocked trying to acquire an
* exclusive lock on our table. The lock code will detect deadlock and
* error out properly.
*
* Note: GetLockConflicts() never reports our own xid, hence we need not
* check for that. Also, prepared xacts are not reported, which is fine
* since they certainly aren't going to do anything more.
*/
old_lockholders = GetLockConflicts(&heaplocktag, ShareLock);
while (VirtualTransactionIdIsValid(*old_lockholders))
{
VirtualXactLock(*old_lockholders, true);
old_lockholders++;
}
/*
* At this moment we are sure that there are no transactions with the
* table open for write that don't have this new index in their list of
* indexes. We have waited out all the existing transactions and any new
* transaction will have the new index in its list, but the index is still
* marked as "not-ready-for-inserts". The index is consulted while
* deciding HOT-safety though. This arrangement ensures that no new HOT
* chains can be created where the new tuple and the old tuple in the
* chain have different index keys.
*
* We now take a new snapshot, and build the index using all tuples that
* are visible in this snapshot. We can be sure that any HOT updates to
* these tuples will be compatible with the index, since any updates made
* by transactions that didn't know about the index are now committed or
* rolled back. Thus, each visible tuple is either the end of its
* HOT-chain or the extension of the chain is HOT-safe for this index.
*/
/* Open and lock the parent heap relation */
rel = heap_openrv(stmt->relation, ShareUpdateExclusiveLock);
/* And the target index relation */
indexRelation = index_open(indexRelationId, RowExclusiveLock);
/* Set ActiveSnapshot since functions in the indexes may need it */
PushActiveSnapshot(GetTransactionSnapshot());
/* We have to re-build the IndexInfo struct, since it was lost in commit */
indexInfo = BuildIndexInfo(indexRelation);
Assert(!indexInfo->ii_ReadyForInserts);
indexInfo->ii_Concurrent = true;
indexInfo->ii_BrokenHotChain = false;
/* Now build the index */
index_build(rel, indexRelation, indexInfo, stmt->primary, false);
/* Close both the relations, but keep the locks */
heap_close(rel, NoLock);
index_close(indexRelation, NoLock);
/*
* Update the pg_index row to mark the index as ready for inserts. Once we
* commit this transaction, any new transactions that open the table must
* insert new entries into the index for insertions and non-HOT updates.
*/
index_set_state_flags(indexRelationId, INDEX_CREATE_SET_READY);
/* we can do away with our snapshot */
PopActiveSnapshot();
/*
* Commit this transaction to make the indisready update visible.
*/
CommitTransactionCommand();
StartTransactionCommand();
/*
* Phase 3 of concurrent index build
*
* We once again wait until no transaction can have the table open with
* the index marked as read-only for updates.
*/
old_lockholders = GetLockConflicts(&heaplocktag, ShareLock);
while (VirtualTransactionIdIsValid(*old_lockholders))
{
VirtualXactLock(*old_lockholders, true);
old_lockholders++;
}
/*
* Now take the "reference snapshot" that will be used by validate_index()
* to filter candidate tuples. Beware! There might still be snapshots in
* use that treat some transaction as in-progress that our reference
* snapshot treats as committed. If such a recently-committed transaction
* deleted tuples in the table, we will not include them in the index; yet
* those transactions which see the deleting one as still-in-progress will
* expect such tuples to be there once we mark the index as valid.
*
* We solve this by waiting for all endangered transactions to exit before
* we mark the index as valid.
*
* We also set ActiveSnapshot to this snap, since functions in indexes may
* need a snapshot.
*/
snapshot = RegisterSnapshot(GetTransactionSnapshot());
PushActiveSnapshot(snapshot);
/*
* Scan the index and the heap, insert any missing index entries.
*/
validate_index(relationId, indexRelationId, snapshot);
/*
* Drop the reference snapshot. We must do this before waiting out other
* snapshot holders, else we will deadlock against other processes also
* doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
* they must wait for. But first, save the snapshot's xmin to use as
* limitXmin for GetCurrentVirtualXIDs().
*/
limitXmin = snapshot->xmin;
PopActiveSnapshot();
UnregisterSnapshot(snapshot);
/*
* The index is now valid in the sense that it contains all currently
* interesting tuples. But since it might not contain tuples deleted just
* before the reference snap was taken, we have to wait out any
* transactions that might have older snapshots. Obtain a list of VXIDs
* of such transactions, and wait for them individually.
*
* We can exclude any running transactions that have xmin > the xmin of
* our reference snapshot; their oldest snapshot must be newer than ours.
* We can also exclude any transactions that have xmin = zero, since they
* evidently have no live snapshot at all (and any one they might be in
* process of taking is certainly newer than ours). Transactions in other
* DBs can be ignored too, since they'll never even be able to see this
* index.
*
* We can also exclude autovacuum processes and processes running manual
* lazy VACUUMs, because they won't be fazed by missing index entries
* either. (Manual ANALYZEs, however, can't be excluded because they
* might be within transactions that are going to do arbitrary operations
* later.)
*
* Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not
* check for that.
*
* If a process goes idle-in-transaction with xmin zero, we do not need to
* wait for it anymore, per the above argument. We do not have the
* infrastructure right now to stop waiting if that happens, but we can at
* least avoid the folly of waiting when it is idle at the time we would
* begin to wait. We do this by repeatedly rechecking the output of
* GetCurrentVirtualXIDs. If, during any iteration, a particular vxid
* doesn't show up in the output, we know we can forget about it.
*/
old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false,
PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
&n_old_snapshots);
for (i = 0; i < n_old_snapshots; i++)
{
if (!VirtualTransactionIdIsValid(old_snapshots[i]))
continue; /* found uninteresting in previous cycle */
if (i > 0)
{
/* see if anything's changed ... */
VirtualTransactionId *newer_snapshots;
int n_newer_snapshots;
int j;
int k;
newer_snapshots = GetCurrentVirtualXIDs(limitXmin,
true, false,
PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
&n_newer_snapshots);
for (j = i; j < n_old_snapshots; j++)
{
if (!VirtualTransactionIdIsValid(old_snapshots[j]))
continue; /* found uninteresting in previous cycle */
for (k = 0; k < n_newer_snapshots; k++)
{
if (VirtualTransactionIdEquals(old_snapshots[j],
newer_snapshots[k]))
break;
}
if (k >= n_newer_snapshots) /* not there anymore */
SetInvalidVirtualTransactionId(old_snapshots[j]);
}
pfree(newer_snapshots);
}
if (VirtualTransactionIdIsValid(old_snapshots[i]))
VirtualXactLock(old_snapshots[i], true);
}
/*
* Index can now be marked valid -- update its pg_index entry
*/
index_set_state_flags(indexRelationId, INDEX_CREATE_SET_VALID);
/*
* The pg_index update will cause backends (including this one) to update
* relcache entries for the index itself, but we should also send a
* relcache inval on the parent table to force replanning of cached plans.
* Otherwise existing sessions might fail to use the new index where it
* would be useful. (Note that our earlier commits did not create reasons
* to replan; so relcache flush on the index itself was sufficient.)
*/
CacheInvalidateRelcacheByRelid(heaprelid.relId);
/*
* Last thing to do is release the session-level lock on the parent table.
*/
UnlockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
return indexRelationId;
}
| Oid DefineOpClass | ( | CreateOpClassStmt * | stmt | ) |
Definition at line 324 of file opclasscmds.c.
References ACL_CREATE, ACL_KIND_NAMESPACE, ACL_KIND_OPER, ACL_KIND_PROC, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, addFamilyMember(), CreateOpClassStmt::amname, AMNAME, Anum_pg_opclass_opcdefault, Anum_pg_opclass_opcfamily, Anum_pg_opclass_opcintype, Anum_pg_opclass_opckeytype, Anum_pg_opclass_opcmethod, Anum_pg_opclass_opcname, Anum_pg_opclass_opcnamespace, Anum_pg_opclass_opcowner, CreateOpClassItem::args, Assert, assignOperTypes(), assignProcTypes(), BoolGetDatum, BTEqualStrategyNumber, BTREE_AM_OID, CatalogUpdateIndexes(), CLAAMNAMENSP, CreateOpClassItem::class_args, ObjectAddress::classId, CreateOpFamily(), CStringGetDatum, CreateOpClassStmt::datatype, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, get_func_name(), get_namespace_name(), get_opcode(), get_opfamily_oid(), get_opname(), GETSTRUCT, GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostCreateHook, IsA, CreateOpClassStmt::isDefault, CreateOpClassStmt::items, CreateOpClassItem::itemtype, OpFamilyMember::lefttype, lfirst, linitial, LookupFuncNameTypeNames(), LookupOperName(), LookupOperNameTypeNames(), lsecond, CreateOpClassItem::name, NameGetDatum, NameStr, namestrcpy(), NIL, NULL, OpFamilyMember::number, CreateOpClassItem::number, OpFamilyMember::object, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, OpclassAmNameNspIndexId, CreateOpClassStmt::opclassname, OperatorClassRelationId, OPFAMILYAMNAMENSP, CreateOpClassStmt::opfamilyname, CreateOpClassItem::order_family, palloc0(), pg_namespace_aclcheck(), pg_oper_ownercheck(), pg_proc_ownercheck(), pg_type_ownercheck(), PointerGetDatum, processTypesSpec(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), ReleaseSysCache(), OpFamilyMember::righttype, RowExclusiveLock, ScanKeyInit(), SearchSysCache1, SearchSysCache3, SearchSysCacheExists3, simple_heap_insert(), SnapshotNow, OpFamilyMember::sortfamily, CreateOpClassItem::storedtype, storeOperators(), storeProcedures(), superuser(), systable_beginscan(), systable_endscan(), systable_getnext(), TypeNameToString(), typenameTypeId(), and values.
Referenced by ProcessUtilitySlow().
{
char *opcname; /* name of opclass we're creating */
Oid amoid, /* our AM's oid */
typeoid, /* indexable datatype oid */
storageoid, /* storage datatype oid, if any */
namespaceoid, /* namespace to create opclass in */
opfamilyoid, /* oid of containing opfamily */
opclassoid; /* oid of opclass we create */
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
bool amstorage; /* amstorage flag */
List *operators; /* OpFamilyMember list for operators */
List *procedures; /* OpFamilyMember list for support procs */
ListCell *l;
Relation rel;
HeapTuple tup;
Form_pg_am pg_am;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
&opcname);
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceoid));
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
stmt->amname)));
amoid = HeapTupleGetOid(tup);
pg_am = (Form_pg_am) GETSTRUCT(tup);
maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
maxProcNumber = pg_am->amsupport;
amstorage = pg_am->amstorage;
/* XXX Should we make any privilege check against the AM? */
ReleaseSysCache(tup);
/*
* The question of appropriate permissions for CREATE OPERATOR CLASS is
* interesting. Creating an opclass is tantamount to granting public
* execute access on the functions involved, since the index machinery
* generally does not check access permission before using the functions.
* A minimum expectation therefore is that the caller have execute
* privilege with grant option. Since we don't have a way to make the
* opclass go away if the grant option is revoked, we choose instead to
* require ownership of the functions. It's also not entirely clear what
* permissions should be required on the datatype, but ownership seems
* like a safe choice.
*
* Currently, we require superuser privileges to create an opclass. This
* seems necessary because we have no way to validate that the offered set
* of operators and functions are consistent with the AM's expectations.
* It would be nice to provide such a check someday, if it can be done
* without solving the halting problem :-(
*
* XXX re-enable NOT_USED code sections below if you remove this test.
*/
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to create an operator class")));
/* Look up the datatype */
typeoid = typenameTypeId(NULL, stmt->datatype);
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
/* Check we have ownership of the datatype */
if (!pg_type_ownercheck(typeoid, GetUserId()))
aclcheck_error_type(ACLCHECK_NOT_OWNER, typeoid);
#endif
/*
* Look up the containing operator family, or create one if FAMILY option
* was omitted and there's not a match already.
*/
if (stmt->opfamilyname)
{
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
}
else
{
/* Lookup existing family of same name and namespace */
tup = SearchSysCache3(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amoid),
PointerGetDatum(opcname),
ObjectIdGetDatum(namespaceoid));
if (HeapTupleIsValid(tup))
{
opfamilyoid = HeapTupleGetOid(tup);
/*
* XXX given the superuser check above, there's no need for an
* ownership check here
*/
ReleaseSysCache(tup);
}
else
{
/*
* Create it ... again no need for more permissions ...
*/
opfamilyoid = CreateOpFamily(stmt->amname, opcname,
namespaceoid, amoid);
}
}
operators = NIL;
procedures = NIL;
/* Storage datatype is optional */
storageoid = InvalidOid;
/*
* Scan the "items" list to obtain additional info.
*/
foreach(l, stmt->items)
{
CreateOpClassItem *item = lfirst(l);
Oid operOid;
Oid funcOid;
Oid sortfamilyOid;
OpFamilyMember *member;
Assert(IsA(item, CreateOpClassItem));
switch (item->itemtype)
{
case OPCLASS_ITEM_OPERATOR:
if (item->number <= 0 || item->number > maxOpNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid operator number %d,"
" must be between 1 and %d",
item->number, maxOpNumber)));
if (item->args != NIL)
{
TypeName *typeName1 = (TypeName *) linitial(item->args);
TypeName *typeName2 = (TypeName *) lsecond(item->args);
operOid = LookupOperNameTypeNames(NULL, item->name,
typeName1, typeName2,
false, -1);
}
else
{
/* Default to binary op on input datatype */
operOid = LookupOperName(NULL, item->name,
typeoid, typeoid,
false, -1);
}
if (item->order_family)
sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
item->order_family,
false);
else
sortfamilyOid = InvalidOid;
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
/* Caller must own operator and its underlying function */
if (!pg_oper_ownercheck(operOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
get_opname(operOid));
funcOid = get_opcode(operOid);
if (!pg_proc_ownercheck(funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
get_func_name(funcOid));
#endif
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = operOid;
member->number = item->number;
member->sortfamily = sortfamilyOid;
assignOperTypes(member, amoid, typeoid);
addFamilyMember(&operators, member, false);
break;
case OPCLASS_ITEM_FUNCTION:
if (item->number <= 0 || item->number > maxProcNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid procedure number %d,"
" must be between 1 and %d",
item->number, maxProcNumber)));
funcOid = LookupFuncNameTypeNames(item->name, item->args,
false);
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
/* Caller must own function */
if (!pg_proc_ownercheck(funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
get_func_name(funcOid));
#endif
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = funcOid;
member->number = item->number;
/* allow overriding of the function's actual arg types */
if (item->class_args)
processTypesSpec(item->class_args,
&member->lefttype, &member->righttype);
assignProcTypes(member, amoid, typeoid);
addFamilyMember(&procedures, member, true);
break;
case OPCLASS_ITEM_STORAGETYPE:
if (OidIsValid(storageoid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("storage type specified more than once")));
storageoid = typenameTypeId(NULL, item->storedtype);
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
/* Check we have ownership of the datatype */
if (!pg_type_ownercheck(storageoid, GetUserId()))
aclcheck_error_type(ACLCHECK_NOT_OWNER, storageoid);
#endif
break;
default:
elog(ERROR, "unrecognized item type: %d", item->itemtype);
break;
}
}
/*
* If storagetype is specified, make sure it's legal.
*/
if (OidIsValid(storageoid))
{
/* Just drop the spec if same as column datatype */
if (storageoid == typeoid)
storageoid = InvalidOid;
else if (!amstorage)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("storage type cannot be different from data type for access method \"%s\"",
stmt->amname)));
}
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
/*
* Make sure there is no existing opclass of this name (this is just to
* give a more friendly error message than "duplicate key").
*/
if (SearchSysCacheExists3(CLAAMNAMENSP,
ObjectIdGetDatum(amoid),
CStringGetDatum(opcname),
ObjectIdGetDatum(namespaceoid)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator class \"%s\" for access method \"%s\" already exists",
opcname, stmt->amname)));
/*
* If we are creating a default opclass, check there isn't one already.
* (Note we do not restrict this test to visible opclasses; this ensures
* that typcache.c can find unique solutions to its questions.)
*/
if (stmt->isDefault)
{
ScanKeyData skey[1];
SysScanDesc scan;
ScanKeyInit(&skey[0],
Anum_pg_opclass_opcmethod,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(amoid));
scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
SnapshotNow, 1, skey);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
if (opclass->opcintype == typeoid && opclass->opcdefault)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("could not make operator class \"%s\" be default for type %s",
opcname,
TypeNameToString(stmt->datatype)),
errdetail("Operator class \"%s\" already is the default.",
NameStr(opclass->opcname))));
}
systable_endscan(scan);
}
/*
* Okay, let's create the pg_opclass entry.
*/
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
namestrcpy(&opcName, opcname);
values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
tup = heap_form_tuple(rel->rd_att, values, nulls);
opclassoid = simple_heap_insert(rel, tup);
CatalogUpdateIndexes(rel, tup);
heap_freetuple(tup);
/*
* Now add tuples to pg_amop and pg_amproc tying in the operators and
* functions. Dependencies on them are inserted, too.
*/
storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
opclassoid, operators, false);
storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
opclassoid, procedures, false);
/*
* Create dependencies for the opclass proper. Note: we do not create a
* dependency link to the AM, because we don't currently support DROP
* ACCESS METHOD.
*/
myself.classId = OperatorClassRelationId;
myself.objectId = opclassoid;
myself.objectSubId = 0;
/* dependency on namespace */
referenced.classId = NamespaceRelationId;
referenced.objectId = namespaceoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on opfamily */
referenced.classId = OperatorFamilyRelationId;
referenced.objectId = opfamilyoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
/* dependency on indexed datatype */
referenced.classId = TypeRelationId;
referenced.objectId = typeoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on storage datatype */
if (OidIsValid(storageoid))
{
referenced.classId = TypeRelationId;
referenced.objectId = storageoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* dependency on owner */
recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
/* dependency on extension */
recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new operator class */
InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
heap_close(rel, RowExclusiveLock);
return opclassoid;
}
Definition at line 63 of file operatorcmds.c.
References ACL_CREATE, ACL_EXECUTE, ACL_KIND_NAMESPACE, ACL_KIND_PROC, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, defGetBoolean(), defGetQualifiedName(), defGetTypeName(), DefElem::defname, ereport, errcode(), errdetail(), errmsg(), ERROR, FLOAT8OID, get_func_rettype(), get_namespace_name(), GetUserId(), lfirst, LookupFuncName(), NameListToString(), NIL, NULL, OidIsValid, OperatorCreate(), pg_namespace_aclcheck(), pg_proc_aclcheck(), pg_strcasecmp(), pg_type_aclcheck(), QualifiedNameGetCreationNamespace(), TypeName::setof, typenameTypeId(), and WARNING.
Referenced by ProcessUtilitySlow().
{
char *oprName;
Oid oprNamespace;
AclResult aclresult;
bool canMerge = false; /* operator merges */
bool canHash = false; /* operator hashes */
List *functionName = NIL; /* function for operator */
TypeName *typeName1 = NULL; /* first type name */
TypeName *typeName2 = NULL; /* second type name */
Oid typeId1 = InvalidOid; /* types converted to OID */
Oid typeId2 = InvalidOid;
Oid rettype;
List *commutatorName = NIL; /* optional commutator operator name */
List *negatorName = NIL; /* optional negator operator name */
List *restrictionName = NIL; /* optional restrict. sel. procedure */
List *joinName = NIL; /* optional join sel. procedure */
Oid functionOid; /* functions converted to OID */
Oid restrictionOid;
Oid joinOid;
Oid typeId[5]; /* only need up to 5 args here */
int nargs;
ListCell *pl;
/* Convert list of names to a name and namespace */
oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
/*
* The SQL standard committee has decided that => should be used for named
* parameters; therefore, a future release of PostgreSQL may disallow it
* as the name of a user-defined operator.
*/
if (strcmp(oprName, "=>") == 0)
ereport(WARNING,
(errmsg("=> is deprecated as an operator name"),
errdetail("This name may be disallowed altogether in future versions of PostgreSQL.")));
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(oprNamespace));
/*
* loop over the definition list and extract the information we need.
*/
foreach(pl, parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
if (pg_strcasecmp(defel->defname, "leftarg") == 0)
{
typeName1 = defGetTypeName(defel);
if (typeName1->setof)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
{
typeName2 = defGetTypeName(defel);
if (typeName2->setof)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
}
else if (pg_strcasecmp(defel->defname, "procedure") == 0)
functionName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "commutator") == 0)
commutatorName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "negator") == 0)
negatorName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "restrict") == 0)
restrictionName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "join") == 0)
joinName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "hashes") == 0)
canHash = defGetBoolean(defel);
else if (pg_strcasecmp(defel->defname, "merges") == 0)
canMerge = defGetBoolean(defel);
/* These obsolete options are taken as meaning canMerge */
else if (pg_strcasecmp(defel->defname, "sort1") == 0)
canMerge = true;
else if (pg_strcasecmp(defel->defname, "sort2") == 0)
canMerge = true;
else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
canMerge = true;
else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
canMerge = true;
else
ereport(WARNING,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("operator attribute \"%s\" not recognized",
defel->defname)));
}
/*
* make sure we have our required definitions
*/
if (functionName == NIL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("operator procedure must be specified")));
/* Transform type names to type OIDs */
if (typeName1)
typeId1 = typenameTypeId(NULL, typeName1);
if (typeName2)
typeId2 = typenameTypeId(NULL, typeName2);
if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("at least one of leftarg or rightarg must be specified")));
if (typeName1)
{
aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error_type(aclresult, typeId1);
}
if (typeName2)
{
aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error_type(aclresult, typeId2);
}
/*
* Look up the operator's underlying function.
*/
if (!OidIsValid(typeId1))
{
typeId[0] = typeId2;
nargs = 1;
}
else if (!OidIsValid(typeId2))
{
typeId[0] = typeId1;
nargs = 1;
}
else
{
typeId[0] = typeId1;
typeId[1] = typeId2;
nargs = 2;
}
functionOid = LookupFuncName(functionName, nargs, typeId, false);
/*
* We require EXECUTE rights for the function. This isn't strictly
* necessary, since EXECUTE will be checked at any attempted use of the
* operator, but it seems like a good idea anyway.
*/
aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
NameListToString(functionName));
rettype = get_func_rettype(functionOid);
aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error_type(aclresult, rettype);
/*
* Look up restriction estimator if specified
*/
if (restrictionName)
{
typeId[0] = INTERNALOID; /* PlannerInfo */
typeId[1] = OIDOID; /* operator OID */
typeId[2] = INTERNALOID; /* args list */
typeId[3] = INT4OID; /* varRelid */
restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
/* estimators must return float8 */
if (get_func_rettype(restrictionOid) != FLOAT8OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("restriction estimator function %s must return type \"float8\"",
NameListToString(restrictionName))));
/* Require EXECUTE rights for the estimator */
aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
NameListToString(restrictionName));
}
else
restrictionOid = InvalidOid;
/*
* Look up join estimator if specified
*/
if (joinName)
{
typeId[0] = INTERNALOID; /* PlannerInfo */
typeId[1] = OIDOID; /* operator OID */
typeId[2] = INTERNALOID; /* args list */
typeId[3] = INT2OID; /* jointype */
typeId[4] = INTERNALOID; /* SpecialJoinInfo */
/*
* As of Postgres 8.4, the preferred signature for join estimators has
* 5 arguments, but we still allow the old 4-argument form. Try the
* preferred form first.
*/
joinOid = LookupFuncName(joinName, 5, typeId, true);
if (!OidIsValid(joinOid))
joinOid = LookupFuncName(joinName, 4, typeId, true);
/* If not found, reference the 5-argument signature in error msg */
if (!OidIsValid(joinOid))
joinOid = LookupFuncName(joinName, 5, typeId, false);
/* estimators must return float8 */
if (get_func_rettype(joinOid) != FLOAT8OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("join estimator function %s must return type \"float8\"",
NameListToString(joinName))));
/* Require EXECUTE rights for the estimator */
aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
NameListToString(joinName));
}
else
joinOid = InvalidOid;
/*
* now have OperatorCreate do all the work..
*/
return
OperatorCreate(oprName, /* operator name */
oprNamespace, /* namespace */
typeId1, /* left type id */
typeId2, /* right type id */
functionOid, /* function for operator */
commutatorName, /* optional commutator operator name */
negatorName, /* optional negator operator name */
restrictionOid, /* optional restrict. sel. procedure */
joinOid, /* optional join sel. procedure name */
canMerge, /* operator merges */
canHash); /* operator hashes */
}
| Oid DefineOpFamily | ( | CreateOpFamilyStmt * | stmt | ) |
Definition at line 725 of file opclasscmds.c.
References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, CreateOpFamilyStmt::amname, CreateOpFamily(), ereport, errcode(), errmsg(), ERROR, get_am_oid(), get_namespace_name(), GetUserId(), CreateOpFamilyStmt::opfamilyname, pg_namespace_aclcheck(), QualifiedNameGetCreationNamespace(), and superuser().
Referenced by ProcessUtilitySlow().
{
char *opfname; /* name of opfamily we're creating */
Oid amoid, /* our AM's oid */
namespaceoid; /* namespace to create opfamily in */
AclResult aclresult;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
&opfname);
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceoid));
/* Get access method OID, throwing an error if it doesn't exist. */
amoid = get_am_oid(stmt->amname, false);
/* XXX Should we make any privilege check against the AM? */
/*
* Currently, we require superuser privileges to create an opfamily. See
* comments in DefineOpClass.
*/
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to create an operator family")));
/* Insert pg_opfamily catalog entry */
return CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
}
Definition at line 949 of file tsearchcmds.c.
References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, Anum_pg_ts_config_cfgname, Anum_pg_ts_config_cfgnamespace, Anum_pg_ts_config_cfgowner, Anum_pg_ts_config_cfgparser, Anum_pg_ts_config_map_mapcfg, Anum_pg_ts_config_map_mapdict, Anum_pg_ts_config_map_mapseqno, Anum_pg_ts_config_map_maptokentype, BTEqualStrategyNumber, CatalogUpdateIndexes(), defGetQualifiedName(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, get_namespace_name(), get_ts_config_oid(), get_ts_parser_oid(), GETSTRUCT, GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), HeapTupleIsValid, InvokeObjectPostCreateHook, lfirst, makeConfigurationDependencies(), NameGetDatum, namestrcpy(), ObjectIdGetDatum, OidIsValid, pg_namespace_aclcheck(), pg_strcasecmp(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1, simple_heap_insert(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), TSConfigMapIndexId, TSConfigMapRelationId, TSCONFIGOID, TSConfigRelationId, and values.
Referenced by ProcessUtilitySlow().
{
Relation cfgRel;
Relation mapRel = NULL;
HeapTuple tup;
Datum values[Natts_pg_ts_config];
bool nulls[Natts_pg_ts_config];
AclResult aclresult;
Oid namespaceoid;
char *cfgname;
NameData cname;
Oid sourceOid = InvalidOid;
Oid prsOid = InvalidOid;
Oid cfgOid;
ListCell *pl;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceoid));
/*
* loop over the definition list and extract the information we need.
*/
foreach(pl, parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
if (pg_strcasecmp(defel->defname, "parser") == 0)
prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
else if (pg_strcasecmp(defel->defname, "copy") == 0)
sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("text search configuration parameter \"%s\" not recognized",
defel->defname)));
}
if (OidIsValid(sourceOid) && OidIsValid(prsOid))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("cannot specify both PARSER and COPY options")));
/*
* Look up source config if given.
*/
if (OidIsValid(sourceOid))
{
Form_pg_ts_config cfg;
tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(sourceOid));
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search configuration %u",
sourceOid);
cfg = (Form_pg_ts_config) GETSTRUCT(tup);
/* use source's parser */
prsOid = cfg->cfgparser;
ReleaseSysCache(tup);
}
/*
* Validation
*/
if (!OidIsValid(prsOid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("text search parser is required")));
/*
* Looks good, build tuple and insert
*/
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
namestrcpy(&cname, cfgname);
values[Anum_pg_ts_config_cfgname - 1] = NameGetDatum(&cname);
values[Anum_pg_ts_config_cfgnamespace - 1] = ObjectIdGetDatum(namespaceoid);
values[Anum_pg_ts_config_cfgowner - 1] = ObjectIdGetDatum(GetUserId());
values[Anum_pg_ts_config_cfgparser - 1] = ObjectIdGetDatum(prsOid);
cfgRel = heap_open(TSConfigRelationId, RowExclusiveLock);
tup = heap_form_tuple(cfgRel->rd_att, values, nulls);
cfgOid = simple_heap_insert(cfgRel, tup);
CatalogUpdateIndexes(cfgRel, tup);
if (OidIsValid(sourceOid))
{
/*
* Copy token-dicts map from source config
*/
ScanKeyData skey;
SysScanDesc scan;
HeapTuple maptup;
mapRel = heap_open(TSConfigMapRelationId, RowExclusiveLock);
ScanKeyInit(&skey,
Anum_pg_ts_config_map_mapcfg,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(sourceOid));
scan = systable_beginscan(mapRel, TSConfigMapIndexId, true,
SnapshotNow, 1, &skey);
while (HeapTupleIsValid((maptup = systable_getnext(scan))))
{
Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);
HeapTuple newmaptup;
Datum mapvalues[Natts_pg_ts_config_map];
bool mapnulls[Natts_pg_ts_config_map];
memset(mapvalues, 0, sizeof(mapvalues));
memset(mapnulls, false, sizeof(mapnulls));
mapvalues[Anum_pg_ts_config_map_mapcfg - 1] = cfgOid;
mapvalues[Anum_pg_ts_config_map_maptokentype - 1] = cfgmap->maptokentype;
mapvalues[Anum_pg_ts_config_map_mapseqno - 1] = cfgmap->mapseqno;
mapvalues[Anum_pg_ts_config_map_mapdict - 1] = cfgmap->mapdict;
newmaptup = heap_form_tuple(mapRel->rd_att, mapvalues, mapnulls);
simple_heap_insert(mapRel, newmaptup);
CatalogUpdateIndexes(mapRel, newmaptup);
heap_freetuple(newmaptup);
}
systable_endscan(scan);
}
makeConfigurationDependencies(tup, false, mapRel);
/* Post creation hook for new text search configuration */
InvokeObjectPostCreateHook(TSConfigRelationId, cfgOid, 0);
heap_freetuple(tup);
if (mapRel)
heap_close(mapRel, RowExclusiveLock);
heap_close(cfgRel, RowExclusiveLock);
return cfgOid;
}
Definition at line 401 of file tsearchcmds.c.
References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, Anum_pg_ts_dict_dictinitoption, Anum_pg_ts_dict_dictname, Anum_pg_ts_dict_dictnamespace, Anum_pg_ts_dict_dictowner, Anum_pg_ts_dict_dicttemplate, CatalogUpdateIndexes(), defGetQualifiedName(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, get_namespace_name(), get_ts_template_oid(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, lappend(), lfirst, makeDictionaryDependencies(), NameGetDatum, namestrcpy(), ObjectIdGetDatum, OidIsValid, pg_namespace_aclcheck(), pg_strcasecmp(), PointerGetDatum, QualifiedNameGetCreationNamespace(), RelationData::rd_att, RowExclusiveLock, serialize_deflist(), simple_heap_insert(), TSDictionaryRelationId, values, and verify_dictoptions().
Referenced by ProcessUtilitySlow().
{
ListCell *pl;
Relation dictRel;
HeapTuple tup;
Datum values[Natts_pg_ts_dict];
bool nulls[Natts_pg_ts_dict];
NameData dname;
Oid templId = InvalidOid;
List *dictoptions = NIL;
Oid dictOid;
Oid namespaceoid;
AclResult aclresult;
char *dictname;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceoid));
/*
* loop over the definition list and extract the information we need.
*/
foreach(pl, parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
if (pg_strcasecmp(defel->defname, "template") == 0)
{
templId = get_ts_template_oid(defGetQualifiedName(defel), false);
}
else
{
/* Assume it's an option for the dictionary itself */
dictoptions = lappend(dictoptions, defel);
}
}
/*
* Validation
*/
if (!OidIsValid(templId))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("text search template is required")));
verify_dictoptions(templId, dictoptions);
/*
* Looks good, insert
*/
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
namestrcpy(&dname, dictname);
values[Anum_pg_ts_dict_dictname - 1] = NameGetDatum(&dname);
values[Anum_pg_ts_dict_dictnamespace - 1] = ObjectIdGetDatum(namespaceoid);
values[Anum_pg_ts_dict_dictowner - 1] = ObjectIdGetDatum(GetUserId());
values[Anum_pg_ts_dict_dicttemplate - 1] = ObjectIdGetDatum(templId);
if (dictoptions)
values[Anum_pg_ts_dict_dictinitoption - 1] =
PointerGetDatum(serialize_deflist(dictoptions));
else
nulls[Anum_pg_ts_dict_dictinitoption - 1] = true;
dictRel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
tup = heap_form_tuple(dictRel->rd_att, values, nulls);
dictOid = simple_heap_insert(dictRel, tup);
CatalogUpdateIndexes(dictRel, tup);
makeDictionaryDependencies(tup);
/* Post creation hook for new text search dictionary */
InvokeObjectPostCreateHook(TSDictionaryRelationId, dictOid, 0);
heap_freetuple(tup);
heap_close(dictRel, RowExclusiveLock);
return dictOid;
}
Definition at line 171 of file tsearchcmds.c.
References Anum_pg_ts_parser_prsend, Anum_pg_ts_parser_prsheadline, Anum_pg_ts_parser_prslextype, Anum_pg_ts_parser_prsname, Anum_pg_ts_parser_prsnamespace, Anum_pg_ts_parser_prsstart, Anum_pg_ts_parser_prstoken, CatalogUpdateIndexes(), DatumGetObjectId, DefElem::defname, ereport, errcode(), errmsg(), ERROR, get_ts_parser_func(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, lfirst, makeParserDependencies(), NameGetDatum, namestrcpy(), ObjectIdGetDatum, OidIsValid, pg_strcasecmp(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, RowExclusiveLock, simple_heap_insert(), superuser(), TSParserRelationId, and values.
Referenced by ProcessUtilitySlow().
{
char *prsname;
ListCell *pl;
Relation prsRel;
HeapTuple tup;
Datum values[Natts_pg_ts_parser];
bool nulls[Natts_pg_ts_parser];
NameData pname;
Oid prsOid;
Oid namespaceoid;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to create text search parsers")));
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
/* initialize tuple fields with name/namespace */
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
namestrcpy(&pname, prsname);
values[Anum_pg_ts_parser_prsname - 1] = NameGetDatum(&pname);
values[Anum_pg_ts_parser_prsnamespace - 1] = ObjectIdGetDatum(namespaceoid);
/*
* loop over the definition list and extract the information we need.
*/
foreach(pl, parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
if (pg_strcasecmp(defel->defname, "start") == 0)
{
values[Anum_pg_ts_parser_prsstart - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
}
else if (pg_strcasecmp(defel->defname, "gettoken") == 0)
{
values[Anum_pg_ts_parser_prstoken - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
}
else if (pg_strcasecmp(defel->defname, "end") == 0)
{
values[Anum_pg_ts_parser_prsend - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
}
else if (pg_strcasecmp(defel->defname, "headline") == 0)
{
values[Anum_pg_ts_parser_prsheadline - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
}
else if (pg_strcasecmp(defel->defname, "lextypes") == 0)
{
values[Anum_pg_ts_parser_prslextype - 1] =
get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
}
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("text search parser parameter \"%s\" not recognized",
defel->defname)));
}
/*
* Validation
*/
if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsstart - 1])))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("text search parser start method is required")));
if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prstoken - 1])))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("text search parser gettoken method is required")));
if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsend - 1])))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("text search parser end method is required")));
if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prslextype - 1])))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("text search parser lextypes method is required")));
/*
* Looks good, insert
*/
prsRel = heap_open(TSParserRelationId, RowExclusiveLock);
tup = heap_form_tuple(prsRel->rd_att, values, nulls);
prsOid = simple_heap_insert(prsRel, tup);
CatalogUpdateIndexes(prsRel, tup);
makeParserDependencies(tup);
/* Post creation hook for new text search parser */
InvokeObjectPostCreateHook(TSParserRelationId, prsOid, 0);
heap_freetuple(tup);
heap_close(prsRel, RowExclusiveLock);
return prsOid;
}
Definition at line 719 of file tsearchcmds.c.
References Anum_pg_ts_template_tmplinit, Anum_pg_ts_template_tmpllexize, Anum_pg_ts_template_tmplname, Anum_pg_ts_template_tmplnamespace, CatalogUpdateIndexes(), DatumGetObjectId, DefElem::defname, ereport, errcode(), errmsg(), ERROR, get_ts_template_func(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), i, InvalidOid, InvokeObjectPostCreateHook, lfirst, makeTSTemplateDependencies(), NameGetDatum, namestrcpy(), ObjectIdGetDatum, OidIsValid, pg_strcasecmp(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, RowExclusiveLock, simple_heap_insert(), superuser(), TSTemplateRelationId, and values.
Referenced by ProcessUtilitySlow().
{
ListCell *pl;
Relation tmplRel;
HeapTuple tup;
Datum values[Natts_pg_ts_template];
bool nulls[Natts_pg_ts_template];
NameData dname;
int i;
Oid tmplOid;
Oid namespaceoid;
char *tmplname;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to create text search templates")));
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
for (i = 0; i < Natts_pg_ts_template; i++)
{
nulls[i] = false;
values[i] = ObjectIdGetDatum(InvalidOid);
}
namestrcpy(&dname, tmplname);
values[Anum_pg_ts_template_tmplname - 1] = NameGetDatum(&dname);
values[Anum_pg_ts_template_tmplnamespace - 1] = ObjectIdGetDatum(namespaceoid);
/*
* loop over the definition list and extract the information we need.
*/
foreach(pl, parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
if (pg_strcasecmp(defel->defname, "init") == 0)
{
values[Anum_pg_ts_template_tmplinit - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
nulls[Anum_pg_ts_template_tmplinit - 1] = false;
}
else if (pg_strcasecmp(defel->defname, "lexize") == 0)
{
values[Anum_pg_ts_template_tmpllexize - 1] =
get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
nulls[Anum_pg_ts_template_tmpllexize - 1] = false;
}
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("text search template parameter \"%s\" not recognized",
defel->defname)));
}
/*
* Validation
*/
if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_template_tmpllexize - 1])))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("text search template lexize method is required")));
/*
* Looks good, insert
*/
tmplRel = heap_open(TSTemplateRelationId, RowExclusiveLock);
tup = heap_form_tuple(tmplRel->rd_att, values, nulls);
tmplOid = simple_heap_insert(tmplRel, tup);
CatalogUpdateIndexes(tmplRel, tup);
makeTSTemplateDependencies(tup);
/* Post creation hook for new text search template */
InvokeObjectPostCreateHook(TSTemplateRelationId, tmplOid, 0);
heap_freetuple(tup);
heap_close(tmplRel, RowExclusiveLock);
return tmplOid;
}
Definition at line 308 of file define.c.
References makeDefElem(), and makeInteger().
{
return makeDefElem("oids", (Node *) makeInteger(value));
}
Definition at line 1542 of file tsearchcmds.c.
References DatumGetTextP, elog, ereport, errcode(), errmsg(), ERROR, lappend(), makeDefElem(), makeString(), palloc(), pfree(), pstrdup(), text_to_cstring(), VARDATA, and VARSIZE.
Referenced by AlterTSDictionary(), lookup_ts_dictionary_cache(), and ts_headline_byid_opt().
{
text *in = DatumGetTextP(txt); /* in case it's toasted */
List *result = NIL;
int len = VARSIZE(in) - VARHDRSZ;
char *ptr,
*endptr,
*workspace,
*wsptr = NULL,
*startvalue = NULL;
typedef enum
{
CS_WAITKEY,
CS_INKEY,
CS_INQKEY,
CS_WAITEQ,
CS_WAITVALUE,
CS_INSQVALUE,
CS_INDQVALUE,
CS_INWVALUE
} ds_state;
ds_state state = CS_WAITKEY;
workspace = (char *) palloc(len + 1); /* certainly enough room */
ptr = VARDATA(in);
endptr = ptr + len;
for (; ptr < endptr; ptr++)
{
switch (state)
{
case CS_WAITKEY:
if (isspace((unsigned char) *ptr) || *ptr == ',')
continue;
if (*ptr == '"')
{
wsptr = workspace;
state = CS_INQKEY;
}
else
{
wsptr = workspace;
*wsptr++ = *ptr;
state = CS_INKEY;
}
break;
case CS_INKEY:
if (isspace((unsigned char) *ptr))
{
*wsptr++ = '\0';
state = CS_WAITEQ;
}
else if (*ptr == '=')
{
*wsptr++ = '\0';
state = CS_WAITVALUE;
}
else
{
*wsptr++ = *ptr;
}
break;
case CS_INQKEY:
if (*ptr == '"')
{
if (ptr + 1 < endptr && ptr[1] == '"')
{
/* copy only one of the two quotes */
*wsptr++ = *ptr++;
}
else
{
*wsptr++ = '\0';
state = CS_WAITEQ;
}
}
else
{
*wsptr++ = *ptr;
}
break;
case CS_WAITEQ:
if (*ptr == '=')
state = CS_WAITVALUE;
else if (!isspace((unsigned char) *ptr))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid parameter list format: \"%s\"",
text_to_cstring(in))));
break;
case CS_WAITVALUE:
if (*ptr == '\'')
{
startvalue = wsptr;
state = CS_INSQVALUE;
}
else if (*ptr == 'E' && ptr + 1 < endptr && ptr[1] == '\'')
{
ptr++;
startvalue = wsptr;
state = CS_INSQVALUE;
}
else if (*ptr == '"')
{
startvalue = wsptr;
state = CS_INDQVALUE;
}
else if (!isspace((unsigned char) *ptr))
{
startvalue = wsptr;
*wsptr++ = *ptr;
state = CS_INWVALUE;
}
break;
case CS_INSQVALUE:
if (*ptr == '\'')
{
if (ptr + 1 < endptr && ptr[1] == '\'')
{
/* copy only one of the two quotes */
*wsptr++ = *ptr++;
}
else
{
*wsptr++ = '\0';
result = lappend(result,
makeDefElem(pstrdup(workspace),
(Node *) makeString(pstrdup(startvalue))));
state = CS_WAITKEY;
}
}
else if (*ptr == '\\')
{
if (ptr + 1 < endptr && ptr[1] == '\\')
{
/* copy only one of the two backslashes */
*wsptr++ = *ptr++;
}
else
*wsptr++ = *ptr;
}
else
{
*wsptr++ = *ptr;
}
break;
case CS_INDQVALUE:
if (*ptr == '"')
{
if (ptr + 1 < endptr && ptr[1] == '"')
{
/* copy only one of the two quotes */
*wsptr++ = *ptr++;
}
else
{
*wsptr++ = '\0';
result = lappend(result,
makeDefElem(pstrdup(workspace),
(Node *) makeString(pstrdup(startvalue))));
state = CS_WAITKEY;
}
}
else
{
*wsptr++ = *ptr;
}
break;
case CS_INWVALUE:
if (*ptr == ',' || isspace((unsigned char) *ptr))
{
*wsptr++ = '\0';
result = lappend(result,
makeDefElem(pstrdup(workspace),
(Node *) makeString(pstrdup(startvalue))));
state = CS_WAITKEY;
}
else
{
*wsptr++ = *ptr;
}
break;
default:
elog(ERROR, "unrecognized deserialize_deflist state: %d",
state);
}
}
if (state == CS_INWVALUE)
{
*wsptr++ = '\0';
result = lappend(result,
makeDefElem(pstrdup(workspace),
(Node *) makeString(pstrdup(startvalue))));
}
else if (state != CS_WAITKEY)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid parameter list format: \"%s\"",
text_to_cstring(in))));
pfree(workspace);
return result;
}
| void DropCastById | ( | Oid | castOid | ) |
Definition at line 1596 of file functioncmds.c.
References BTEqualStrategyNumber, CastOidIndexId, CastRelationId, elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdAttributeNumber, ObjectIdGetDatum, RowExclusiveLock, ScanKeyInit(), simple_heap_delete(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.
Referenced by doDeletion().
{
Relation relation;
ScanKeyData scankey;
SysScanDesc scan;
HeapTuple tuple;
relation = heap_open(CastRelationId, RowExclusiveLock);
ScanKeyInit(&scankey,
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(castOid));
scan = systable_beginscan(relation, CastOidIndexId, true,
SnapshotNow, 1, &scankey);
tuple = systable_getnext(scan);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "could not find tuple for cast %u", castOid);
simple_heap_delete(relation, &tuple->t_self);
systable_endscan(scan);
heap_close(relation, RowExclusiveLock);
}
| void ExecuteDoStmt | ( | DoStmt * | stmt | ) |
Definition at line 1649 of file functioncmds.c.
References ACL_KIND_LANGUAGE, ACL_USAGE, aclcheck_error(), ACLCHECK_NO_PRIV, ACLCHECK_OK, DefElem::arg, arg, DoStmt::args, DefElem::defname, elog, ereport, errcode(), errhint(), errmsg(), ERROR, GETSTRUCT, GetUserId(), HeapTupleGetOid, HeapTupleIsValid, InlineCodeBlock::langIsTrusted, LANGNAME, InlineCodeBlock::langOid, lfirst, makeNode, NameStr, OidFunctionCall1, OidIsValid, pg_language_aclcheck(), PLTemplateExists(), PointerGetDatum, ReleaseSysCache(), SearchSysCache1, InlineCodeBlock::source_text, strVal, and superuser().
Referenced by standard_ProcessUtility().
{
InlineCodeBlock *codeblock = makeNode(InlineCodeBlock);
ListCell *arg;
DefElem *as_item = NULL;
DefElem *language_item = NULL;
char *language;
Oid laninline;
HeapTuple languageTuple;
Form_pg_language languageStruct;
/* Process options we got from gram.y */
foreach(arg, stmt->args)
{
DefElem *defel = (DefElem *) lfirst(arg);
if (strcmp(defel->defname, "as") == 0)
{
if (as_item)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
as_item = defel;
}
else if (strcmp(defel->defname, "language") == 0)
{
if (language_item)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
language_item = defel;
}
else
elog(ERROR, "option \"%s\" not recognized",
defel->defname);
}
if (as_item)
codeblock->source_text = strVal(as_item->arg);
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("no inline code specified")));
/* if LANGUAGE option wasn't specified, use the default */
if (language_item)
language = strVal(language_item->arg);
else
language = "plpgsql";
/* Look up the language and validate permissions */
languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
if (!HeapTupleIsValid(languageTuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("language \"%s\" does not exist", language),
(PLTemplateExists(language) ?
errhint("Use CREATE LANGUAGE to load the language into the database.") : 0)));
codeblock->langOid = HeapTupleGetOid(languageTuple);
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
codeblock->langIsTrusted = languageStruct->lanpltrusted;
if (languageStruct->lanpltrusted)
{
/* if trusted language, need USAGE privilege */
AclResult aclresult;
aclresult = pg_language_aclcheck(codeblock->langOid, GetUserId(),
ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
NameStr(languageStruct->lanname));
}
else
{
/* if untrusted language, must be superuser */
if (!superuser())
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
NameStr(languageStruct->lanname));
}
/* get the handler function's OID */
laninline = languageStruct->laninline;
if (!OidIsValid(laninline))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("language \"%s\" does not support inline code execution",
NameStr(languageStruct->lanname))));
ReleaseSysCache(languageTuple);
/* execute the inline handler */
OidFunctionCall1(laninline, PointerGetDatum(codeblock));
}
Definition at line 1735 of file opclasscmds.c.
References AMNAME, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, GetSysCacheOid1, and OidIsValid.
Referenced by DefineOpFamily(), get_object_address_opcf(), and transformIndexConstraint().
{
Oid oid;
oid = GetSysCacheOid1(AMNAME, CStringGetDatum(amname));
if (!OidIsValid(oid) && !missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist", amname)));
return oid;
}
Definition at line 1579 of file functioncmds.c.
References CASTSOURCETARGET, ereport, errcode(), errmsg(), ERROR, format_type_be(), GetSysCacheOid2, ObjectIdGetDatum, and OidIsValid.
Referenced by get_object_address().
{
Oid oid;
oid = GetSysCacheOid2(CASTSOURCETARGET,
ObjectIdGetDatum(sourcetypeid),
ObjectIdGetDatum(targettypeid));
if (!OidIsValid(oid) && !missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("cast from type %s to type %s does not exist",
format_type_be(sourcetypeid),
format_type_be(targettypeid))));
return oid;
}
Definition at line 223 of file opclasscmds.c.
References HeapTupleGetOid, HeapTupleIsValid, OpClassCacheLookup(), and ReleaseSysCache().
Referenced by findRangeSubOpclass(), and get_object_address_opcf().
{
HeapTuple htup;
Oid opcID;
htup = OpClassCacheLookup(amID, opclassname, missing_ok);
if (!HeapTupleIsValid(htup))
return InvalidOid;
opcID = HeapTupleGetOid(htup);
ReleaseSysCache(htup);
return opcID;
}
Definition at line 147 of file opclasscmds.c.
References HeapTupleGetOid, HeapTupleIsValid, OpFamilyCacheLookup(), and ReleaseSysCache().
Referenced by AlterOpFamily(), AlterOpFamilyAdd(), DefineOpClass(), and get_object_address_opcf().
{
HeapTuple htup;
Oid opfID;
htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
if (!HeapTupleIsValid(htup))
return InvalidOid;
opfID = HeapTupleGetOid(htup);
ReleaseSysCache(htup);
return opfID;
}
Definition at line 1324 of file indexcmds.c.
References AccessShareLock, Anum_pg_opclass_opcmethod, BTEqualStrategyNumber, ereport, errcode(), errmsg(), ERROR, format_type_be(), getBaseType(), GETSTRUCT, heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, IsBinaryCoercible(), IsPreferredType(), ObjectIdGetDatum, OpclassAmNameNspIndexId, OperatorClassRelationId, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and TypeCategory().
Referenced by findRangeSubOpclass(), get_opclass(), get_opclass_name(), GetIndexOpClass(), lookup_type_cache(), and transformIndexConstraint().
{
Oid result = InvalidOid;
int nexact = 0;
int ncompatible = 0;
int ncompatiblepreferred = 0;
Relation rel;
ScanKeyData skey[1];
SysScanDesc scan;
HeapTuple tup;
TYPCATEGORY tcategory;
/* If it's a domain, look at the base type instead */
type_id = getBaseType(type_id);
tcategory = TypeCategory(type_id);
/*
* We scan through all the opclasses available for the access method,
* looking for one that is marked default and matches the target type
* (either exactly or binary-compatibly, but prefer an exact match).
*
* We could find more than one binary-compatible match. If just one is
* for a preferred type, use that one; otherwise we fail, forcing the user
* to specify which one he wants. (The preferred-type special case is a
* kluge for varchar: it's binary-compatible to both text and bpchar, so
* we need a tiebreaker.) If we find more than one exact match, then
* someone put bogus entries in pg_opclass.
*/
rel = heap_open(OperatorClassRelationId, AccessShareLock);
ScanKeyInit(&skey[0],
Anum_pg_opclass_opcmethod,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(am_id));
scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
SnapshotNow, 1, skey);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
/* ignore altogether if not a default opclass */
if (!opclass->opcdefault)
continue;
if (opclass->opcintype == type_id)
{
nexact++;
result = HeapTupleGetOid(tup);
}
else if (nexact == 0 &&
IsBinaryCoercible(type_id, opclass->opcintype))
{
if (IsPreferredType(tcategory, opclass->opcintype))
{
ncompatiblepreferred++;
result = HeapTupleGetOid(tup);
}
else if (ncompatiblepreferred == 0)
{
ncompatible++;
result = HeapTupleGetOid(tup);
}
}
}
systable_endscan(scan);
heap_close(rel, AccessShareLock);
/* raise error if pg_opclass contains inconsistent data */
if (nexact > 1)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("there are multiple default operator classes for data type %s",
format_type_be(type_id))));
if (nexact == 1 ||
ncompatiblepreferred == 1 ||
(ncompatiblepreferred == 0 && ncompatible == 1))
return result;
return InvalidOid;
}
| void IsThereFunctionInNamespace | ( | const char * | proname, | |
| int | pronargs, | |||
| oidvector | proargtypes, | |||
| Oid | nspOid | |||
| ) |
Definition at line 1628 of file functioncmds.c.
References CStringGetDatum, ereport, errcode(), errmsg(), ERROR, funcname_signature_string(), get_namespace_name(), NIL, ObjectIdGetDatum, PointerGetDatum, PROCNAMEARGSNSP, SearchSysCacheExists3, and oidvector::values.
Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().
{
/* check for duplicate name (more friendly than unique-index failure) */
if (SearchSysCacheExists3(PROCNAMEARGSNSP,
CStringGetDatum(proname),
PointerGetDatum(&proargtypes),
ObjectIdGetDatum(nspOid)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_FUNCTION),
errmsg("function %s already exists in schema \"%s\"",
funcname_signature_string(proname, pronargs,
NIL, proargtypes.values),
get_namespace_name(nspOid))));
}
Definition at line 1689 of file opclasscmds.c.
References CLAAMNAMENSP, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_am_name(), get_namespace_name(), ObjectIdGetDatum, and SearchSysCacheExists3.
Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().
{
/* make sure the new name doesn't exist */
if (SearchSysCacheExists3(CLAAMNAMENSP,
ObjectIdGetDatum(opcmethod),
CStringGetDatum(opcname),
ObjectIdGetDatum(opcnamespace)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
opcname,
get_am_name(opcmethod),
get_namespace_name(opcnamespace))));
}
Definition at line 1712 of file opclasscmds.c.
References CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_am_name(), get_namespace_name(), ObjectIdGetDatum, OPFAMILYAMNAMENSP, and SearchSysCacheExists3.
Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().
{
/* make sure the new name doesn't exist */
if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(opfmethod),
CStringGetDatum(opfname),
ObjectIdGetDatum(opfnamespace)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
opfname,
get_am_name(opfmethod),
get_namespace_name(opfnamespace))));
}
| char* makeObjectName | ( | const char * | name1, | |
| const char * | name2, | |||
| const char * | label | |||
| ) |
Definition at line 1432 of file indexcmds.c.
References Assert, name, NAMEDATALEN, palloc(), and pg_mbcliplen().
Referenced by ChooseConstraintName(), and ChooseRelationName().
{
char *name;
int overhead = 0; /* chars needed for label and underscores */
int availchars; /* chars available for name(s) */
int name1chars; /* chars allocated to name1 */
int name2chars; /* chars allocated to name2 */
int ndx;
name1chars = strlen(name1);
if (name2)
{
name2chars = strlen(name2);
overhead++; /* allow for separating underscore */
}
else
name2chars = 0;
if (label)
overhead += strlen(label) + 1;
availchars = NAMEDATALEN - 1 - overhead;
Assert(availchars > 0); /* else caller chose a bad label */
/*
* If we must truncate, preferentially truncate the longer name. This
* logic could be expressed without a loop, but it's simple and obvious as
* a loop.
*/
while (name1chars + name2chars > availchars)
{
if (name1chars > name2chars)
name1chars--;
else
name2chars--;
}
name1chars = pg_mbcliplen(name1, name1chars, name1chars);
if (name2)
name2chars = pg_mbcliplen(name2, name2chars, name2chars);
/* Now construct the string using the chosen lengths */
name = palloc(name1chars + name2chars + overhead + 1);
memcpy(name, name1, name1chars);
ndx = name1chars;
if (name2)
{
name[ndx++] = '_';
memcpy(name + ndx, name2, name2chars);
ndx += name2chars;
}
if (label)
{
name[ndx++] = '_';
strcpy(name + ndx, label);
}
else
name[ndx] = '\0';
return name;
}
Definition at line 1788 of file indexcmds.c.
References AccessShareLock, ACL_KIND_DATABASE, aclcheck_error(), ACLCHECK_NOT_OWNER, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), AssertArg, CommitTransactionCommand(), ereport, errcode(), errmsg(), ERROR, ForwardScanDirection, get_database_name(), get_namespace_name(), get_rel_name(), get_rel_namespace(), GETSTRUCT, GetTransactionSnapshot(), GetUserId(), heap_beginscan(), heap_close, heap_endscan(), heap_getnext(), heap_open(), HeapTupleGetOid, IsSystemClass(), isTempNamespace(), lappend_oid(), lfirst_oid, MemoryContextDelete(), MemoryContextSwitchTo(), MyDatabaseId, NOTICE, NULL, pg_database_ownercheck(), PopActiveSnapshot(), PortalContext, PushActiveSnapshot(), REINDEX_REL_PROCESS_TOAST, reindex_relation(), RelationRelationId, RELKIND_MATVIEW, RELKIND_RELATION, RELPERSISTENCE_TEMP, SnapshotNow, and StartTransactionCommand().
Referenced by standard_ProcessUtility().
{
Relation relationRelation;
HeapScanDesc scan;
HeapTuple tuple;
MemoryContext private_context;
MemoryContext old;
List *relids = NIL;
ListCell *l;
AssertArg(databaseName);
if (strcmp(databaseName, get_database_name(MyDatabaseId)) != 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("can only reindex the currently open database")));
if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
databaseName);
/*
* Create a memory context that will survive forced transaction commits we
* do below. Since it is a child of PortalContext, it will go away
* eventually even if we suffer an error; there's no need for special
* abort cleanup logic.
*/
private_context = AllocSetContextCreate(PortalContext,
"ReindexDatabase",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/*
* We always want to reindex pg_class first. This ensures that if there
* is any corruption in pg_class' indexes, they will be fixed before we
* process any other tables. This is critical because reindexing itself
* will try to update pg_class.
*/
if (do_system)
{
old = MemoryContextSwitchTo(private_context);
relids = lappend_oid(relids, RelationRelationId);
MemoryContextSwitchTo(old);
}
/*
* Scan pg_class to build a list of the relations we need to reindex.
*
* We only consider plain relations here (toast rels will be processed
* indirectly by reindex_relation).
*/
relationRelation = heap_open(RelationRelationId, AccessShareLock);
scan = heap_beginscan(relationRelation, SnapshotNow, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
if (classtuple->relkind != RELKIND_RELATION &&
classtuple->relkind != RELKIND_MATVIEW)
continue;
/* Skip temp tables of other backends; we can't reindex them at all */
if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
!isTempNamespace(classtuple->relnamespace))
continue;
/* Check user/system classification, and optionally skip */
if (IsSystemClass(classtuple))
{
if (!do_system)
continue;
}
else
{
if (!do_user)
continue;
}
if (HeapTupleGetOid(tuple) == RelationRelationId)
continue; /* got it already */
old = MemoryContextSwitchTo(private_context);
relids = lappend_oid(relids, HeapTupleGetOid(tuple));
MemoryContextSwitchTo(old);
}
heap_endscan(scan);
heap_close(relationRelation, AccessShareLock);
/* Now reindex each rel in a separate transaction */
PopActiveSnapshot();
CommitTransactionCommand();
foreach(l, relids)
{
Oid relid = lfirst_oid(l);
StartTransactionCommand();
/* functions in indexes may want a snapshot set */
PushActiveSnapshot(GetTransactionSnapshot());
if (reindex_relation(relid, REINDEX_REL_PROCESS_TOAST))
ereport(NOTICE,
(errmsg("table \"%s.%s\" was reindexed",
get_namespace_name(get_rel_namespace(relid)),
get_rel_name(relid))));
PopActiveSnapshot();
CommitTransactionCommand();
}
StartTransactionCommand();
MemoryContextDelete(private_context);
return MyDatabaseId;
}
Definition at line 1683 of file indexcmds.c.
References AccessExclusiveLock, RangeVarCallbackForReindexIndex(), RangeVarGetRelidExtended(), and reindex_index().
Referenced by standard_ProcessUtility().
{
Oid indOid;
Oid heapOid = InvalidOid;
/* lock level used here should match index lock reindex_index() */
indOid = RangeVarGetRelidExtended(indexRelation, AccessExclusiveLock,
false, false,
RangeVarCallbackForReindexIndex,
(void *) &heapOid);
reindex_index(indOid, false);
return indOid;
}
Definition at line 1763 of file indexcmds.c.
References ereport, errmsg(), NOTICE, NULL, RangeVarCallbackOwnsTable(), RangeVarGetRelidExtended(), REINDEX_REL_PROCESS_TOAST, reindex_relation(), RangeVar::relname, and ShareLock.
Referenced by standard_ProcessUtility().
{
Oid heapOid;
/* The lock level used here should match reindex_relation(). */
heapOid = RangeVarGetRelidExtended(relation, ShareLock, false, false,
RangeVarCallbackOwnsTable, NULL);
if (!reindex_relation(heapOid, REINDEX_REL_PROCESS_TOAST))
ereport(NOTICE,
(errmsg("table \"%s\" has no indexes",
relation->relname)));
return heapOid;
}
| void RemoveAmOpEntryById | ( | Oid | entryOid | ) |
Definition at line 1610 of file opclasscmds.c.
References AccessMethodOperatorOidIndexId, AccessMethodOperatorRelationId, BTEqualStrategyNumber, elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdAttributeNumber, ObjectIdGetDatum, RowExclusiveLock, ScanKeyInit(), simple_heap_delete(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.
Referenced by doDeletion().
{
Relation rel;
HeapTuple tup;
ScanKeyData skey[1];
SysScanDesc scan;
ScanKeyInit(&skey[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(entryOid));
rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
scan = systable_beginscan(rel, AccessMethodOperatorOidIndexId, true,
SnapshotNow, 1, skey);
/* we expect exactly one match */
tup = systable_getnext(scan);
if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for amop entry %u", entryOid);
simple_heap_delete(rel, &tup->t_self);
systable_endscan(scan);
heap_close(rel, RowExclusiveLock);
}
| void RemoveAmProcEntryById | ( | Oid | entryOid | ) |
Definition at line 1639 of file opclasscmds.c.
References AccessMethodProcedureOidIndexId, AccessMethodProcedureRelationId, BTEqualStrategyNumber, elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdAttributeNumber, ObjectIdGetDatum, RowExclusiveLock, ScanKeyInit(), simple_heap_delete(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.
Referenced by doDeletion().
{
Relation rel;
HeapTuple tup;
ScanKeyData skey[1];
SysScanDesc scan;
ScanKeyInit(&skey[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(entryOid));
rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
scan = systable_beginscan(rel, AccessMethodProcedureOidIndexId, true,
SnapshotNow, 1, skey);
/* we expect exactly one match */
tup = systable_getnext(scan);
if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for amproc entry %u", entryOid);
simple_heap_delete(rel, &tup->t_self);
systable_endscan(scan);
heap_close(rel, RowExclusiveLock);
}
| void RemoveForeignDataWrapperById | ( | Oid | fdwId | ) |
Definition at line 785 of file foreigncmds.c.
References elog, ERROR, FOREIGNDATAWRAPPEROID, ForeignDataWrapperRelationId, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), and HeapTupleData::t_self.
Referenced by doDeletion().
{
HeapTuple tp;
Relation rel;
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
tp = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwId));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwId);
simple_heap_delete(rel, &tp->t_self);
ReleaseSysCache(tp);
heap_close(rel, RowExclusiveLock);
}
| void RemoveForeignServerById | ( | Oid | srvId | ) |
Definition at line 1019 of file foreigncmds.c.
References elog, ERROR, FOREIGNSERVEROID, ForeignServerRelationId, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), and HeapTupleData::t_self.
Referenced by doDeletion().
{
HeapTuple tp;
Relation rel;
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
tp = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvId));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for foreign server %u", srvId);
simple_heap_delete(rel, &tp->t_self);
ReleaseSysCache(tp);
heap_close(rel, RowExclusiveLock);
}
| void RemoveFunctionById | ( | Oid | funcOid | ) |
Definition at line 997 of file functioncmds.c.
References AGGFNOID, AggregateRelationId, elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, ProcedureRelationId, PROCOID, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), and HeapTupleData::t_self.
Referenced by doDeletion().
{
Relation relation;
HeapTuple tup;
bool isagg;
/*
* Delete the pg_proc tuple.
*/
relation = heap_open(ProcedureRelationId, RowExclusiveLock);
tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for function %u", funcOid);
isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg;
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
/*
* If there's a pg_aggregate tuple, delete that too.
*/
if (isagg)
{
relation = heap_open(AggregateRelationId, RowExclusiveLock);
tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
}
}
| void RemoveObjects | ( | DropStmt * | stmt | ) |
Definition at line 47 of file dropcmds.c.
References AccessExclusiveLock, add_exact_object_address(), DropStmt::arguments, DropStmt::behavior, check_object_ownership(), does_not_exist_skipping(), elog, ereport, errcode(), errhint(), errmsg(), ERROR, free_object_addresses(), get_object_address(), get_object_namespace(), GETSTRUCT, GetUserId(), heap_close, HeapTupleIsValid, lfirst, list_head(), lnext, DropStmt::missing_ok, NameListToString(), new_object_addresses(), NoLock, OBJECT_FUNCTION, ObjectAddress::objectId, ObjectIdGetDatum, DropStmt::objects, OidIsValid, performMultipleDeletions(), pg_namespace_ownercheck(), PROCOID, ReleaseSysCache(), DropStmt::removeType, and SearchSysCache1.
Referenced by ExecDropStmt().
{
ObjectAddresses *objects;
ListCell *cell1;
ListCell *cell2 = NULL;
objects = new_object_addresses();
foreach(cell1, stmt->objects)
{
ObjectAddress address;
List *objname = lfirst(cell1);
List *objargs = NIL;
Relation relation = NULL;
Oid namespaceId;
if (stmt->arguments)
{
cell2 = (!cell2 ? list_head(stmt->arguments) : lnext(cell2));
objargs = lfirst(cell2);
}
/* Get an ObjectAddress for the object. */
address = get_object_address(stmt->removeType,
objname, objargs,
&relation,
AccessExclusiveLock,
stmt->missing_ok);
/* Issue NOTICE if supplied object was not found. */
if (!OidIsValid(address.objectId))
{
does_not_exist_skipping(stmt->removeType, objname, objargs);
continue;
}
/*
* Although COMMENT ON FUNCTION, SECURITY LABEL ON FUNCTION, etc. are
* happy to operate on an aggregate as on any other function, we have
* historically not allowed this for DROP FUNCTION.
*/
if (stmt->removeType == OBJECT_FUNCTION)
{
Oid funcOid = address.objectId;
HeapTuple tup;
tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for function %u", funcOid);
if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an aggregate function",
NameListToString(objname)),
errhint("Use DROP AGGREGATE to drop aggregate functions.")));
ReleaseSysCache(tup);
}
/* Check permissions. */
namespaceId = get_object_namespace(&address);
if (!OidIsValid(namespaceId) ||
!pg_namespace_ownercheck(namespaceId, GetUserId()))
check_object_ownership(GetUserId(), stmt->removeType, address,
objname, objargs, relation);
/* Release any relcache reference count, but keep lock until commit. */
if (relation)
heap_close(relation, NoLock);
add_exact_object_address(&address, objects);
}
/* Here we really delete them. */
performMultipleDeletions(objects, stmt->behavior, 0);
free_object_addresses(objects);
}
| void RemoveOpClassById | ( | Oid | opclassOid | ) |
Definition at line 1591 of file opclasscmds.c.
References CLAOID, elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, OperatorClassRelationId, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), and HeapTupleData::t_self.
Referenced by doDeletion().
{
Relation rel;
HeapTuple tup;
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
tup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
simple_heap_delete(rel, &tup->t_self);
ReleaseSysCache(tup);
heap_close(rel, RowExclusiveLock);
}
| void RemoveOperatorById | ( | Oid | operOid | ) |
Definition at line 316 of file operatorcmds.c.
References elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, OperatorRelationId, OPEROID, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), and HeapTupleData::t_self.
Referenced by doDeletion().
{
Relation relation;
HeapTuple tup;
relation = heap_open(OperatorRelationId, RowExclusiveLock);
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for operator %u", operOid);
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
}
| void RemoveOpFamilyById | ( | Oid | opfamilyOid | ) |
Definition at line 1572 of file opclasscmds.c.
References elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, OperatorFamilyRelationId, OPFAMILYOID, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), and HeapTupleData::t_self.
Referenced by doDeletion().
{
Relation rel;
HeapTuple tup;
rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
simple_heap_delete(rel, &tup->t_self);
ReleaseSysCache(tup);
heap_close(rel, RowExclusiveLock);
}
| void RemoveTSConfigurationById | ( | Oid | cfgId | ) |
Definition at line 1109 of file tsearchcmds.c.
References Anum_pg_ts_config_map_mapcfg, BTEqualStrategyNumber, elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1, simple_heap_delete(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, TSConfigMapIndexId, TSConfigMapRelationId, TSCONFIGOID, and TSConfigRelationId.
Referenced by doDeletion().
{
Relation relCfg,
relMap;
HeapTuple tup;
ScanKeyData skey;
SysScanDesc scan;
/* Remove the pg_ts_config entry */
relCfg = heap_open(TSConfigRelationId, RowExclusiveLock);
tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgId));
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search dictionary %u",
cfgId);
simple_heap_delete(relCfg, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relCfg, RowExclusiveLock);
/* Remove any pg_ts_config_map entries */
relMap = heap_open(TSConfigMapRelationId, RowExclusiveLock);
ScanKeyInit(&skey,
Anum_pg_ts_config_map_mapcfg,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(cfgId));
scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
SnapshotNow, 1, &skey);
while (HeapTupleIsValid((tup = systable_getnext(scan))))
{
simple_heap_delete(relMap, &tup->t_self);
}
systable_endscan(scan);
heap_close(relMap, RowExclusiveLock);
}
| void RemoveTSDictionaryById | ( | Oid | dictId | ) |
Definition at line 494 of file tsearchcmds.c.
References elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), HeapTupleData::t_self, TSDictionaryRelationId, and TSDICTOID.
Referenced by doDeletion().
{
Relation relation;
HeapTuple tup;
relation = heap_open(TSDictionaryRelationId, RowExclusiveLock);
tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search dictionary %u",
dictId);
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
}
| void RemoveTSParserById | ( | Oid | prsId | ) |
Definition at line 288 of file tsearchcmds.c.
References elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), HeapTupleData::t_self, TSPARSEROID, and TSParserRelationId.
Referenced by doDeletion().
{
Relation relation;
HeapTuple tup;
relation = heap_open(TSParserRelationId, RowExclusiveLock);
tup = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(prsId));
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search parser %u", prsId);
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
}
| void RemoveTSTemplateById | ( | Oid | tmplId | ) |
Definition at line 812 of file tsearchcmds.c.
References elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), HeapTupleData::t_self, TSTEMPLATEOID, and TSTemplateRelationId.
Referenced by doDeletion().
{
Relation relation;
HeapTuple tup;
relation = heap_open(TSTemplateRelationId, RowExclusiveLock);
tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search template %u",
tmplId);
simple_heap_delete(relation, &tup->t_self);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
}
| Oid RemoveUserMapping | ( | DropUserMappingStmt * | stmt | ) |
Definition at line 1256 of file foreigncmds.c.
References DROP_CASCADE, elog, ereport, errcode(), errmsg(), ERROR, GetForeignServerByName(), GetSysCacheOid2, GetUserOidFromMapping(), MappingUserName, DropUserMappingStmt::missing_ok, NOTICE, ObjectIdGetDatum, OidIsValid, performDeletion(), ForeignServer::serverid, ForeignServer::servername, DropUserMappingStmt::servername, user_mapping_ddl_aclcheck(), USERMAPPINGUSERSERVER, and DropUserMappingStmt::username.
Referenced by ProcessUtilitySlow().
{
ObjectAddress object;
Oid useId;
Oid umId;
ForeignServer *srv;
useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
srv = GetForeignServerByName(stmt->servername, true);
if (stmt->username && !OidIsValid(useId))
{
/*
* IF EXISTS specified, role not found and not public. Notice this and
* leave.
*/
elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
return InvalidOid;
}
if (!srv)
{
if (!stmt->missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("server \"%s\" does not exist",
stmt->servername)));
/* IF EXISTS, just note it */
ereport(NOTICE, (errmsg("server does not exist, skipping")));
return InvalidOid;
}
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
ObjectIdGetDatum(useId),
ObjectIdGetDatum(srv->serverid));
if (!OidIsValid(umId))
{
if (!stmt->missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("user mapping \"%s\" does not exist for the server",
MappingUserName(useId))));
/* IF EXISTS specified, just note it */
ereport(NOTICE,
(errmsg("user mapping \"%s\" does not exist for the server, skipping",
MappingUserName(useId))));
return InvalidOid;
}
user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);
/*
* Do the deletion
*/
object.classId = UserMappingRelationId;
object.objectId = umId;
object.objectSubId = 0;
performDeletion(&object, DROP_CASCADE, 0);
return umId;
}
| void RemoveUserMappingById | ( | Oid | umId | ) |
Definition at line 1326 of file foreigncmds.c.
References elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), HeapTupleData::t_self, USERMAPPINGOID, and UserMappingRelationId.
Referenced by doDeletion().
{
HeapTuple tp;
Relation rel;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
tp = SearchSysCache1(USERMAPPINGOID, ObjectIdGetDatum(umId));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for user mapping %u", umId);
simple_heap_delete(rel, &tp->t_self);
ReleaseSysCache(tp);
heap_close(rel, RowExclusiveLock);
}
Definition at line 1497 of file tsearchcmds.c.
References appendStringInfo(), appendStringInfoChar(), buf, cstring_to_text_with_len(), StringInfoData::data, defGetString(), DefElem::defname, ESCAPE_STRING_SYNTAX, initStringInfo(), StringInfoData::len, lfirst, lnext, NULL, pfree(), quote_identifier(), SQL_STR_DOUBLE, and val.
Referenced by AlterTSDictionary(), and DefineTSDictionary().
{
text *result;
StringInfoData buf;
ListCell *l;
initStringInfo(&buf);
foreach(l, deflist)
{
DefElem *defel = (DefElem *) lfirst(l);
char *val = defGetString(defel);
appendStringInfo(&buf, "%s = ",
quote_identifier(defel->defname));
/* If backslashes appear, force E syntax to determine their handling */
if (strchr(val, '\\'))
appendStringInfoChar(&buf, ESCAPE_STRING_SYNTAX);
appendStringInfoChar(&buf, '\'');
while (*val)
{
char ch = *val++;
if (SQL_STR_DOUBLE(ch, true))
appendStringInfoChar(&buf, ch);
appendStringInfoChar(&buf, ch);
}
appendStringInfoChar(&buf, '\'');
if (lnext(l) != NULL)
appendStringInfo(&buf, ", ");
}
result = cstring_to_text_with_len(buf.data, buf.len);
pfree(buf.data);
return result;
}
Definition at line 1222 of file functioncmds.c.
References CatalogUpdateIndexes(), elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, OPAQUEOID, ProcedureRelationId, PROCOID, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), and HeapTupleData::t_self.
Referenced by findTypeInputFunction(), and findTypeOutputFunction().
{
Relation pg_proc_rel;
HeapTuple tup;
Form_pg_proc procForm;
pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for function %u", funcOid);
procForm = (Form_pg_proc) GETSTRUCT(tup);
if (argIndex < 0 || argIndex >= procForm->pronargs ||
procForm->proargtypes.values[argIndex] != OPAQUEOID)
elog(ERROR, "function %u doesn't take OPAQUE", funcOid);
/* okay to overwrite copied tuple */
procForm->proargtypes.values[argIndex] = newArgType;
/* update the catalog and its indexes */
simple_heap_update(pg_proc_rel, &tup->t_self, tup);
CatalogUpdateIndexes(pg_proc_rel, tup);
heap_close(pg_proc_rel, RowExclusiveLock);
}
Definition at line 1188 of file functioncmds.c.
References CatalogUpdateIndexes(), elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, OPAQUEOID, ProcedureRelationId, PROCOID, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), and HeapTupleData::t_self.
Referenced by CreateProceduralLanguage(), CreateTrigger(), and DefineType().
{
Relation pg_proc_rel;
HeapTuple tup;
Form_pg_proc procForm;
pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for function %u", funcOid);
procForm = (Form_pg_proc) GETSTRUCT(tup);
if (procForm->prorettype != OPAQUEOID) /* caller messed up */
elog(ERROR, "function %u doesn't return OPAQUE", funcOid);
/* okay to overwrite copied tuple */
procForm->prorettype = newRetType;
/* update the catalog and its indexes */
simple_heap_update(pg_proc_rel, &tup->t_self, tup);
CatalogUpdateIndexes(pg_proc_rel, tup);
heap_close(pg_proc_rel, RowExclusiveLock);
}
Definition at line 94 of file foreigncmds.c.
References construct_empty_array(), DatumGetPointer, DefElem::defaction, DEFELEM_ADD, DEFELEM_DROP, DEFELEM_SET, DEFELEM_UNSPEC, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, lappend(), lfirst, list_delete_cell(), NULL, ObjectIdGetDatum, OidFunctionCall2, OidIsValid, optionListToArray(), PointerGetDatum, TEXTOID, and untransformRelOptions().
Referenced by AlterForeignDataWrapper(), AlterForeignServer(), AlterUserMapping(), ATExecAlterColumnGenericOptions(), ATExecGenericOptions(), CreateForeignDataWrapper(), CreateForeignServer(), CreateForeignTable(), and CreateUserMapping().
{
List *resultOptions = untransformRelOptions(oldOptions);
ListCell *optcell;
Datum result;
foreach(optcell, options)
{
DefElem *od = lfirst(optcell);
ListCell *cell;
ListCell *prev = NULL;
/*
* Find the element in resultOptions. We need this for validation in
* all cases. Also identify the previous element.
*/
foreach(cell, resultOptions)
{
DefElem *def = lfirst(cell);
if (strcmp(def->defname, od->defname) == 0)
break;
else
prev = cell;
}
/*
* It is possible to perform multiple SET/DROP actions on the same
* option. The standard permits this, as long as the options to be
* added are unique. Note that an unspecified action is taken to be
* ADD.
*/
switch (od->defaction)
{
case DEFELEM_DROP:
if (!cell)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("option \"%s\" not found",
od->defname)));
resultOptions = list_delete_cell(resultOptions, cell, prev);
break;
case DEFELEM_SET:
if (!cell)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("option \"%s\" not found",
od->defname)));
lfirst(cell) = od;
break;
case DEFELEM_ADD:
case DEFELEM_UNSPEC:
if (cell)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("option \"%s\" provided more than once",
od->defname)));
resultOptions = lappend(resultOptions, od);
break;
default:
elog(ERROR, "unrecognized action %d on option \"%s\"",
(int) od->defaction, od->defname);
break;
}
}
result = optionListToArray(resultOptions);
if (OidIsValid(fdwvalidator))
{
Datum valarg = result;
/*
* Pass a null options list as an empty array, so that validators
* don't have to be declared non-strict to handle the case.
*/
if (DatumGetPointer(valarg) == NULL)
valarg = PointerGetDatum(construct_empty_array(TEXTOID));
OidFunctionCall2(fdwvalidator, valarg, ObjectIdGetDatum(catalogId));
}
return result;
}
1.7.1