Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
681ed4e2
Commit
681ed4e2
authored
Sep 01, 2002
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Code cleanups: make non-implicit WITHOUT FUNCTION casts work, avoid
redundant pg_cast searches, fix obsolete comments.
parent
a03f9adb
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
266 additions
and
299 deletions
+266
-299
src/backend/parser/parse_coerce.c
src/backend/parser/parse_coerce.c
+266
-299
No files found.
src/backend/parser/parse_coerce.c
View file @
681ed4e2
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.8
1 2002/08/31 22:10:46
tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.8
2 2002/09/01 02:27:32
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -27,24 +27,27 @@
...
@@ -27,24 +27,27 @@
#include "utils/syscache.h"
#include "utils/syscache.h"
Oid
DemoteType
(
Oid
inType
);
Oid
PromoteTypeToNext
(
Oid
inType
);
static
Oid
PreferredType
(
CATEGORY
category
,
Oid
type
);
static
Oid
PreferredType
(
CATEGORY
category
,
Oid
type
);
static
Node
*
build_func_call
(
Oid
funcid
,
Oid
rettype
,
List
*
args
);
static
bool
find_coercion_pathway
(
Oid
targetTypeId
,
Oid
sourceTypeId
,
static
Oid
find_coercion_function
(
Oid
targetTypeId
,
Oid
sourceTypeId
,
bool
isExplicit
,
bool
isExplicit
);
Oid
*
funcid
);
static
Oid
find_typmod_coercion_function
(
Oid
typeId
);
static
Oid
find_typmod_coercion_function
(
Oid
typeId
);
static
Node
*
build_func_call
(
Oid
funcid
,
Oid
rettype
,
List
*
args
);
/* coerce_type()
/*
* Convert a function argument to a different type.
* coerce_type()
* Convert a function argument to a different type.
*
* The caller should already have determined that the coercion is possible;
* see can_coerce_type.
*/
*/
Node
*
Node
*
coerce_type
(
ParseState
*
pstate
,
Node
*
node
,
Oid
inputTypeId
,
coerce_type
(
ParseState
*
pstate
,
Node
*
node
,
Oid
inputTypeId
,
Oid
targetTypeId
,
int32
atttypmod
,
bool
isExplicit
)
Oid
targetTypeId
,
int32
atttypmod
,
bool
isExplicit
)
{
{
Node
*
result
;
Node
*
result
;
Oid
funcId
;
if
(
targetTypeId
==
inputTypeId
||
if
(
targetTypeId
==
inputTypeId
||
node
==
NULL
)
node
==
NULL
)
...
@@ -118,25 +121,71 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
...
@@ -118,25 +121,71 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
/* assume can_coerce_type verified that implicit coercion is okay */
/* assume can_coerce_type verified that implicit coercion is okay */
result
=
node
;
result
=
node
;
}
}
else
if
(
IsBinaryCompatible
(
inputTypeId
,
targetTypeId
))
else
if
(
find_coercion_pathway
(
targetTypeId
,
inputTypeId
,
isExplicit
,
&
funcId
))
{
{
/*
if
(
OidIsValid
(
funcId
))
* We don't really need to do a conversion, but we do need to
{
* attach a RelabelType node so that the expression will be seen
/*
* to have the intended type when inspected by higher-level code.
* Generate an expression tree representing run-time application
*
* of the conversion function. If we are dealing with a domain
* Also, domains may have value restrictions beyond the base type
* target type, the conversion function will yield the base type.
* that must be accounted for.
*/
*/
Oid
baseTypeId
=
getBaseType
(
targetTypeId
);
result
=
coerce_type_constraints
(
pstate
,
node
,
targetTypeId
,
true
);
/*
result
=
build_func_call
(
funcId
,
baseTypeId
,
makeList1
(
node
));
* XXX could we label result with exprTypmod(node) instead of
* default -1 typmod, to save a possible length-coercion later?
/*
* Would work if both types have same interpretation of typmod,
* If domain, test against domain constraints and relabel with
* which is likely but not certain (wrong if target is a domain,
* domain type ID
* in any case).
*/
*/
if
(
targetTypeId
!=
baseTypeId
)
result
=
(
Node
*
)
makeRelabelType
(
result
,
targetTypeId
,
-
1
);
{
result
=
coerce_type_constraints
(
pstate
,
result
,
targetTypeId
,
true
);
result
=
(
Node
*
)
makeRelabelType
(
result
,
targetTypeId
,
-
1
);
}
/*
* If the input is a constant, apply the type conversion function
* now instead of delaying to runtime. (We could, of course, just
* leave this to be done during planning/optimization; but it's a
* very frequent special case, and we save cycles in the rewriter
* if we fold the expression now.)
*
* Note that no folding will occur if the conversion function is
* not marked 'immutable'.
*
* HACK: if constant is NULL, don't fold it here. This is needed
* by make_subplan(), which calls this routine on placeholder
* Const nodes that mustn't be collapsed. (It'd be a lot cleaner
* to make a separate node type for that purpose...)
*/
if
(
IsA
(
node
,
Const
)
&&
!
((
Const
*
)
node
)
->
constisnull
)
result
=
eval_const_expressions
(
result
);
}
else
{
/*
* We don't need to do a physical conversion, but we do need to
* attach a RelabelType node so that the expression will be seen
* to have the intended type when inspected by higher-level code.
*
* Also, domains may have value restrictions beyond the base type
* that must be accounted for.
*/
result
=
coerce_type_constraints
(
pstate
,
node
,
targetTypeId
,
true
);
/*
* XXX could we label result with exprTypmod(node) instead of
* default -1 typmod, to save a possible length-coercion later?
* Would work if both types have same interpretation of typmod,
* which is likely but not certain (wrong if target is a domain,
* in any case).
*/
result
=
(
Node
*
)
makeRelabelType
(
result
,
targetTypeId
,
-
1
);
}
}
}
else
if
(
typeInheritsFrom
(
inputTypeId
,
targetTypeId
))
else
if
(
typeInheritsFrom
(
inputTypeId
,
targetTypeId
))
{
{
...
@@ -149,74 +198,23 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
...
@@ -149,74 +198,23 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
}
}
else
else
{
{
/*
/* If we get here, caller blew it */
* Otherwise, find the appropriate type conversion function
elog
(
ERROR
,
"coerce_type: no conversion function from %s to %s"
,
* (caller should have determined that there is one), and generate
format_type_be
(
inputTypeId
),
format_type_be
(
targetTypeId
));
* an expression tree representing run-time application of the
result
=
NULL
;
/* keep compiler quiet */
* conversion function.
*
* For domains, we use the coercion function for the base type.
*/
Oid
baseTypeId
=
getBaseType
(
targetTypeId
);
Oid
funcId
;
funcId
=
find_coercion_function
(
baseTypeId
,
getBaseType
(
inputTypeId
),
isExplicit
);
if
(
!
OidIsValid
(
funcId
))
elog
(
ERROR
,
"coerce_type: no conversion function from '%s' to '%s'"
,
format_type_be
(
inputTypeId
),
format_type_be
(
targetTypeId
));
result
=
build_func_call
(
funcId
,
baseTypeId
,
makeList1
(
node
));
/*
* If domain, test against domain constraints and relabel with
* domain type ID
*/
if
(
targetTypeId
!=
baseTypeId
)
{
result
=
coerce_type_constraints
(
pstate
,
result
,
targetTypeId
,
true
);
result
=
(
Node
*
)
makeRelabelType
(
result
,
targetTypeId
,
-
1
);
}
/*
* If the input is a constant, apply the type conversion function
* now instead of delaying to runtime. (We could, of course, just
* leave this to be done during planning/optimization; but it's a
* very frequent special case, and we save cycles in the rewriter
* if we fold the expression now.)
*
* Note that no folding will occur if the conversion function is not
* marked 'iscachable'.
*
* HACK: if constant is NULL, don't fold it here. This is needed by
* make_subplan(), which calls this routine on placeholder Const
* nodes that mustn't be collapsed. (It'd be a lot cleaner to
* make a separate node type for that purpose...)
*/
if
(
IsA
(
node
,
Const
)
&&
!
((
Const
*
)
node
)
->
constisnull
)
result
=
eval_const_expressions
(
result
);
}
}
return
result
;
return
result
;
}
}
/* can_coerce_type()
/*
* Can input_typeids be coerced to func_typeids?
* can_coerce_type()
*
* Can input_typeids be coerced to func_typeids?
* There are a few types which are known apriori to be convertible.
* We will check for those cases first, and then look for possible
* conversion functions.
*
*
* We must be told whether this is an implicit or explicit coercion
* We must be told whether this is an implicit or explicit coercion
* (explicit being a CAST construct, explicit function call, etc).
* (explicit being a CAST construct, explicit function call, etc).
* We will accept a wider set of coercion cases for an explicit coercion.
* We will accept a wider set of coercion cases for an explicit coercion.
*
* Notes:
* This uses the same mechanism as the CAST() SQL construct in gram.y.
*/
*/
bool
bool
can_coerce_type
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
func_typeids
,
can_coerce_type
(
int
nargs
,
Oid
*
input_typeids
,
Oid
*
func_typeids
,
...
@@ -278,35 +276,101 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
...
@@ -278,35 +276,101 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
}
}
/*
/*
*
one of the known-good transparent conversions? then drop
*
If pg_cast shows that we can coerce, accept. This test now
*
through..
.
*
covers both binary-compatible and coercion-function cases
.
*/
*/
if
(
IsBinaryCompatible
(
inputTypeId
,
targetTypeId
))
if
(
find_coercion_pathway
(
targetTypeId
,
inputTypeId
,
isExplicit
,
&
funcId
))
continue
;
continue
;
/*
/*
* If input is a class type that inherits from target,
no problem
* If input is a class type that inherits from target,
accept
*/
*/
if
(
typeInheritsFrom
(
inputTypeId
,
targetTypeId
))
if
(
typeInheritsFrom
(
inputTypeId
,
targetTypeId
))
continue
;
continue
;
/*
/*
* Else, try for run-time conversion using functions: look for a
* Else, cannot coerce at this argument position
* single-argument function named with the target type name and
* accepting the source type.
*
* If either type is a domain, use its base type instead.
*/
*/
funcId
=
find_coercion_function
(
getBaseType
(
targetTypeId
),
return
false
;
getBaseType
(
inputTypeId
),
isExplicit
);
if
(
!
OidIsValid
(
funcId
))
return
false
;
}
}
return
true
;
return
true
;
}
}
/*
* Create an expression tree to enforce the constraints (if any)
* that should be applied by the type. Currently this is only
* interesting for domain types.
*/
Node
*
coerce_type_constraints
(
ParseState
*
pstate
,
Node
*
arg
,
Oid
typeId
,
bool
applyTypmod
)
{
char
*
notNull
=
NULL
;
int32
typmod
=
-
1
;
for
(;;)
{
HeapTuple
tup
;
Form_pg_type
typTup
;
tup
=
SearchSysCache
(
TYPEOID
,
ObjectIdGetDatum
(
typeId
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
tup
))
elog
(
ERROR
,
"coerce_type_constraints: failed to lookup type %u"
,
typeId
);
typTup
=
(
Form_pg_type
)
GETSTRUCT
(
tup
);
/* Test for NOT NULL Constraint */
if
(
typTup
->
typnotnull
&&
notNull
==
NULL
)
notNull
=
pstrdup
(
NameStr
(
typTup
->
typname
));
/* TODO: Add CHECK Constraints to domains */
if
(
typTup
->
typtype
!=
'd'
)
{
/* Not a domain, so done */
ReleaseSysCache
(
tup
);
break
;
}
Assert
(
typmod
<
0
);
typeId
=
typTup
->
typbasetype
;
typmod
=
typTup
->
typtypmod
;
ReleaseSysCache
(
tup
);
}
/*
* If domain applies a typmod to its base type, do length coercion.
*/
if
(
applyTypmod
&&
typmod
>=
0
)
arg
=
coerce_type_typmod
(
pstate
,
arg
,
typeId
,
typmod
);
/*
* Only need to add one NOT NULL check regardless of how many
* domains in the stack request it. The topmost domain that
* requested it is used as the constraint name.
*/
if
(
notNull
)
{
ConstraintTest
*
r
=
makeNode
(
ConstraintTest
);
r
->
arg
=
arg
;
r
->
testtype
=
CONSTR_TEST_NOTNULL
;
r
->
name
=
notNull
;
r
->
check_expr
=
NULL
;
arg
=
(
Node
*
)
r
;
}
return
arg
;
}
/* coerce_type_typmod()
/* coerce_type_typmod()
* Force a value to a particular typmod, if meaningful and possible.
* Force a value to a particular typmod, if meaningful and possible.
*
*
...
@@ -317,21 +381,9 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
...
@@ -317,21 +381,9 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
* The caller must have already ensured that the value is of the correct
* The caller must have already ensured that the value is of the correct
* type, typically by applying coerce_type.
* type, typically by applying coerce_type.
*
*
* If the target column type possesses a function named for the type
* and having parameter signature (columntype, int4), we assume that
* the type requires coercion to its own length and that the said
* function should be invoked to do that.
*
* "bpchar" (ie, char(N)) and "numeric" are examples of such types.
*
* This mechanism may seem pretty grotty and in need of replacement by
* something in pg_cast, but since typmod is only interesting for datatypes
* that have special handling in the grammar, there's not really much
* percentage in making it any easier to apply such coercions ...
*
* NOTE: this does not need to work on domain types, because any typmod
* NOTE: this does not need to work on domain types, because any typmod
* coercion for a domain is considered to be part of the type coercion
* coercion for a domain is considered to be part of the type coercion
* needed to produce the domain value in the first place.
* needed to produce the domain value in the first place.
So, no getBaseType.
*/
*/
Node
*
Node
*
coerce_type_typmod
(
ParseState
*
pstate
,
Node
*
node
,
coerce_type_typmod
(
ParseState
*
pstate
,
Node
*
node
,
...
@@ -600,100 +652,6 @@ TypeCategory(Oid inType)
...
@@ -600,100 +652,6 @@ TypeCategory(Oid inType)
}
/* TypeCategory() */
}
/* TypeCategory() */
/* IsBinaryCompatible()
* Check if two types are binary-compatible.
*
* This notion allows us to cheat and directly exchange values without
* going through the trouble of calling a conversion function.
*
* XXX This should be moved to system catalog lookups
* to allow for better type extensibility.
*/
#define TypeIsTextGroup(t) \
((t) == TEXTOID || \
(t) == BPCHAROID || \
(t) == VARCHAROID)
/* Notice OidGroup is a subset of Int4GroupA */
#define TypeIsOidGroup(t) \
((t) == OIDOID || \
(t) == REGPROCOID || \
(t) == REGPROCEDUREOID || \
(t) == REGOPEROID || \
(t) == REGOPERATOROID || \
(t) == REGCLASSOID || \
(t) == REGTYPEOID)
/*
* INT4 is binary-compatible with many types, but we don't want to allow
* implicit coercion directly between, say, OID and AbsTime. So we subdivide
* the categories.
*/
#define TypeIsInt4GroupA(t) \
((t) == INT4OID || \
TypeIsOidGroup(t))
#define TypeIsInt4GroupB(t) \
((t) == INT4OID || \
(t) == ABSTIMEOID)
#define TypeIsInt4GroupC(t) \
((t) == INT4OID || \
(t) == RELTIMEOID)
#define TypeIsInetGroup(t) \
((t) == INETOID || \
(t) == CIDROID)
#define TypeIsBitGroup(t) \
((t) == BITOID || \
(t) == VARBITOID)
static
bool
DirectlyBinaryCompatible
(
Oid
type1
,
Oid
type2
)
{
HeapTuple
tuple
;
bool
result
;
if
(
type1
==
type2
)
return
true
;
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
;
}
bool
IsBinaryCompatible
(
Oid
type1
,
Oid
type2
)
{
if
(
DirectlyBinaryCompatible
(
type1
,
type2
))
return
true
;
/*
* Perhaps the types are domains; if so, look at their base types
*/
if
(
OidIsValid
(
type1
))
type1
=
getBaseType
(
type1
);
if
(
OidIsValid
(
type2
))
type2
=
getBaseType
(
type2
);
if
(
DirectlyBinaryCompatible
(
type1
,
type2
))
return
true
;
return
false
;
}
/* IsPreferredType()
/* IsPreferredType()
* Check if this type is a preferred type.
* Check if this type is a preferred type.
* XXX This should be moved to system catalog lookups
* XXX This should be moved to system catalog lookups
...
@@ -733,7 +691,13 @@ PreferredType(CATEGORY category, Oid type)
...
@@ -733,7 +691,13 @@ PreferredType(CATEGORY category, Oid type)
break
;
break
;
case
(
NUMERIC_TYPE
):
case
(
NUMERIC_TYPE
):
if
(
TypeIsOidGroup
(
type
))
if
(
type
==
OIDOID
||
type
==
REGPROCOID
||
type
==
REGPROCEDUREOID
||
type
==
REGOPEROID
||
type
==
REGOPERATOROID
||
type
==
REGCLASSOID
||
type
==
REGTYPEOID
)
result
=
OIDOID
;
result
=
OIDOID
;
else
if
(
type
==
NUMERICOID
)
else
if
(
type
==
NUMERICOID
)
result
=
NUMERICOID
;
result
=
NUMERICOID
;
...
@@ -768,30 +732,85 @@ PreferredType(CATEGORY category, Oid type)
...
@@ -768,30 +732,85 @@ PreferredType(CATEGORY category, Oid type)
return
result
;
return
result
;
}
/* PreferredType() */
}
/* PreferredType() */
/*
* find_coercion_function
/* IsBinaryCompatible()
*
Look for a coercion function between two types
.
*
Check if two types are binary-compatible
.
*
*
* A coercion function must be named after (the internal name of) its
* This notion allows us to cheat and directly exchange values without
* result type, and must accept exactly the specified input type. We
* going through the trouble of calling a conversion function.
* also require it to be defined in the same namespace as its result type.
* Furthermore, unless we are doing explicit coercion the function must
* be marked as usable for implicit coercion --- this allows coercion
* functions to be provided that aren't implicitly invokable.
*
*
* This routine is also used to look for length-coercion functions, which
* As of 7.3, binary compatibility isn't hardwired into the code anymore.
* are similar but accept a second argument. secondArgType is the type
* We consider two types binary-compatible if there is an implicit,
* of the second argument (normally INT4OID), or InvalidOid if we are
* no-function-needed pg_cast entry. NOTE that we assume that such
* looking for a regular coercion function.
* entries are symmetric, ie, it doesn't matter which type we consider
* source and which target. (cf. checks in opr_sanity regression test)
*/
bool
IsBinaryCompatible
(
Oid
type1
,
Oid
type2
)
{
HeapTuple
tuple
;
Form_pg_cast
castForm
;
bool
result
;
/* Fast path if same type */
if
(
type1
==
type2
)
return
true
;
/* Perhaps the types are domains; if so, look at their base types */
if
(
OidIsValid
(
type1
))
type1
=
getBaseType
(
type1
);
if
(
OidIsValid
(
type2
))
type2
=
getBaseType
(
type2
);
/* Somewhat-fast path if same base type */
if
(
type1
==
type2
)
return
true
;
/* Else look in pg_cast */
tuple
=
SearchSysCache
(
CASTSOURCETARGET
,
ObjectIdGetDatum
(
type1
),
ObjectIdGetDatum
(
type2
),
0
,
0
);
if
(
!
HeapTupleIsValid
(
tuple
))
return
false
;
/* no cast */
castForm
=
(
Form_pg_cast
)
GETSTRUCT
(
tuple
);
result
=
(
castForm
->
castfunc
==
InvalidOid
)
&&
castForm
->
castimplicit
;
ReleaseSysCache
(
tuple
);
return
result
;
}
/*
* find_coercion_pathway
* Look for a coercion pathway between two types.
*
*
* If a function is found, return its pg_proc OID; else return InvalidOid.
* If we find a matching entry in pg_cast, return TRUE, and set *funcid
* to the castfunc value (which may be InvalidOid for a binary-compatible
* coercion).
*/
*/
static
Oid
static
bool
find_coercion_function
(
Oid
targetTypeId
,
Oid
sourceTypeId
,
bool
isExplicit
)
find_coercion_pathway
(
Oid
targetTypeId
,
Oid
sourceTypeId
,
bool
isExplicit
,
Oid
*
funcid
)
{
{
Oid
funcid
=
InvalidOid
;
bool
result
=
false
;
HeapTuple
tuple
;
HeapTuple
tuple
;
*
funcid
=
InvalidOid
;
/* Perhaps the types are domains; if so, look at their base types */
if
(
OidIsValid
(
sourceTypeId
))
sourceTypeId
=
getBaseType
(
sourceTypeId
);
if
(
OidIsValid
(
targetTypeId
))
targetTypeId
=
getBaseType
(
targetTypeId
);
/* Domains are automatically binary-compatible with their base type */
if
(
sourceTypeId
==
targetTypeId
)
return
true
;
/* Else look in pg_cast */
tuple
=
SearchSysCache
(
CASTSOURCETARGET
,
tuple
=
SearchSysCache
(
CASTSOURCETARGET
,
ObjectIdGetDatum
(
sourceTypeId
),
ObjectIdGetDatum
(
sourceTypeId
),
ObjectIdGetDatum
(
targetTypeId
),
ObjectIdGetDatum
(
targetTypeId
),
...
@@ -799,18 +818,36 @@ find_coercion_function(Oid targetTypeId, Oid sourceTypeId, bool isExplicit)
...
@@ -799,18 +818,36 @@ find_coercion_function(Oid targetTypeId, Oid sourceTypeId, bool isExplicit)
if
(
HeapTupleIsValid
(
tuple
))
if
(
HeapTupleIsValid
(
tuple
))
{
{
Form_pg_cast
c
f
orm
=
(
Form_pg_cast
)
GETSTRUCT
(
tuple
);
Form_pg_cast
c
astF
orm
=
(
Form_pg_cast
)
GETSTRUCT
(
tuple
);
if
(
isExplicit
||
cform
->
castimplicit
)
if
(
isExplicit
||
castForm
->
castimplicit
)
funcid
=
cform
->
castfunc
;
{
*
funcid
=
castForm
->
castfunc
;
result
=
true
;
}
ReleaseSysCache
(
tuple
);
ReleaseSysCache
(
tuple
);
}
}
return
funcid
;
return
result
;
}
}
/*
* find_typmod_coercion_function -- does the given type need length coercion?
*
* If the target type possesses a function named for the type
* and having parameter signature (targettype, int4), we assume that
* the type requires coercion to its own length and that the said
* function should be invoked to do that.
*
* "bpchar" (ie, char(N)) and "numeric" are examples of such types.
*
* This mechanism may seem pretty grotty and in need of replacement by
* something in pg_cast, but since typmod is only interesting for datatypes
* that have special handling in the grammar, there's not really much
* percentage in making it any easier to apply such coercions ...
*/
static
Oid
static
Oid
find_typmod_coercion_function
(
Oid
typeId
)
find_typmod_coercion_function
(
Oid
typeId
)
{
{
...
@@ -849,6 +886,7 @@ find_typmod_coercion_function(Oid typeId)
...
@@ -849,6 +886,7 @@ find_typmod_coercion_function(Oid typeId)
}
}
ReleaseSysCache
(
targetType
);
ReleaseSysCache
(
targetType
);
return
funcid
;
return
funcid
;
}
}
...
@@ -877,74 +915,3 @@ build_func_call(Oid funcid, Oid rettype, List *args)
...
@@ -877,74 +915,3 @@ build_func_call(Oid funcid, Oid rettype, List *args)
return
(
Node
*
)
expr
;
return
(
Node
*
)
expr
;
}
}
/*
* Create an expression tree to enforce the constraints (if any)
* that should be applied by the type. Currently this is only
* interesting for domain types.
*/
Node
*
coerce_type_constraints
(
ParseState
*
pstate
,
Node
*
arg
,
Oid
typeId
,
bool
applyTypmod
)
{
char
*
notNull
=
NULL
;
int32
typmod
=
-
1
;
for
(;;)
{
HeapTuple
tup
;
Form_pg_type
typTup
;
tup
=
SearchSysCache
(
TYPEOID
,
ObjectIdGetDatum
(
typeId
),
0
,
0
,
0
);
if
(
!
HeapTupleIsValid
(
tup
))
elog
(
ERROR
,
"coerce_type_constraints: failed to lookup type %u"
,
typeId
);
typTup
=
(
Form_pg_type
)
GETSTRUCT
(
tup
);
/* Test for NOT NULL Constraint */
if
(
typTup
->
typnotnull
&&
notNull
==
NULL
)
notNull
=
pstrdup
(
NameStr
(
typTup
->
typname
));
/* TODO: Add CHECK Constraints to domains */
if
(
typTup
->
typtype
!=
'd'
)
{
/* Not a domain, so done */
ReleaseSysCache
(
tup
);
break
;
}
Assert
(
typmod
<
0
);
typeId
=
typTup
->
typbasetype
;
typmod
=
typTup
->
typtypmod
;
ReleaseSysCache
(
tup
);
}
/*
* If domain applies a typmod to its base type, do length coercion.
*/
if
(
applyTypmod
&&
typmod
>=
0
)
arg
=
coerce_type_typmod
(
pstate
,
arg
,
typeId
,
typmod
);
/*
* Only need to add one NOT NULL check regardless of how many
* domains in the stack request it. The topmost domain that
* requested it is used as the constraint name.
*/
if
(
notNull
)
{
ConstraintTest
*
r
=
makeNode
(
ConstraintTest
);
r
->
arg
=
arg
;
r
->
testtype
=
CONSTR_TEST_NOTNULL
;
r
->
name
=
notNull
;
r
->
check_expr
=
NULL
;
arg
=
(
Node
*
)
r
;
}
return
arg
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment