1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-12 05:01:15 +03:00

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.
This commit is contained in:
Peter Eisentraut
2002-07-18 23:11:32 +00:00
parent a345ac8842
commit 97377048b4
36 changed files with 1299 additions and 343 deletions

View File

@@ -2,7 +2,7 @@
#
# Makefile for backend/catalog
#
# $Header: /cvsroot/pgsql/src/backend/catalog/Makefile,v 1.41 2002/07/12 18:43:13 tgl Exp $
# $Header: /cvsroot/pgsql/src/backend/catalog/Makefile,v 1.42 2002/07/18 23:11:27 petere Exp $
#
#-------------------------------------------------------------------------
@@ -30,7 +30,7 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h \
pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \
pg_depend.h indexing.h \
)

View File

@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.4 2002/07/18 16:47:22 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.5 2002/07/18 23:11:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,6 +47,7 @@
/* This enum covers all system catalogs whose OIDs can appear in classid. */
typedef enum ObjectClasses
{
OCLASS_CAST, /* pg_cast */
OCLASS_CLASS, /* pg_class */
OCLASS_PROC, /* pg_proc */
OCLASS_TYPE, /* pg_type */
@@ -604,6 +605,10 @@ doDeletion(const ObjectAddress *object)
RemoveSchemaById(object->objectId);
break;
case OCLASS_CAST:
DropCastById(object->objectId);
break;
default:
elog(ERROR, "doDeletion: Unsupported object class %u",
object->classId);
@@ -979,6 +984,7 @@ term_object_addresses(ObjectAddresses *addrs)
static void
init_object_classes(void)
{
object_classes[OCLASS_CAST] = get_system_catalog_relid(CastRelationName);
object_classes[OCLASS_CLASS] = RelOid_pg_class;
object_classes[OCLASS_PROC] = RelOid_pg_proc;
object_classes[OCLASS_TYPE] = RelOid_pg_type;
@@ -1023,6 +1029,11 @@ getObjectClass(const ObjectAddress *object)
if (!object_classes_initialized)
init_object_classes();
if (object->classId == object_classes[OCLASS_CAST])
{
Assert(object->objectSubId == 0);
return OCLASS_CAST;
}
if (object->classId == object_classes[OCLASS_CONSTRAINT])
{
Assert(object->objectSubId == 0);
@@ -1078,6 +1089,10 @@ getObjectDescription(const ObjectAddress *object)
switch (getObjectClass(object))
{
case OCLASS_CAST:
appendStringInfo(&buffer, "cast");
break;
case OCLASS_CLASS:
getRelationDescription(&buffer, object->objectId);
if (object->objectSubId != 0)

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.97 2002/07/15 16:33:31 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.98 2002/07/18 23:11:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -43,6 +43,8 @@ char *Name_pg_attr_indices[Num_pg_attr_indices] =
{AttributeRelidNameIndex, AttributeRelidNumIndex};
char *Name_pg_attrdef_indices[Num_pg_attrdef_indices] =
{AttrDefaultIndex, AttrDefaultOidIndex};
char *Name_pg_cast_indices[Num_pg_cast_indices] =
{CastSourceTargetIndex};
char *Name_pg_class_indices[Num_pg_class_indices] =
{ClassNameNspIndex, ClassOidIndex};
char *Name_pg_constraint_indices[Num_pg_constraint_indices] =

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.50 2002/07/16 22:12:18 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.51 2002/07/18 23:11:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -144,7 +144,6 @@ AggregateCreate(const char *aggName,
"-", /* probin */
true, /* isAgg */
false, /* security invoker (currently not definable for agg) */
false, /* isImplicit */
false, /* isStrict (not needed for agg) */
PROVOLATILE_IMMUTABLE, /* volatility (not needed for agg) */
BYTE_PCT, /* default cost values */

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.78 2002/07/18 16:47:23 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.79 2002/07/18 23:11:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -55,7 +55,6 @@ ProcedureCreate(const char *procedureName,
const char *probin,
bool isAgg,
bool security_definer,
bool isImplicit,
bool isStrict,
char volatility,
int32 byte_pct,
@@ -163,7 +162,7 @@ ProcedureCreate(const char *procedureName,
values[i++] = ObjectIdGetDatum(languageObjectId); /* prolang */
values[i++] = BoolGetDatum(isAgg); /* proisagg */
values[i++] = BoolGetDatum(security_definer); /* prosecdef */
values[i++] = BoolGetDatum(isImplicit); /* proimplicit */
values[i++] = BoolGetDatum(false); /* proimplicit */
values[i++] = BoolGetDatum(isStrict); /* proisstrict */
values[i++] = BoolGetDatum(returnsSet); /* proretset */
values[i++] = CharGetDatum(volatility); /* provolatile */

View File

@@ -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);
}

View File

@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.346 2002/07/18 17:14:19 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.347 2002/07/18 23:11:27 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -135,13 +135,13 @@ static void doNegateFloat(Value *v);
AlterDatabaseSetStmt, AlterGroupStmt,
AlterTableStmt, AlterUserStmt, AlterUserSetStmt,
AnalyzeStmt, ClosePortalStmt, ClusterStmt, CommentStmt,
ConstraintsSetStmt, CopyStmt, CreateAsStmt,
ConstraintsSetStmt, CopyStmt, CreateAsStmt, CreateCastStmt,
CreateDomainStmt, CreateGroupStmt, CreatePLangStmt,
CreateSchemaStmt, CreateSeqStmt, CreateStmt,
CreateAssertStmt, CreateTrigStmt, CreateUserStmt,
CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropStmt,
DropAssertStmt, DropTrigStmt, DropRuleStmt,
DropAssertStmt, DropTrigStmt, DropRuleStmt, DropCastStmt,
DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt,
LockStmt, NotifyStmt, OptimizableStmt,
@@ -165,7 +165,7 @@ static void doNegateFloat(Value *v);
%type <defelt> createdb_opt_item, copy_opt_item
%type <ival> opt_lock, lock_type
%type <boolean> opt_force, opt_or_replace
%type <boolean> opt_force, opt_or_replace, opt_assignment
%type <list> user_list
@@ -346,7 +346,7 @@ static void doNegateFloat(Value *v);
HANDLER, HAVING, HOUR_P,
ILIKE, IMMEDIATE, IMMUTABLE, IMPLICIT, IN_P, INCREMENT,
ILIKE, IMMEDIATE, IMMUTABLE, IN_P, INCREMENT,
INDEX, INHERITS, INITIALLY, INNER_P, INOUT, INPUT,
INSENSITIVE, INSERT, INSTEAD, INT, INTEGER, INTERSECT,
INTERVAL, INTO, INVOKER, IS, ISNULL, ISOLATION,
@@ -475,6 +475,7 @@ stmt :
| CopyStmt
| CreateStmt
| CreateAsStmt
| CreateCastStmt
| CreateDomainStmt
| CreateFunctionStmt
| CreateSchemaStmt
@@ -489,6 +490,7 @@ stmt :
| DropStmt
| TruncateStmt
| CommentStmt
| DropCastStmt
| DropGroupStmt
| DropPLangStmt
| DropAssertStmt
@@ -2886,15 +2888,6 @@ RecipeStmt: EXECUTE RECIPE recipe_name
* as <filename or code in language as appropriate>
* language <lang> [with parameters]
*
* CAST() form allowing all options from the CREATE FUNCTION form:
* create [or replace] cast (<type> as <type>)
* as <filename or code in language as appropriate>
* language <lang> [with parameters]
*
* SQL99 CAST() form (requires a function to be previously defined):
* create [or replace] cast (<type> as <type>)
* with function fname (<type>) [as assignment]
*
*****************************************************************************/
CreateFunctionStmt:
@@ -2910,63 +2903,6 @@ CreateFunctionStmt:
n->withClause = $9;
$$ = (Node *)n;
}
/* CREATE CAST SQL99 standard form */
| CREATE opt_or_replace CAST '(' func_type AS func_type ')'
WITH FUNCTION func_name func_args opt_assignment opt_definition
{
CreateFunctionStmt *n;
char buf[256];
n = makeNode(CreateFunctionStmt);
n->replace = $2;
n->funcname = $7->names;
n->argTypes = makeList1($5);
n->returnType = $7;
/* expand this into a string of SQL language */
strcpy(buf, "select ");
strcat(buf, ((Value *)lfirst($11))->val.str);
strcat(buf, "($1)");
n->options = lappend($14, makeDefElem("as", (Node *)makeList1(makeString(pstrdup(buf)))));
/* make sure that this will allow implicit casting */
n->options = lappend(n->options,
makeDefElem("implicit", (Node *)makeInteger(TRUE)));
/* and mention that this is SQL language */
n->options = lappend(n->options,
makeDefElem("language", (Node *)makeString(pstrdup("sql"))));
$$ = (Node *)n;
}
/* CREATE CAST SQL99 minimally variant form */
| CREATE opt_or_replace CAST '(' func_type AS func_type ')'
WITH FUNCTION func_name func_args AS Sconst opt_definition
{
CreateFunctionStmt *n;
n = makeNode(CreateFunctionStmt);
n->replace = $2;
n->funcname = $7->names;
n->argTypes = makeList1($5);
n->returnType = $7;
n->options = lappend($15, makeDefElem("as", (Node *)lcons(makeList1(makeString($14)), $11)));
/* make sure that this will allow implicit casting */
n->options = lappend(n->options,
makeDefElem("implicit", (Node *)makeInteger(TRUE)));
n->options = lappend(n->options,
makeDefElem("language", (Node *)makeString(pstrdup("c"))));
$$ = (Node *)n;
}
/* CREATE CAST with mostly CREATE FUNCTION clauses */
| CREATE opt_or_replace CAST '(' func_type AS func_type ')'
createfunc_opt_list opt_definition
{
CreateFunctionStmt *n;
n = makeNode(CreateFunctionStmt);
n->replace = $2;
n->funcname = $7->names;
n->argTypes = makeList1($5);
n->returnType = $7;
/* make sure that this will allow implicit casting */
n->options = lappend($9, makeDefElem("implicit", (Node *)makeInteger(TRUE)));
n->withClause = $10;
$$ = (Node *)n;
}
;
opt_or_replace:
@@ -3090,10 +3026,6 @@ createfunc_opt_item:
{
$$ = makeDefElem("security", (Node *)makeInteger(FALSE));
}
| IMPLICIT CAST
{
$$ = makeDefElem("implicit", (Node *)makeInteger(TRUE));
}
;
func_as: Sconst { $$ = makeList1(makeString($1)); }
@@ -3108,10 +3040,6 @@ opt_definition:
| /*EMPTY*/ { $$ = NIL; }
;
opt_assignment: AS ASSIGNMENT {}
| /*EMPTY*/ {}
;
/*****************************************************************************
*
@@ -3132,14 +3060,6 @@ RemoveFuncStmt:
n->behavior = $5;
$$ = (Node *)n;
}
| DROP CAST '(' func_type AS func_type ')' opt_drop_behavior
{
RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
n->funcname = $6->names;
n->args = makeList1($4);
n->behavior = $8;
$$ = (Node *)n;
}
;
RemoveAggrStmt:
@@ -3190,6 +3110,49 @@ any_operator:
;
/*****************************************************************************
*
* CREATE CAST / DROP CAST
*
*****************************************************************************/
CreateCastStmt: CREATE CAST '(' ConstTypename AS ConstTypename ')'
WITH FUNCTION function_with_argtypes opt_assignment
{
CreateCastStmt *n = makeNode(CreateCastStmt);
n->sourcetype = $4;
n->targettype = $6;
n->func = (FuncWithArgs *) $10;
n->implicit = $11;
$$ = (Node *)n;
}
| CREATE CAST '(' ConstTypename AS ConstTypename ')'
WITHOUT FUNCTION opt_assignment
{
CreateCastStmt *n = makeNode(CreateCastStmt);
n->sourcetype = $4;
n->targettype = $6;
n->func = NULL;
n->implicit = $10;
$$ = (Node *)n;
}
opt_assignment: AS ASSIGNMENT { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
DropCastStmt: DROP CAST '(' ConstTypename AS ConstTypename ')' opt_drop_behavior
{
DropCastStmt *n = makeNode(DropCastStmt);
n->sourcetype = $4;
n->targettype = $6;
n->behavior = $8;
$$ = (Node *)n;
}
/*****************************************************************************
*
* QUERY:
@@ -6701,7 +6664,6 @@ unreserved_keyword:
| HOUR_P
| IMMEDIATE
| IMMUTABLE
| IMPLICIT
| INCREMENT
| INDEX
| INHERITS

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.121 2002/07/18 17:14:19 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.122 2002/07/18 23:11:28 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -142,7 +142,6 @@ static const ScanKeyword ScanKeywords[] = {
{"ilike", ILIKE},
{"immediate", IMMEDIATE},
{"immutable", IMMUTABLE},
{"implicit", IMPLICIT},
{"in", IN_P},
{"increment", INCREMENT},
{"index", INDEX},

View File

@@ -8,12 +8,13 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.77 2002/07/09 13:52:14 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.78 2002/07/18 23:11:28 petere Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_proc.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
@@ -31,8 +32,9 @@ Oid PromoteTypeToNext(Oid inType);
static Oid PreferredType(CATEGORY category, Oid type);
static Node *build_func_call(Oid funcid, Oid rettype, List *args);
static Oid find_coercion_function(Oid targetTypeId, Oid inputTypeId,
Oid secondArgType, bool isExplicit);
static Oid find_coercion_function(Oid targetTypeId, Oid sourceTypeId,
bool isExplicit);
static Oid find_typmod_coercion_function(Oid typeId);
static Node *TypeConstraints(Node *arg, Oid typeId);
/* coerce_type()
@@ -142,7 +144,6 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
funcId = find_coercion_function(baseTypeId,
getBaseType(inputTypeId),
InvalidOid,
isExplicit);
if (!OidIsValid(funcId))
elog(ERROR, "coerce_type: no conversion function from '%s' to '%s'",
@@ -258,7 +259,6 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
*/
funcId = find_coercion_function(getBaseType(targetTypeId),
getBaseType(inputTypeId),
InvalidOid,
isExplicit);
if (!OidIsValid(funcId))
return false;
@@ -312,8 +312,7 @@ coerce_type_typmod(ParseState *pstate, Node *node,
if (atttypmod < 0 || atttypmod == exprTypmod(node))
return node;
/* Note this is always implicit coercion */
funcId = find_coercion_function(baseTypeId, baseTypeId, INT4OID, false);
funcId = find_typmod_coercion_function(baseTypeId);
if (OidIsValid(funcId))
{
Const *cons;
@@ -621,21 +620,25 @@ TypeCategory(Oid inType)
static bool
DirectlyBinaryCompatible(Oid type1, Oid type2)
{
HeapTuple tuple;
bool result;
if (type1 == type2)
return true;
if (TypeIsTextGroup(type1) && TypeIsTextGroup(type2))
return true;
if (TypeIsInt4GroupA(type1) && TypeIsInt4GroupA(type2))
return true;
if (TypeIsInt4GroupB(type1) && TypeIsInt4GroupB(type2))
return true;
if (TypeIsInt4GroupC(type1) && TypeIsInt4GroupC(type2))
return true;
if (TypeIsInetGroup(type1) && TypeIsInetGroup(type2))
return true;
if (TypeIsBitGroup(type1) && TypeIsBitGroup(type2))
return true;
return false;
tuple = SearchSysCache(CASTSOURCETARGET, type1, type2, 0, 0);
if (HeapTupleIsValid(tuple))
{
Form_pg_cast caststruct;
caststruct = (Form_pg_cast) GETSTRUCT(tuple);
result = caststruct->castfunc == InvalidOid && caststruct->castimplicit;
ReleaseSysCache(tuple);
}
else
result = false;
return result;
}
@@ -750,34 +753,51 @@ PreferredType(CATEGORY category, Oid type)
* If a function is found, return its pg_proc OID; else return InvalidOid.
*/
static Oid
find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType,
bool isExplicit)
find_coercion_function(Oid targetTypeId, Oid sourceTypeId, bool isExplicit)
{
Oid funcid = InvalidOid;
HeapTuple tuple;
tuple = SearchSysCache(CASTSOURCETARGET,
ObjectIdGetDatum(sourceTypeId),
ObjectIdGetDatum(targetTypeId),
0, 0);
if (HeapTupleIsValid(tuple))
{
Form_pg_cast cform = (Form_pg_cast) GETSTRUCT(tuple);
if (isExplicit || cform->castimplicit)
funcid = cform->castfunc;
ReleaseSysCache(tuple);
}
return funcid;
}
static Oid
find_typmod_coercion_function(Oid typeId)
{
Oid funcid = InvalidOid;
Type targetType;
char *typname;
Oid typnamespace;
Oid oid_array[FUNC_MAX_ARGS];
int nargs;
HeapTuple ftup;
targetType = typeidType(targetTypeId);
targetType = typeidType(typeId);
typname = NameStr(((Form_pg_type) GETSTRUCT(targetType))->typname);
typnamespace = ((Form_pg_type) GETSTRUCT(targetType))->typnamespace;
MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
oid_array[0] = inputTypeId;
if (OidIsValid(secondArgType))
{
oid_array[1] = secondArgType;
nargs = 2;
}
else
nargs = 1;
oid_array[0] = typeId;
oid_array[1] = INT4OID;
ftup = SearchSysCache(PROCNAMENSP,
CStringGetDatum(typname),
Int16GetDatum(nargs),
Int16GetDatum(2),
PointerGetDatum(oid_array),
ObjectIdGetDatum(typnamespace));
if (HeapTupleIsValid(ftup))
@@ -785,15 +805,11 @@ find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType,
Form_pg_proc pform = (Form_pg_proc) GETSTRUCT(ftup);
/* Make sure the function's result type is as expected */
if (pform->prorettype == targetTypeId && !pform->proretset &&
if (pform->prorettype == typeId && !pform->proretset &&
!pform->proisagg)
{
/* If needed, make sure it can be invoked implicitly */
if (isExplicit || pform->proimplicit)
{
/* Okay to use it */
funcid = ftup->t_data->t_oid;
}
/* Okay to use it */
funcid = ftup->t_data->t_oid;
}
ReleaseSysCache(ftup);
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.271 2002/07/18 16:47:25 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.272 2002/07/18 23:11:28 petere Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -1693,7 +1693,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.271 $ $Date: 2002/07/18 16:47:25 $\n");
puts("$Revision: 1.272 $ $Date: 2002/07/18 23:11:28 $\n");
}
/*
@@ -2444,6 +2444,14 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE CONVERSION";
break;
case T_CreateCastStmt:
tag = "CREATE CAST";
break;
case T_DropCastStmt:
tag = "DROP CAST";
break;
default:
elog(LOG, "CreateCommandTag: unknown parse node type %d",
nodeTag(parsetree));

View File

@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.163 2002/07/18 16:47:25 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.164 2002/07/18 23:11:28 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -829,6 +829,14 @@ ProcessUtility(Node *parsetree,
}
break;
case T_CreateCastStmt:
CreateCast((CreateCastStmt *) parsetree);
break;
case T_DropCastStmt:
DropCast((DropCastStmt *) parsetree);
break;
default:
elog(ERROR, "ProcessUtility: command #%d unsupported",
nodeTag(parsetree));

View File

@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.111 2002/07/18 17:14:20 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.112 2002/07/18 23:11:28 petere Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -43,6 +43,7 @@
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_index.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
@@ -2048,9 +2049,9 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
* Strip any type coercions at the top of the given expression tree,
* as long as they are coercions to the given datatype.
*
* A RelabelType node is always a type coercion. A function call is also
* considered a type coercion if it has one argument and the function name
* is the same as the (internal) name of its result type.
* A RelabelType node is always a type coercion. A function call is
* also considered a type coercion if it has one argument and there is
* a cast declared that uses it.
*
* XXX It'd be better if the parsetree retained some explicit indication
* of the coercion, so we didn't need these heuristics.
@@ -2069,9 +2070,9 @@ strip_type_coercion(Node *expr, Oid resultType)
{
Func *func;
HeapTuple procTuple;
HeapTuple typeTuple;
HeapTuple castTuple;
Form_pg_proc procStruct;
Form_pg_type typeStruct;
Form_pg_cast castStruct;
func = (Func *) (((Expr *) expr)->oper);
Assert(IsA(func, Func));
@@ -2085,33 +2086,33 @@ strip_type_coercion(Node *expr, Oid resultType)
elog(ERROR, "cache lookup for proc %u failed", func->funcid);
procStruct = (Form_pg_proc) GETSTRUCT(procTuple);
/* Double-check func has one arg and correct result type */
/* Also, it must be an implicit coercion function */
if (procStruct->pronargs != 1 ||
procStruct->prorettype != resultType ||
!procStruct->proimplicit)
procStruct->prorettype != resultType)
{
ReleaseSysCache(procTuple);
return expr;
}
/* See if function has same name/namespace as its result type */
typeTuple = SearchSysCache(TYPEOID,
ObjectIdGetDatum(procStruct->prorettype),
0, 0, 0);
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup for type %u failed",
procStruct->prorettype);
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
if (strcmp(NameStr(procStruct->proname),
NameStr(typeStruct->typname)) != 0 ||
procStruct->pronamespace != typeStruct->typnamespace)
/* See if function has is actually declared as a cast */
castTuple = SearchSysCache(CASTSOURCETARGET,
ObjectIdGetDatum(procStruct->proargtypes[0]),
ObjectIdGetDatum(procStruct->prorettype),
0, 0);
if (!HeapTupleIsValid(castTuple))
{
ReleaseSysCache(procTuple);
ReleaseSysCache(typeTuple);
return expr;
}
/* It must also be an implicit cast. */
castStruct = (Form_pg_cast) GETSTRUCT(castTuple);
if (!castStruct->castimplicit)
{
ReleaseSysCache(procTuple);
ReleaseSysCache(castTuple);
return expr;
}
/* Okay, it is indeed a type-coercion function */
ReleaseSysCache(procTuple);
ReleaseSysCache(typeTuple);
ReleaseSysCache(castTuple);
return strip_type_coercion(lfirst(((Expr *) expr)->args), resultType);
}

View File

@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.46 2002/06/20 20:29:38 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.47 2002/07/18 23:11:29 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -63,7 +63,6 @@ SetDefine(char *querystr, Oid elemType)
fileName, /* probin */
false, /* not aggregate */
false, /* security invoker */
false, /* not implicit coercion */
false, /* isStrict (irrelevant, no args) */
PROVOLATILE_VOLATILE, /* assume unsafe */
100, /* byte_pct */

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.81 2002/07/11 07:39:27 ishii Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.82 2002/07/18 23:11:29 petere Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
@@ -28,6 +28,7 @@
#include "catalog/pg_aggregate.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_group.h"
#include "catalog/pg_index.h"
@@ -174,6 +175,17 @@ static const struct cachedesc cacheinfo[] = {
0,
0
}},
{
CastRelationName, /* CASTSOURCETARGET */
CastSourceTargetIndex,
0,
2,
{
Anum_pg_cast_castsource,
Anum_pg_cast_casttarget,
0,
0
}},
{OperatorClassRelationName, /* CLAAMNAMENSP */
OpclassAmNameNspIndex,
0,