#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; }