The information you were given on StackOverflow is somewhat misleading, since it is referring to the behaviour of PDO::quote(), not anything to do with binding parameters. The referenced bug report is indeed not a bug.
Still, I don't really use Postgres but a quick smoke test indicates you're not wrong about the behaviour of bindValue/bindParam on the PG driver when emulation mode is switched off. $pdb->exec('CREATE OR REPLACE FUNCTION baz(in int, out f1 text) AS $$ SELECT CAST($1 AS text) || \' as int\' $$ LANGUAGE SQL;'); $pdb->exec('CREATE OR REPLACE FUNCTION baz(in text, out f1 text) AS $$ SELECT $1 || \' as string\' $$ LANGUAGE SQL;'); var_dump( $pdb->query('SELECT baz(23);')->fetchAll() ); ["baz"]=> string(9) "23 as int" var_dump( $pdb->query('SELECT baz(\'23\');')->fetchAll() ); ["baz"]=>string(12) "23 as string" $st=$pdb->prepare('SELECT baz(?)'); $st->bindValue(1,3,PDO::PARAM_INT); $st->execute(); var_dump($st->fetchAll()); ["baz"]=>string(11) "3 as string" Looks like your only option is: $st=$pdb->prepare('SELECT baz(CAST(? AS int))'); $st->bindValue(1,3,PDO::PARAM_INT); $st->execute(); var_dump($st->fetchAll()); which gives the expected ["baz"]=>string(8) "3 as int" Whether this is a *bug* I can't really say, there might be a reason Postgres is implemented this way on PDO, I don't know, I'm not a Postgres guy. But the funny thing is it works exactly as expected when emulation is switched ON: $pdb->setAttribute(PDO::ATTR_EMULATE_PREPARES,true); $st = $pdb->prepare('SELECT baz(?)'); $st->bindValue(1,3,PDO::PARAM_INT); $st->execute(); var_dump($st->fetchAll()); ["baz"]=>string(8) "3 as int" Regards, David On Sun, Mar 14, 2021 at 8:19 PM Benjamin Morel <benjamin.mo...@gmail.com> wrote: > Hi internals, > > I just stumbled upon what I consider to be a bug with the PDO pgsql driver. > *TL;DR: the driver treats parameters bound with PARAM_INT the same as > PARAM_STR.* > > Take the following example: > > ``` > $pdo = new PDO('pgsql:host=localhost;port=5432', 'postgres', 'postgres'); > > $statement = $pdo->prepare(" > SELECT ST_AsText( > ST_Transform( > ST_GeomFromText('POINT(0 0)', 2154), > ? > ) > ) > "); > > $statement->bindValue(1, 4326, PDO::PARAM_INT); > $statement->execute(); > ``` > > This fails with the following message: > > PDOException: SQLSTATE[XX000]: Internal error: 7 ERROR: could not parse > > proj string '4326' > > > This is because the pgsql driver seems to treat everything as PARAM_STR, > despite being explicitly requested to bind the value as PARAM_INT; the > placeholder is therefore replaced with the string '4326' instead of the > integer 4326. > > The problem is, in PostGIS, the ST_Transform() > <https://postgis.net/docs/ST_Transform.html> function has different > signatures with different behaviours depending on whether the second > parameter is an integer or a string. > > As far as I can see, because of this issue, *there is no way to pass an > actual integer to ST_Transform()*, which forces me to use > PostgreSQL-specific cast syntax to get the behaviour I need, in a library > <https://github.com/brick/geo> I maintain that's supposed to work with any > GIS-enabled database. > > Is there any reason why the pgsql driver doesn't respect PDO::PARAM_STR? > > I asked this question on StackOverflow > <https://stackoverflow.com/q/66625661/759866>, and was pointed to the > following bug, which I'm not sure is directly related, but was closed as > "not a bug": > > https://bugs.php.net/bug.php?id=50206 > > *Should this be requalified as a bug and be fixed?* > > Thanks in advance for your consideration, > > — Benjamin >