mirror of
https://github.com/postgres/postgres.git
synced 2025-08-22 21:53:06 +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:
@@ -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
|
||||
|
@@ -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},
|
||||
|
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user