Skip to content

Navigation Menu

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

Appearance settings

Commit 8272749

Browse filesBrowse files
committed
Record dependencies of a cast on other casts that it requires.
When creating a cast that uses a conversion function, we've historically allowed the input and result types to be binary-compatible with the function's input and result types, rather than necessarily being identical. This means that the new cast is logically dependent on the binary-compatible cast or casts that it references: if those are defined by pg_cast entries, and you try to restore the new cast without having defined them, it'll fail. Hence, we should make pg_depend entries to record these dependencies so that pg_dump knows that there is an ordering requirement. This is not the only place where we allow such shortcuts; aggregate functions for example are similarly lax, and in principle should gain similar dependencies. However, for now it seems sufficient to fix the cast-versus-cast case, as pg_dump's other ordering heuristics should keep it out of trouble for other object types. Per report from David Turoň; thanks also to Robert Haas for preliminary investigation. I considered back-patching, but seeing that this issue has existed for many years without previous reports, it's not clear it's worth the trouble. Moreover, back-patching wouldn't be enough to ensure that the new pg_depend entries exist in existing databases anyway. Discussion: https://postgr.es/m/OF0A160F3E.578B15D1-ONC12588DA.003E4857-C12588DA.0045A428@notes.linuxbox.cz
1 parent 797e313 commit 8272749
Copy full SHA for 8272749

File tree

9 files changed

+111
-9
lines changed
Filter options

9 files changed

+111
-9
lines changed

‎src/backend/catalog/pg_cast.c

Copy file name to clipboardExpand all lines: src/backend/catalog/pg_cast.c
+22-3Lines 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(Oid sourcetypeid, Oid targettypeid, Oid funcid, char castcontext,
44-
char castmethod, DependencyType behavior)
49+
CastCreate(Oid sourcetypeid, Oid targettypeid,
50+
Oid funcid, Oid incastid, Oid outcastid,
51+
char castcontext, char castmethod, DependencyType behavior)
4552
{
4653
Relation relation;
4754
HeapTuple tuple;
@@ -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

Copy file name to clipboardExpand all lines: src/backend/commands/functioncmds.c
+10-4Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,8 @@ CreateCast(CreateCastStmt *stmt)
15261526
char sourcetyptype;
15271527
char targettyptype;
15281528
Oid funcid;
1529+
Oid incastid = InvalidOid;
1530+
Oid outcastid = InvalidOid;
15291531
int nargs;
15301532
char castcontext;
15311533
char castmethod;
@@ -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
return myself;
17621768
}
17631769

‎src/backend/commands/typecmds.c

Copy file name to clipboardExpand all lines: src/backend/commands/typecmds.c
+3-1Lines 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

Copy file name to clipboardExpand all lines: src/backend/parser/parse_coerce.c
+21Lines 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(Oid srctype, Oid targettype)
2996+
{
2997+
Oid castoid;
2998+
2999+
return IsBinaryCoercibleWithCast(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(Oid srctype, Oid targettype,
3011+
Oid *castoid)
29963012
{
29973013
HeapTuple tuple;
29983014
Form_pg_cast castForm;
29993015
bool result;
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
return result;

‎src/include/catalog/pg_cast.h

Copy file name to clipboardExpand all lines: src/include/catalog/pg_cast.h
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ typedef enum CoercionMethod
9595
extern ObjectAddress CastCreate(Oid sourcetypeid,
9696
Oid targettypeid,
9797
Oid funcid,
98+
Oid incastid,
99+
Oid outcastid,
98100
char castcontext,
99101
char castmethod,
100102
DependencyType behavior);

‎src/include/parser/parse_coerce.h

Copy file name to clipboardExpand all lines: src/include/parser/parse_coerce.h
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ typedef enum CoercionPathType
3232

3333

3434
extern bool IsBinaryCoercible(Oid srctype, Oid targettype);
35+
extern bool IsBinaryCoercibleWithCast(Oid srctype, Oid targettype,
36+
Oid *castoid);
3537
extern bool IsPreferredType(TYPCATEGORY category, Oid type);
3638
extern TYPCATEGORY TypeCategory(Oid type);
3739

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

Copy file name to clipboardExpand all lines: src/test/regress/expected/create_cast.out
+29Lines 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

Copy file name to clipboardExpand all lines: src/test/regress/sql/create_cast.sql
+21Lines 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 (int4 AS casttesttype) WITH FUNCTION int4_casttesttype(int4) AS IMPLICIT;
5454
SELECT 1234::int4::casttesttype; -- Should work now
55+
56+
DROP FUNCTION int4_casttesttype(int4) CASCADE;
57+
58+
-- Try it with a function that requires an implicit cast
59+
60+
CREATE FUNCTION bar_int4_text(int4) RETURNS text LANGUAGE SQL AS
61+
$$ SELECT ('bar'::text || $1::text); $$;
62+
63+
CREATE CAST (int4 AS casttesttype) WITH FUNCTION bar_int4_text(int4) AS IMPLICIT;
64+
SELECT 1234::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'::regclass AND
72+
objid = (SELECT oid FROM pg_cast
73+
WHERE castsource = 'int4'::regtype
74+
AND casttarget = 'casttesttype'::regtype)
75+
ORDER BY refclassid;

‎src/tools/valgrind.supp

Copy file name to clipboardExpand all lines: src/tools/valgrind.supp
+1-1Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.