📄 functioncmds.c
字号:
simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); heap_close(rel, NoLock); heap_freetuple(tup);}/* * SetFunctionReturnType - change declared return type of a function * * This is presently only used for adjusting legacy functions that return * OPAQUE to return whatever we find their correct definition should be. * The caller should emit a suitable warning explaining what we did. */voidSetFunctionReturnType(Oid funcOid, Oid newRetType){ Relation pg_proc_rel; HeapTuple tup; Form_pg_proc procForm; pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock); tup = SearchSysCacheCopy(PROCOID, ObjectIdGetDatum(funcOid), 0, 0, 0); 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);}/* * SetFunctionArgType - change declared argument type of a function * * As above, but change an argument's type. */voidSetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType){ Relation pg_proc_rel; HeapTuple tup; Form_pg_proc procForm; pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock); tup = SearchSysCacheCopy(PROCOID, ObjectIdGetDatum(funcOid), 0, 0, 0); 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);}/* * CREATE CAST */voidCreateCast(CreateCastStmt *stmt){ Oid sourcetypeid; Oid targettypeid; Oid funcid; int nargs; char castcontext; Relation relation; HeapTuple tuple; Datum values[Natts_pg_cast]; char nulls[Natts_pg_cast]; ObjectAddress myself, referenced; sourcetypeid = LookupTypeName(stmt->sourcetype); if (!OidIsValid(sourcetypeid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("source data type %s does not exist", TypeNameToString(stmt->sourcetype)))); targettypeid = LookupTypeName(stmt->targettype); if (!OidIsValid(targettypeid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("target data type %s does not exist", TypeNameToString(stmt->targettype)))); /* No shells, no pseudo-types allowed */ if (!get_typisdefined(sourcetypeid)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("source data type %s is only a shell", TypeNameToString(stmt->sourcetype)))); if (!get_typisdefined(targettypeid)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("target data type %s is only a shell", TypeNameToString(stmt->targettype)))); if (get_typtype(sourcetypeid) == 'p') ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("source data type %s is a pseudo-type", TypeNameToString(stmt->sourcetype)))); if (get_typtype(targettypeid) == 'p') 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", TypeNameToString(stmt->sourcetype), TypeNameToString(stmt->targettype)))); if (stmt->func != NULL) { Form_pg_proc procstruct; funcid = LookupFuncNameTypeNames(stmt->func->funcname, stmt->func->funcargs, false); tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0); 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 (procstruct->proargtypes.values[0] != sourcetypeid) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("argument of cast function must match 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 (procstruct->prorettype != targettypeid) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("return data type of cast function must match 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->proretset) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("cast function must not return a set"))); ReleaseSysCache(tuple); } else { int16 typ1len; int16 typ2len; bool typ1byval; bool typ2byval; char typ1align; char typ2align; /* indicates binary coercibility */ funcid = InvalidOid; nargs = 0; /* * 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"))); } /* * 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 = SearchSysCache(CASTSOURCETARGET, ObjectIdGetDatum(sourcetypeid), ObjectIdGetDatum(targettypeid), 0, 0); if (HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("cast from type %s to type %s already exists", TypeNameToString(stmt->sourcetype), TypeNameToString(stmt->targettype)))); /* 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); MemSet(nulls, ' ', Natts_pg_cast); tuple = heap_formtuple(RelationGetDescr(relation), values, nulls); simple_heap_insert(relation, tuple); CatalogUpdateIndexes(relation, tuple); /* make dependency entries */ myself.classId = CastRelationId; myself.objectId = HeapTupleGetOid(tuple); 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); } heap_freetuple(tuple); heap_close(relation, RowExclusiveLock);}/* * DROP CAST */voidDropCast(DropCastStmt *stmt){ Oid sourcetypeid; Oid targettypeid; HeapTuple tuple; ObjectAddress object; sourcetypeid = LookupTypeName(stmt->sourcetype); if (!OidIsValid(sourcetypeid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("source data type %s does not exist", TypeNameToString(stmt->sourcetype)))); targettypeid = LookupTypeName(stmt->targettype); if (!OidIsValid(targettypeid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("target data type %s does not exist", TypeNameToString(stmt->targettype)))); tuple = SearchSysCache(CASTSOURCETARGET, ObjectIdGetDatum(sourcetypeid), ObjectIdGetDatum(targettypeid), 0, 0); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("cast from type %s to type %s does not exist", TypeNameToString(stmt->sourcetype), 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", TypeNameToString(stmt->sourcetype), TypeNameToString(stmt->targettype)))); /* * Do the deletion */ object.classId = CastRelationId; object.objectId = HeapTupleGetOid(tuple); object.objectSubId = 0; ReleaseSysCache(tuple); performDeletion(&object, stmt->behavior);}voidDropCastById(Oid castOid){ 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);}/* * Execute ALTER FUNCTION SET SCHEMA */voidAlterFunctionNamespace(List *name, List *argtypes, const char *newschema){ Oid procOid; Oid oldNspOid; Oid nspOid; HeapTuple tup; Relation procRel; Form_pg_proc proc; procRel = heap_open(ProcedureRelationId, RowExclusiveLock); /* get function OID */ procOid = LookupFuncNameTypeNames(name, argtypes, false); /* check permissions on function */ if (!pg_proc_ownercheck(procOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(name)); tup = SearchSysCacheCopy(PROCOID, ObjectIdGetDatum(procOid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for function %u", procOid); proc = (Form_pg_proc) GETSTRUCT(tup); oldNspOid = proc->pronamespace; /* get schema OID and check its permissions */ nspOid = LookupCreationNamespace(newschema); if (oldNspOid == nspOid) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_FUNCTION), errmsg("function \"%s\" is already in schema \"%s\"", NameListToString(name), newschema))); /* disallow renaming into or out of temp schemas */ if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot move objects into or out of temporary schemas"))); /* same for TOAST schema */ if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot move objects into or out of TOAST schema"))); /* check for duplicate name (more friendly than unique-index failure) */ if (SearchSysCacheExists(PROCNAMEARGSNSP, CStringGetDatum(NameStr(proc->proname)), PointerGetDatum(&proc->proargtypes), ObjectIdGetDatum(nspOid), 0)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_FUNCTION), errmsg("function \"%s\" already exists in schema \"%s\"", NameStr(proc->proname), newschema))); /* OK, modify the pg_proc row */ /* tup is a copy, so we can scribble directly on it */ proc->pronamespace = nspOid; simple_heap_update(procRel, &tup->t_self, tup); CatalogUpdateIndexes(procRel, tup); /* Update dependency on schema */ if (changeDependencyFor(ProcedureRelationId, procOid, NamespaceRelationId, oldNspOid, nspOid) != 1) elog(ERROR, "failed to change schema dependency for function \"%s\"", NameListToString(name)); heap_freetuple(tup); heap_close(procRel, RowExclusiveLock);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -