|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2008-10-28 19:40 UTC] alec at smecher dot bc dot ca
Description:
------------
Using PHP's setlocale function can cause number formats to change (e.g. formatting floats using a comma instead of a decimal, such as 3,5 instead of 3.5). This causes pg_query_params to break when binding floats into the parameter array, as psql doesn't understand comma-formatted numbers.
You may need to generate the hr_HR locale on your system in order for number formatting to work as described above once setlocale has been called (see the debug "echo" in the reproduce code).
I reproduced the problem with 5.2.6 and 5.2.7RC2.
Reproduce code:
---------------
<?php
ini_set('display_errors', E_ALL);
setlocale(LC_ALL, 'hr_HR.utf-8', 'hr_HR');
$number = 3.5;
$dbuser = 'putdbusernamehere';
$dbpass = 'putdbpasswordhere';
echo "Three and a half is: " . $number . " (should come out as 3,5)\n";
$conn = pg_connect("host=localhost user=$dbuser password=$dbpass");
$result = pg_query_params($conn, 'SELECT $1::numeric', array($number));
pg_close($conn);
?>
Expected result:
----------------
Three and a half is: 3,5 (should come out as 3,5)
Actual result:
--------------
Three and a half is: 3,5 (should come out as 3,5)
Warning: pg_query_params(): Query failed: ERROR: invalid input syntax for type numeric: "3,5" in /home/asmecher/cvs/ojs2-stable/test.php on line 13
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Mon Oct 27 21:00:02 2025 UTC |
PostgreSQL users are supposed to pass/recieve data via strings *always* with C/C++ API. Programmers are responsible how it's passed. As as mentioned already, system will not know how numbers should be formatted for certain column. The code even don't care the column types of tables. Think, create table test (a text); and insert into test (a) values ("number"); The number format is decided by PHP programmer, not pgsql module.@yohgaki (and others) I think that, the root of the problem is the way PHP uses the locale information, which I consider deeply broken. Here are the details: In my understanding, the locale information is useful only for *output*, i.e. for messages destined to the user. They should not be used for any internal conversion from one type to the other, unless the result is destined to output. The problem is, that PHP uses the locale for any automatic conversion from number to string. This behaviour is ok in the following case: echo "Three and a half is: " . $number; However, in the following cases, this is NOT correct, because the resulting string must not be localised: * constructing a JSON object (I hope that json_encode() does NOT use internal number-to-string conversion); * using bcmath package (I have personnaly be bitten by this misfeature); * construct a SQL request (the present case); * etc. In all these cases, you have to do one of the following options: (1) never use any locale other than en_US (and re-implement manually the locale feature); (2) carefully check the type of each and every parameter and explicitely perform a correct conversion when needed, e.g. using number_format(..., '.', ''); (3) fix PHP to NOT use locale for number-to-string conversion unless it is explicitely asked for (side note: historically, there has been a similar problem with the "magic quote" misfeature); (4) modify the modules bcmath, postgresql, etc, so that they circumvent the mentionned PHP misfeature, i.e., they do the option (2) above at your place. In my dreams, the option (3) would be implemented, but pragmatically, I think that option (4) has more chance to be implemented rapidly, if ever. I think that alec asked precisely the option (4) to be implemented. (Personnally, I have opted for option (1).) Claude P.S. The option (4) might seem a non-optimal hack. However, do not forget that programming languages and API should be adapted to the needs of the programmers, and not the other way round.I suggest this patch. diff -u -r php-5.4.6/ext/pgsql/pgsql.c php-5.4.6-mod/ext/pgsql/pgsql.c --- php-5.4.6/ext/pgsql/pgsql.c 2012-08-14 21:26:05.000000000 -0700 +++ php-5.4.6-mod/ext/pgsql/pgsql.c 2012-09-06 10:59:45.000000000 -0700 @@ -23,6 +23,7 @@ /* $Id$ */ #include <stdlib.h> +#include <locale.h> #define PHP_PGSQL_PRIVATE 1 @@ -1736,7 +1737,15 @@ } else { zval tmp_val = **tmp; zval_copy_ctor(&tmp_val); + + // PSQL requires . for radix; convert to string, + // avoiding problems with doubles and locales + // using , as a radix character instead + // (see https://bugs.php.net/bug.php?id=46408) + char *current_locale = setlocale(LC_NUMERIC, "C"); convert_to_string(&tmp_val); + setlocale(LC_NUMERIC, current_locale); + if (Z_TYPE(tmp_val) != IS_STRING) { php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter"); zval_dtor(&tmp_val);