diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/parser/parse_func.c | 28 | ||||
-rw-r--r-- | src/test/regress/expected/rowtypes.out | 46 | ||||
-rw-r--r-- | src/test/regress/sql/rowtypes.sql | 15 |
3 files changed, 85 insertions, 4 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index b50bce44872..9bb100e0c1e 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -985,8 +985,13 @@ func_get_detail(List *funcname, * can't write "foo[] (something)" as a function call. In theory * someone might want to invoke it as "_foo (something)" but we have * never supported that historically, so we can insist that people - * write it as a normal cast instead. Lack of historical support is - * also the reason for not considering composite-type casts here. + * write it as a normal cast instead. + * + * We also reject the specific case of COERCEVIAIO for a composite + * source type and a string-category target type. This is a case that + * find_coercion_pathway() allows by default, but experience has shown + * that it's too commonly invoked by mistake. So, again, insist that + * people use cast syntax if they want to do that. * * NB: it's important that this code does not exceed what coerce_type * can do, because the caller will try to apply coerce_type if we @@ -1017,8 +1022,23 @@ func_get_detail(List *funcname, cpathtype = find_coercion_pathway(targetType, sourceType, COERCION_EXPLICIT, &cfuncid); - iscoercion = (cpathtype == COERCION_PATH_RELABELTYPE || - cpathtype == COERCION_PATH_COERCEVIAIO); + switch (cpathtype) + { + case COERCION_PATH_RELABELTYPE: + iscoercion = true; + break; + case COERCION_PATH_COERCEVIAIO: + if ((sourceType == RECORDOID || + ISCOMPLEX(sourceType)) && + TypeCategory(targetType) == TYPCATEGORY_STRING) + iscoercion = false; + else + iscoercion = true; + break; + default: + iscoercion = false; + break; + } } if (iscoercion) diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out index a21f7b8c06b..e5cd71421c6 100644 --- a/src/test/regress/expected/rowtypes.out +++ b/src/test/regress/expected/rowtypes.out @@ -324,3 +324,49 @@ select * from price; (3 rows) rollback; +-- +-- We allow I/O conversion casts from composite types to strings to be +-- invoked via cast syntax, but not functional syntax. This is because +-- the latter is too prone to be invoked unintentionally. +-- +select cast (fullname as text) from fullname; + fullname +---------- +(0 rows) + +select fullname::text from fullname; + fullname +---------- +(0 rows) + +select text(fullname) from fullname; -- error +ERROR: function text(fullname) does not exist +LINE 1: select text(fullname) from fullname; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +select fullname.text from fullname; -- error +ERROR: column fullname.text does not exist +LINE 1: select fullname.text from fullname; + ^ +-- same, but RECORD instead of named composite type: +select cast (row('Jim', 'Beam') as text); + row +------------ + (Jim,Beam) +(1 row) + +select (row('Jim', 'Beam'))::text; + row +------------ + (Jim,Beam) +(1 row) + +select text(row('Jim', 'Beam')); -- error +ERROR: function text(record) does not exist +LINE 1: select text(row('Jim', 'Beam')); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +select (row('Jim', 'Beam')).text; -- error +ERROR: could not identify column "text" in record data type +LINE 1: select (row('Jim', 'Beam')).text; + ^ diff --git a/src/test/regress/sql/rowtypes.sql b/src/test/regress/sql/rowtypes.sql index e5a77f79f65..9041df147fe 100644 --- a/src/test/regress/sql/rowtypes.sql +++ b/src/test/regress/sql/rowtypes.sql @@ -157,3 +157,18 @@ UPDATE price select * from price; rollback; + +-- +-- We allow I/O conversion casts from composite types to strings to be +-- invoked via cast syntax, but not functional syntax. This is because +-- the latter is too prone to be invoked unintentionally. +-- +select cast (fullname as text) from fullname; +select fullname::text from fullname; +select text(fullname) from fullname; -- error +select fullname.text from fullname; -- error +-- same, but RECORD instead of named composite type: +select cast (row('Jim', 'Beam') as text); +select (row('Jim', 'Beam'))::text; +select text(row('Jim', 'Beam')); -- error +select (row('Jim', 'Beam')).text; -- error |