Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8272749

Browse files
committed
Record dependencies of a cast on other casts that it requires.
When creating a cast that uses a conversion function, we'vehistorically allowed the input and result types to bebinary-compatible with the function's input and result types,rather than necessarily being identical. This means that the newcast is logically dependent on the binary-compatible cast or caststhat it references: if those are defined by pg_cast entries, and youtry to restore the new cast without having defined them, it'll fail.Hence, we should make pg_depend entries to record these dependenciesso that pg_dump knows that there is an ordering requirement.This is not the only place where we allow such shortcuts; aggregatefunctions for example are similarly lax, and in principle should gainsimilar dependencies. However, for now it seems sufficient to fixthe cast-versus-cast case, as pg_dump's other ordering heuristicsshould keep it out of trouble for other object types.Per report from David Turoň; thanks also to Robert Haas forpreliminary investigation. I considered back-patching, butseeing that this issue has existed for many years withoutprevious reports, it's not clear it's worth the trouble.Moreover, back-patching wouldn't be enough to ensure that thenew pg_depend entries exist in existing databases anyway.Discussion:https://postgr.es/m/OF0A160F3E.578B15D1-ONC12588DA.003E4857-C12588DA.0045A428@notes.linuxbox.cz
1 parent797e313 commit8272749

File tree

9 files changed

+111
-9
lines changed

9 files changed

+111
-9
lines changed

‎src/backend/catalog/pg_cast.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,20 @@
3535
* Caller must have already checked privileges, and done consistency
3636
* checks on the given datatypes and cast function (if applicable).
3737
*
38+
* Since we allow binary coercibility of the datatypes to the cast
39+
* function's input and result, there could be one or two WITHOUT FUNCTION
40+
* casts that this one depends on. We don't record that explicitly
41+
* in pg_cast, but we still need to make dependencies on those casts.
42+
*
3843
* 'behavior' indicates the types of the dependencies that the new
39-
* cast will have on its input and output types and the cast function.
44+
* cast will have on its input and output types, the cast function,
45+
* and the other casts if any.
4046
* ----------------------------------------------------------------
4147
*/
4248
ObjectAddress
43-
CastCreate(Oidsourcetypeid,Oidtargettypeid,Oidfuncid,charcastcontext,
44-
charcastmethod,DependencyTypebehavior)
49+
CastCreate(Oidsourcetypeid,Oidtargettypeid,
50+
Oidfuncid,Oidincastid,Oidoutcastid,
51+
charcastcontext,charcastmethod,DependencyTypebehavior)
4552
{
4653
Relationrelation;
4754
HeapTupletuple;
@@ -102,6 +109,18 @@ CastCreate(Oid sourcetypeid, Oid targettypeid, Oid funcid, char castcontext,
102109
add_exact_object_address(&referenced,addrs);
103110
}
104111

112+
/* dependencies on casts required for function */
113+
if (OidIsValid(incastid))
114+
{
115+
ObjectAddressSet(referenced,CastRelationId,incastid);
116+
add_exact_object_address(&referenced,addrs);
117+
}
118+
if (OidIsValid(outcastid))
119+
{
120+
ObjectAddressSet(referenced,CastRelationId,outcastid);
121+
add_exact_object_address(&referenced,addrs);
122+
}
123+
105124
record_object_address_dependencies(&myself,addrs,behavior);
106125
free_object_addresses(addrs);
107126

‎src/backend/commands/functioncmds.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,8 @@ CreateCast(CreateCastStmt *stmt)
15261526
charsourcetyptype;
15271527
chartargettyptype;
15281528
Oidfuncid;
1529+
Oidincastid=InvalidOid;
1530+
Oidoutcastid=InvalidOid;
15291531
intnargs;
15301532
charcastcontext;
15311533
charcastmethod;
@@ -1603,7 +1605,9 @@ CreateCast(CreateCastStmt *stmt)
16031605
ereport(ERROR,
16041606
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16051607
errmsg("cast function must take one to three arguments")));
1606-
if (!IsBinaryCoercible(sourcetypeid,procstruct->proargtypes.values[0]))
1608+
if (!IsBinaryCoercibleWithCast(sourcetypeid,
1609+
procstruct->proargtypes.values[0],
1610+
&incastid))
16071611
ereport(ERROR,
16081612
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16091613
errmsg("argument of cast function must match or be binary-coercible from source data type")));
@@ -1617,7 +1621,9 @@ CreateCast(CreateCastStmt *stmt)
16171621
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16181622
errmsg("third argument of cast function must be type %s",
16191623
"boolean")));
1620-
if (!IsBinaryCoercible(procstruct->prorettype,targettypeid))
1624+
if (!IsBinaryCoercibleWithCast(procstruct->prorettype,
1625+
targettypeid,
1626+
&outcastid))
16211627
ereport(ERROR,
16221628
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16231629
errmsg("return data type of cast function must match or be binary-coercible to target data type")));
@@ -1756,8 +1762,8 @@ CreateCast(CreateCastStmt *stmt)
17561762
break;
17571763
}
17581764

1759-
myself=CastCreate(sourcetypeid,targettypeid,funcid,castcontext,
1760-
castmethod,DEPENDENCY_NORMAL);
1765+
myself=CastCreate(sourcetypeid,targettypeid,funcid,incastid,outcastid,
1766+
castcontext,castmethod,DEPENDENCY_NORMAL);
17611767
returnmyself;
17621768
}
17631769

‎src/backend/commands/typecmds.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1705,7 +1705,9 @@ DefineRange(ParseState *pstate, CreateRangeStmt *stmt)
17051705
&castFuncOid);
17061706

17071707
/* Create cast from the range type to its multirange type */
1708-
CastCreate(typoid,multirangeOid,castFuncOid,'e','f',DEPENDENCY_INTERNAL);
1708+
CastCreate(typoid,multirangeOid,castFuncOid,InvalidOid,InvalidOid,
1709+
COERCION_CODE_EXPLICIT,COERCION_METHOD_FUNCTION,
1710+
DEPENDENCY_INTERNAL);
17091711

17101712
pfree(multirangeArrayName);
17111713

‎src/backend/parser/parse_coerce.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2993,11 +2993,29 @@ IsPreferredType(TYPCATEGORY category, Oid type)
29932993
*/
29942994
bool
29952995
IsBinaryCoercible(Oidsrctype,Oidtargettype)
2996+
{
2997+
Oidcastoid;
2998+
2999+
returnIsBinaryCoercibleWithCast(srctype,targettype,&castoid);
3000+
}
3001+
3002+
/* IsBinaryCoercibleWithCast()
3003+
*Check if srctype is binary-coercible to targettype.
3004+
*
3005+
* This variant also returns the OID of the pg_cast entry if one is involved.
3006+
* *castoid is set to InvalidOid if no binary-coercible cast exists, or if
3007+
* there is a hard-wired rule for it rather than a pg_cast entry.
3008+
*/
3009+
bool
3010+
IsBinaryCoercibleWithCast(Oidsrctype,Oidtargettype,
3011+
Oid*castoid)
29963012
{
29973013
HeapTupletuple;
29983014
Form_pg_castcastForm;
29993015
boolresult;
30003016

3017+
*castoid=InvalidOid;
3018+
30013019
/* Fast path if same type */
30023020
if (srctype==targettype)
30033021
return true;
@@ -3061,6 +3079,9 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
30613079
result= (castForm->castmethod==COERCION_METHOD_BINARY&&
30623080
castForm->castcontext==COERCION_CODE_IMPLICIT);
30633081

3082+
if (result)
3083+
*castoid=castForm->oid;
3084+
30643085
ReleaseSysCache(tuple);
30653086

30663087
returnresult;

‎src/include/catalog/pg_cast.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ typedef enum CoercionMethod
9595
externObjectAddressCastCreate(Oidsourcetypeid,
9696
Oidtargettypeid,
9797
Oidfuncid,
98+
Oidincastid,
99+
Oidoutcastid,
98100
charcastcontext,
99101
charcastmethod,
100102
DependencyTypebehavior);

‎src/include/parser/parse_coerce.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ typedef enum CoercionPathType
3232

3333

3434
externboolIsBinaryCoercible(Oidsrctype,Oidtargettype);
35+
externboolIsBinaryCoercibleWithCast(Oidsrctype,Oidtargettype,
36+
Oid*castoid);
3537
externboolIsPreferredType(TYPCATEGORYcategory,Oidtype);
3638
externTYPCATEGORYTypeCategory(Oidtype);
3739

‎src/test/regress/expected/create_cast.out

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,32 @@ SELECT 1234::int4::casttesttype; -- Should work now
7272
foo1234
7373
(1 row)
7474

75+
DROP FUNCTION int4_casttesttype(int4) CASCADE;
76+
NOTICE: drop cascades to cast from integer to casttesttype
77+
-- Try it with a function that requires an implicit cast
78+
CREATE FUNCTION bar_int4_text(int4) RETURNS text LANGUAGE SQL AS
79+
$$ SELECT ('bar'::text || $1::text); $$;
80+
CREATE CAST (int4 AS casttesttype) WITH FUNCTION bar_int4_text(int4) AS IMPLICIT;
81+
SELECT 1234::int4::casttesttype; -- Should work now
82+
casttesttype
83+
--------------
84+
bar1234
85+
(1 row)
86+
87+
-- check dependencies generated for that
88+
SELECT pg_describe_object(classid, objid, objsubid) as obj,
89+
pg_describe_object(refclassid, refobjid, refobjsubid) as objref,
90+
deptype
91+
FROM pg_depend
92+
WHERE classid = 'pg_cast'::regclass AND
93+
objid = (SELECT oid FROM pg_cast
94+
WHERE castsource = 'int4'::regtype
95+
AND casttarget = 'casttesttype'::regtype)
96+
ORDER BY refclassid;
97+
obj | objref | deptype
98+
-----------------------------------+---------------------------------+---------
99+
cast from integer to casttesttype | type casttesttype | n
100+
cast from integer to casttesttype | function bar_int4_text(integer) | n
101+
cast from integer to casttesttype | cast from text to casttesttype | n
102+
(3 rows)
103+

‎src/test/regress/sql/create_cast.sql

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,24 @@ $$ SELECT ('foo'::text || $1::text)::casttesttype; $$;
5252

5353
CREATE CAST (int4AS casttesttype) WITH FUNCTION int4_casttesttype(int4)AS IMPLICIT;
5454
SELECT1234::int4::casttesttype;-- Should work now
55+
56+
DROPFUNCTION int4_casttesttype(int4) CASCADE;
57+
58+
-- Try it with a function that requires an implicit cast
59+
60+
CREATEFUNCTIONbar_int4_text(int4) RETURNStext LANGUAGE SQLAS
61+
$$SELECT ('bar'::text|| $1::text); $$;
62+
63+
CREATE CAST (int4AS casttesttype) WITH FUNCTION bar_int4_text(int4)AS IMPLICIT;
64+
SELECT1234::int4::casttesttype;-- Should work now
65+
66+
-- check dependencies generated for that
67+
SELECT pg_describe_object(classid, objid, objsubid)as obj,
68+
pg_describe_object(refclassid, refobjid, refobjsubid)as objref,
69+
deptype
70+
FROM pg_depend
71+
WHERE classid='pg_cast'::regclassAND
72+
objid= (SELECToidFROM pg_cast
73+
WHERE castsource='int4'::regtype
74+
AND casttarget='casttesttype'::regtype)
75+
ORDER BY refclassid;

‎src/tools/valgrind.supp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@
113113
overread_tuplestruct_pg_cast
114114
Memcheck:Addr4
115115

116-
fun:IsBinaryCoercible
116+
fun:IsBinaryCoercibleWithCast
117117
}
118118

119119
# Python's allocator does some low-level tricks for efficiency. Those

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp