diff options
Diffstat (limited to 'src/backend/commands/functioncmds.c')
-rw-r--r-- | src/backend/commands/functioncmds.c | 147 |
1 files changed, 88 insertions, 59 deletions
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index c8e4c65386..647385b207 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -5,12 +5,12 @@ * Routines for CREATE and DROP FUNCTION commands and CREATE and DROP * CAST commands. * - * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.118 2010/02/26 02:00:39 momjian Exp $ + * src/backend/commands/functioncmds.c * * DESCRIPTION * These routines take the parse tree and pick out the @@ -37,6 +37,7 @@ #include "access/sysattr.h" #include "catalog/dependency.h" #include "catalog/indexing.h" +#include "catalog/objectaccess.h" #include "catalog/pg_aggregate.h" #include "catalog/pg_cast.h" #include "catalog/pg_language.h" @@ -50,6 +51,7 @@ #include "miscadmin.h" #include "optimizer/var.h" #include "parser/parse_coerce.h" +#include "parser/parse_collate.h" #include "parser/parse_expr.h" #include "parser/parse_func.h" #include "parser/parse_type.h" @@ -333,6 +335,7 @@ examine_parameter_list(List *parameters, Oid languageOid, def = transformExpr(pstate, fp->defexpr); def = coerce_to_specific_type(pstate, def, toid, "DEFAULT"); + assign_expr_collations(pstate, def); /* * Make sure no variables are referred to. @@ -1507,8 +1510,8 @@ CreateCast(CreateCastStmt *stmt) ObjectAddress myself, referenced; - sourcetypeid = typenameTypeId(NULL, stmt->sourcetype, NULL); - targettypeid = typenameTypeId(NULL, stmt->targettype, NULL); + sourcetypeid = typenameTypeId(NULL, stmt->sourcetype); + targettypeid = typenameTypeId(NULL, stmt->targettype); sourcetyptype = get_typtype(sourcetypeid); targettyptype = get_typtype(targettypeid); @@ -1668,6 +1671,23 @@ CreateCast(CreateCastStmt *stmt) 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"))); } /* @@ -1755,6 +1775,13 @@ CreateCast(CreateCastStmt *stmt) recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } + /* dependency on extension */ + recordDependencyOnCurrentExtension(&myself); + + /* Post creation hook for new cast */ + InvokeObjectAccessHook(OAT_POST_CREATE, + CastRelationId, myself.objectId, 0); + heap_freetuple(tuple); heap_close(relation, RowExclusiveLock); @@ -1770,30 +1797,23 @@ DropCast(DropCastStmt *stmt) { Oid sourcetypeid; Oid targettypeid; - HeapTuple tuple; ObjectAddress object; /* when dropping a cast, the types must exist even if you use IF EXISTS */ - sourcetypeid = typenameTypeId(NULL, stmt->sourcetype, NULL); - targettypeid = typenameTypeId(NULL, stmt->targettype, NULL); + sourcetypeid = typenameTypeId(NULL, stmt->sourcetype); + targettypeid = typenameTypeId(NULL, stmt->targettype); - tuple = SearchSysCache2(CASTSOURCETARGET, - ObjectIdGetDatum(sourcetypeid), - ObjectIdGetDatum(targettypeid)); - if (!HeapTupleIsValid(tuple)) + object.classId = CastRelationId; + object.objectId = get_cast_oid(sourcetypeid, targettypeid, + stmt->missing_ok); + object.objectSubId = 0; + + if (!OidIsValid(object.objectId)) { - if (!stmt->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)))); - else - ereport(NOTICE, + ereport(NOTICE, (errmsg("cast from type %s to type %s does not exist, skipping", format_type_be(sourcetypeid), format_type_be(targettypeid)))); - return; } @@ -1809,15 +1829,31 @@ DropCast(DropCastStmt *stmt) /* * Do the deletion */ - object.classId = CastRelationId; - object.objectId = HeapTupleGetOid(tuple); - object.objectSubId = 0; - - ReleaseSysCache(tuple); - performDeletion(&object, stmt->behavior); } +/* + * get_cast_oid - given two type OIDs, look up a cast OID + * + * If missing_ok is false, throw an error if the cast is not found. If + * true, just return InvalidOid. + */ +Oid +get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok) +{ + 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; +} void DropCastById(Oid castOid) @@ -1855,13 +1891,7 @@ AlterFunctionNamespace(List *name, List *argtypes, bool isagg, 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 */ if (isagg) @@ -1869,39 +1899,36 @@ AlterFunctionNamespace(List *name, List *argtypes, bool isagg, else 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)); + /* get schema OID and check its permissions */ + nspOid = LookupCreationNamespace(newschema); + + AlterFunctionNamespace_oid(procOid, nspOid); +} + +Oid +AlterFunctionNamespace_oid(Oid procOid, Oid nspOid) +{ + Oid oldNspOid; + HeapTuple tup; + Relation procRel; + Form_pg_proc proc; + + procRel = heap_open(ProcedureRelationId, RowExclusiveLock); tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid)); 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))); + /* check permissions on function */ + if (!pg_proc_ownercheck(procOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, + NameStr(proc->proname)); - /* 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"))); + oldNspOid = proc->pronamespace; - /* 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"))); + /* common checks on switching namespaces */ + CheckSetNamespace(oldNspOid, nspOid, ProcedureRelationId, procOid); /* check for duplicate name (more friendly than unique-index failure) */ if (SearchSysCacheExists3(PROCNAMEARGSNSP, @@ -1912,7 +1939,7 @@ AlterFunctionNamespace(List *name, List *argtypes, bool isagg, (errcode(ERRCODE_DUPLICATE_FUNCTION), errmsg("function \"%s\" already exists in schema \"%s\"", NameStr(proc->proname), - newschema))); + get_namespace_name(nspOid)))); /* OK, modify the pg_proc row */ @@ -1926,11 +1953,13 @@ AlterFunctionNamespace(List *name, List *argtypes, bool isagg, if (changeDependencyFor(ProcedureRelationId, procOid, NamespaceRelationId, oldNspOid, nspOid) != 1) elog(ERROR, "failed to change schema dependency for function \"%s\"", - NameListToString(name)); + NameStr(proc->proname)); heap_freetuple(tup); heap_close(procRel, RowExclusiveLock); + + return oldNspOid; } |