diff options
author | Peter Eisentraut <peter_e@gmx.net> | 2002-07-18 23:11:32 +0000 |
---|---|---|
committer | Peter Eisentraut <peter_e@gmx.net> | 2002-07-18 23:11:32 +0000 |
commit | 97377048b460823a300b1d414203c5f09c8efc1b (patch) | |
tree | 7c567e9728b214a10604afa1aa923d02a683156e /src/backend/commands/functioncmds.c | |
parent | a345ac8842089cbca1678d5b28773a827937693f (diff) | |
download | postgresql-97377048b460823a300b1d414203c5f09c8efc1b.tar.gz postgresql-97377048b460823a300b1d414203c5f09c8efc1b.zip |
pg_cast table, and standards-compliant CREATE/DROP CAST commands, plus
extension to create binary compatible casts. Includes dependency tracking
as well.
pg_proc.proimplicit is now defunct, but will be removed in a separate
commit.
pg_dump provides a migration path from the previous scheme to declare
casts. Dumping binary compatible casts is currently impossible, though.
Diffstat (limited to 'src/backend/commands/functioncmds.c')
-rw-r--r-- | src/backend/commands/functioncmds.c | 252 |
1 files changed, 225 insertions, 27 deletions
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 9a33810b073..2ed9581b665 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.8 2002/07/12 18:43:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.9 2002/07/18 23:11:27 petere Exp $ * * DESCRIPTION * These routines take the parse tree and pick out the @@ -34,7 +34,9 @@ #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/dependency.h" +#include "catalog/indexing.h" #include "catalog/namespace.h" +#include "catalog/pg_cast.h" #include "catalog/pg_language.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" @@ -44,6 +46,7 @@ #include "parser/parse_func.h" #include "parser/parse_type.h" #include "utils/acl.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/syscache.h" @@ -171,8 +174,7 @@ compute_attributes_sql_style(const List *options, char **language, char *volatility_p, bool *strict_p, - bool *security_definer, - bool *implicit_cast) + bool *security_definer) { const List *option; DefElem *as_item = NULL; @@ -180,7 +182,6 @@ compute_attributes_sql_style(const List *options, DefElem *volatility_item = NULL; DefElem *strict_item = NULL; DefElem *security_item = NULL; - DefElem *implicit_item = NULL; foreach(option, options) { @@ -216,12 +217,6 @@ compute_attributes_sql_style(const List *options, elog(ERROR, "conflicting or redundant options"); security_item = defel; } - else if (strcmp(defel->defname, "implicit")==0) - { - if (implicit_item) - elog(ERROR, "conflicting or redundant options"); - implicit_item = defel; - } else elog(ERROR, "invalid CREATE FUNCTION option"); } @@ -252,8 +247,6 @@ compute_attributes_sql_style(const List *options, *strict_p = intVal(strict_item->arg); if (security_item) *security_definer = intVal(security_item->arg); - if (implicit_item) - *implicit_cast = intVal(implicit_item->arg); } @@ -264,10 +257,7 @@ compute_attributes_sql_style(const List *options, * These parameters supply optional information about a function. * All have defaults if not specified. * - * Note: currently, only three of these parameters actually do anything: - * - * * isImplicit means the function may be used as an implicit type - * coercion. + * Note: currently, only two of these parameters actually do anything: * * * isStrict means the function should not be called when any NULL * inputs are present; instead a NULL result value should be assumed. @@ -284,7 +274,7 @@ static void compute_attributes_with_style(List *parameters, int32 *byte_pct_p, int32 *perbyte_cpu_p, int32 *percall_cpu_p, int32 *outin_ratio_p, - bool *isImplicit_p, bool *isStrict_p, + bool *isStrict_p, char *volatility_p) { List *pl; @@ -293,9 +283,7 @@ compute_attributes_with_style(List *parameters, { DefElem *param = (DefElem *) lfirst(pl); - if (strcasecmp(param->defname, "implicitcoercion") == 0) - *isImplicit_p = true; - else if (strcasecmp(param->defname, "isstrict") == 0) + if (strcasecmp(param->defname, "isstrict") == 0) *isStrict_p = true; else if (strcasecmp(param->defname, "isimmutable") == 0) *volatility_p = PROVOLATILE_IMMUTABLE; @@ -398,8 +386,7 @@ CreateFunction(CreateFunctionStmt *stmt) perbyte_cpu, percall_cpu, outin_ratio; - bool isImplicit, - isStrict, + bool isStrict, security; char volatility; HeapTuple languageTuple; @@ -420,14 +407,13 @@ CreateFunction(CreateFunctionStmt *stmt) perbyte_cpu = PERBYTE_CPU; percall_cpu = PERCALL_CPU; outin_ratio = OUTIN_RATIO; - isImplicit = false; isStrict = false; security = false; volatility = PROVOLATILE_VOLATILE; /* override attributes from explicit list */ compute_attributes_sql_style(stmt->options, - &as_clause, &language, &volatility, &isStrict, &security, &isImplicit); + &as_clause, &language, &volatility, &isStrict, &security); /* Convert language name to canonical case */ case_translate_language_name(language, languageName); @@ -474,8 +460,7 @@ CreateFunction(CreateFunctionStmt *stmt) compute_attributes_with_style(stmt->withClause, &byte_pct, &perbyte_cpu, &percall_cpu, - &outin_ratio, &isImplicit, &isStrict, - &volatility); + &outin_ratio, &isStrict, &volatility); interpret_AS_clause(languageOid, languageName, as_clause, &prosrc_str, &probin_str); @@ -517,7 +502,6 @@ CreateFunction(CreateFunctionStmt *stmt) probin_str, /* converted to text later */ false, /* not an aggregate */ security, - isImplicit, isStrict, volatility, byte_pct, @@ -639,3 +623,217 @@ RemoveFunctionById(Oid funcOid) heap_close(relation, RowExclusiveLock); } } + + + +/* + * CREATE CAST + */ +void +CreateCast(CreateCastStmt *stmt) +{ + Oid sourcetypeid; + Oid targettypeid; + Oid funcid; + HeapTuple tuple; + Relation relation; + Form_pg_proc procstruct; + + Datum values[Natts_pg_proc]; + char nulls[Natts_pg_proc]; + int i; + + ObjectAddress myself, + referenced; + + sourcetypeid = LookupTypeName(stmt->sourcetype); + if (!OidIsValid(sourcetypeid)) + elog(ERROR, "source data type %s does not exist", + TypeNameToString(stmt->sourcetype)); + + targettypeid = LookupTypeName(stmt->targettype); + if (!OidIsValid(targettypeid)) + elog(ERROR, "target data type %s does not exist", + TypeNameToString(stmt->targettype)); + + if (sourcetypeid == targettypeid) + elog(ERROR, "source data type and target data type are the same"); + + relation = heap_openr(CastRelationName, RowExclusiveLock); + + tuple = SearchSysCache(CASTSOURCETARGET, + ObjectIdGetDatum(sourcetypeid), + ObjectIdGetDatum(targettypeid), + 0, 0); + if (HeapTupleIsValid(tuple)) + elog(ERROR, "cast from data type %s to data type %s already exists", + TypeNameToString(stmt->sourcetype), + TypeNameToString(stmt->targettype)); + + if (stmt->func != NULL) + { + funcid = LookupFuncNameTypeNames(stmt->func->funcname, stmt->func->funcargs, false, "CreateCast"); + + if(!pg_proc_ownercheck(funcid, GetUserId())) + elog(ERROR, "permission denied"); + + tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup of function %u failed", funcid); + + procstruct = (Form_pg_proc) GETSTRUCT(tuple); + if (procstruct->pronargs != 1) + elog(ERROR, "cast function must take 1 argument"); + if (procstruct->proargtypes[0] != sourcetypeid) + elog(ERROR, "argument of cast function must match source data type"); + if (procstruct->prorettype != targettypeid) + elog(ERROR, "return data type of cast function must match target data type"); + if (procstruct->provolatile != PROVOLATILE_IMMUTABLE) + elog(ERROR, "cast function must be immutable"); + if (procstruct->proisagg) + elog(ERROR, "cast function must not be an aggregate function"); + if (procstruct->proretset) + elog(ERROR, "cast function must be not return a set"); + + ReleaseSysCache(tuple); + } + else + { + /* indicates binary compatibility */ + if (!pg_type_ownercheck(sourcetypeid, GetUserId()) + || !pg_type_ownercheck(targettypeid, GetUserId())) + elog(ERROR, "permission denied"); + funcid = 0; + } + + /* 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_castimplicit-1] = BoolGetDatum(stmt->implicit); + + for (i = 0; i < Natts_pg_cast; ++i) + nulls[i] = ' '; + + tuple = heap_formtuple(RelationGetDescr(relation), values, nulls); + simple_heap_insert(relation, tuple); + + if (RelationGetForm(relation)->relhasindex) + { + Relation idescs[Num_pg_cast_indices]; + + CatalogOpenIndices(Num_pg_cast_indices, Name_pg_cast_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_cast_indices, relation, tuple); + CatalogCloseIndices(Num_pg_cast_indices, idescs); + } + + myself.classId = get_system_catalog_relid(CastRelationName); + myself.objectId = tuple->t_data->t_oid; + myself.objectSubId = 0; + + /* dependency on source type */ + referenced.classId = RelOid_pg_type; + referenced.objectId = sourcetypeid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* dependency on target type */ + referenced.classId = RelOid_pg_type; + referenced.objectId = targettypeid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* dependency on function */ + if (OidIsValid(funcid)) + { + referenced.classId = RelOid_pg_proc; + referenced.objectId = funcid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + heap_freetuple(tuple); + heap_close(relation, RowExclusiveLock); +} + + + +/* + * DROP CAST + */ +void +DropCast(DropCastStmt *stmt) +{ + Oid sourcetypeid; + Oid targettypeid; + HeapTuple tuple; + Form_pg_cast caststruct; + ObjectAddress object; + + sourcetypeid = LookupTypeName(stmt->sourcetype); + if (!OidIsValid(sourcetypeid)) + elog(ERROR, "source data type %s does not exist", + TypeNameToString(stmt->sourcetype)); + + targettypeid = LookupTypeName(stmt->targettype); + if (!OidIsValid(targettypeid)) + elog(ERROR, "target data type %s does not exist", + TypeNameToString(stmt->targettype)); + + tuple = SearchSysCache(CASTSOURCETARGET, + ObjectIdGetDatum(sourcetypeid), + ObjectIdGetDatum(targettypeid), + 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cast from type %s to type %s does not exist", + TypeNameToString(stmt->sourcetype), + TypeNameToString(stmt->targettype)); + + /* Permission check */ + caststruct = (Form_pg_cast) GETSTRUCT(tuple); + if (caststruct->castfunc != InvalidOid) + { + if(!pg_proc_ownercheck(caststruct->castfunc, GetUserId())) + elog(ERROR, "permission denied"); + } + else + { + if (!pg_type_ownercheck(sourcetypeid, GetUserId()) + || !pg_type_ownercheck(targettypeid, GetUserId())) + elog(ERROR, "permission denied"); + } + + ReleaseSysCache(tuple); + + /* + * Do the deletion + */ + object.classId = get_system_catalog_relid(CastRelationName); + object.objectId = tuple->t_data->t_oid; + object.objectSubId = 0; + + performDeletion(&object, stmt->behavior); +} + + +void +DropCastById(Oid castOid) +{ + Relation relation; + ScanKeyData scankey; + HeapScanDesc scan; + HeapTuple tuple; + + relation = heap_openr(CastRelationName, RowExclusiveLock); + ScanKeyEntryInitialize(&scankey, 0x0, + ObjectIdAttributeNumber, F_OIDEQ, + ObjectIdGetDatum(castOid)); + scan = heap_beginscan(relation, SnapshotNow, 1, &scankey); + tuple = heap_getnext(scan, ForwardScanDirection); + if (HeapTupleIsValid(tuple)) + simple_heap_delete(relation, &tuple->t_self); + else + elog(ERROR, "could not find tuple for cast %u", castOid); + heap_endscan(scan); + heap_close(relation, RowExclusiveLock); +} |