Open smilingthax opened 3 months ago
Hi @smilingthax,
If I understand your issue correctly, you are trying to say that cast operations should push down to the remote server to get the correct result.
So, considering this PG query -
SELECT val::int4::float FROM ext_table GROUP BY 1;
should be deparsed as
SELECT CAST(CAST(val AS int4) AS float) FROM t GROUP BY 1;
to get the correct result?
I executed the above query on MySQL and got syntax error:
mysql> SELECT CAST(CAST(val AS int4) AS float) FROM real_test GROUP BY 1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'int4) AS float) FROM real_test GROUP BY 1' at line 1
If I understand your issue correctly, you are trying to say that cast operations should push down to the remote server to get the correct result.
AFAIUI, mysql_fdw decides whether it can "handle" a certain operation, otherwise postgres will execute it locally.
In the current implementation, mysql_fdw says: "yes, I can handle casts", but does this not by pushing them down, but by somehow 'executing' them "after reading the result from mysql, but before postgres uses the data".
This is problematic, because (e.g.) truncating cast + group by cannot always "simply be done" after reading a result from mysql. Also, currently the expected (integer) vs. obtained values (potentially "0.1") disagree, which leads to the invalid input syntax for type integer: "0.1"
.
Either mysql_fdw MUST NOT claim to be able to handle them in non-trivial cases (and let postgres do the correct thing instead),
or it has to implement it by actually pushing the casts to the mysql server.
So, considering this PG query -
SELECT val::int4::float FROM ext_table GROUP BY 1;
should be deparsed as
SELECT CAST(CAST(val AS int4) AS float) FROM t GROUP BY 1;
to get the correct result?
This would do the correct thing here, yes.
I executed the above query on MySQL and got syntax error:
mysql> SELECT CAST(CAST(val AS int4) AS float) FROM real_test GROUP BY 1; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'int4) AS float) FROM real_test GROUP BY 1' at line 1
The statement does not error on MariaDB 10.11.2;
I can confirm, though, that at least MariaDB 10.3.12 has problems with using float
in the cast (and also certain other "type names", AFAICT... real
, anyone?).
Replacing float
with double
does the trick there: (note that double
is not a valid type in postgres, it would be float8
)
MariaDB> SELECT CAST(CAST(val AS int4) AS double) FROM real_test GROUP BY 1;
I'm not sure, if that's enough to formulate a fixed postgres->mysql type mapping which works for as many mysql/mariadb versions as possible...?
int4 only exists as cast, not as function in mysql
That's a separate issue: Currently, casts and function calls are treated as "the same" thing (ROUTINE
) wrt. to push-down.
But in reality:
int4(val)
), AND as cast (val::int4
resp. CAST(val AS int4)
) on the postgres side, but ONLY as cast (NOT as function call) in the mysql side.float
works as cast, not as function [float4 works as both, though]) and the mysql side (float
works in some versions, more portable would be double
?)date
.Therefore mysql_fdw_pushdown.config
should most certainly distinguish these cases, e.g. by introducing a new keyword CAST
(which types as cast target can be pushed down) or/and maybe TYPE
(which postgres type name can/may be mapped to which mysql type name?).
val float
column, two rows with values0
and0.1
.val
becomesreal
mysql_fdw_pushdown.config
allowsROUTINE pg_catalog.int4(real)
to be pushed down(My original encounter with this issue was with
::date
, resp.CAST(... AS date)
, when I tried to addto
mysql_fdw_pushdown.config
to allow it to be pushed down – w/o this entry, the grouping was (correctly) not pushed down, but performed by postgres. With the entry, the cast would be (wrongly) pushed down only partially, as described above. Usingdate(...)
instead pushes both that and the GROUP BY down correctly then (date
also exists as mysql function, whereint4
doesn't) ...)