aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/parser/parse_func.c28
-rw-r--r--src/test/regress/expected/rowtypes.out46
-rw-r--r--src/test/regress/sql/rowtypes.sql15
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