Skip to content

Bug #46408: Fix double formatting for PostgreSQL bound parameters #186

Closed
wants to merge 1 commit into from

5 participants

@asmecher
asmecher commented Sep 6, 2012

See https://bugs.php.net/bug.php?id=46408 for extensive discussion of this.

@reeze reeze and 1 other commented on an outdated diff Sep 9, 2012
ext/pgsql/pgsql.c
@@ -1736,7 +1737,15 @@ static void _php_pgsql_free_params(char **params, int num_params)
} else {
zval tmp_val = **tmp;
zval_copy_ctor(&tmp_val);
+
+ // PSQL requires . for radix; convert to string,
@reeze
reeze added a note Sep 9, 2012

please use '/* */' instead of '//'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lstrojny

While this fix sure does what it needs to do to address this problem, I’m not sure we should work around this design flaw on every single occasion. Additionally the bugfix misses a test to make sure we don’t get a regression at some point.

@lstrojny lstrojny commented on an outdated diff Sep 13, 2012
ext/pgsql/pgsql.c
@@ -1736,7 +1737,13 @@ static void _php_pgsql_free_params(char **params, int num_params)
} 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 bug #46408) */
+ char *current_locale = setlocale(LC_NUMERIC, "C");
@lstrojny
lstrojny added a note Sep 13, 2012

As we use C89/C90, declarations may not be mixed with code. Please move the declaration to the beginning of the block.

@lstrojny
lstrojny added a note Sep 13, 2012

Additionally: are you certain this works on any platform we support?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@asmecher

Thanks for the hints, Lars -- I've moved the var declaration to the head of the block, added #ifdef checks to make sure HAVE_SETLOCALE is respected, and added a regression test (ext/pgsql/tests/bug46408.phpt). I haven't contributed code to PHP before so your scrutiny is appreciated.

@asmecher

As for whether or not this problem should be worked around in PHP, it's necessary either to do it there or to do it in my own PHP scripts (and for everyone else who needs both setlocale and pg_query_params). I agree that it's not ideal but it does rehabilitate that function; I wouldn't know what to suggest as a broader strategy.

Note that the test will require the hr_HR locale to be generated on the test system (see /etc/locale.gen).

@lstrojny

Alright, digged a little deeper into this issue and here is my first analysis. The code flow basically goes like this

#define convert_to_string(zval *op) (defined in Zend/zend_operators.h)
    void _convert_to_string(zval *op ZEND_FILE_LINE_DC)  (defined in Zend/zend_operators.c)
        zend_spprintf(&Z_STRVAL_P(op), 0, "%.*G", (int) EG(precision), dval) (which is assigned in Zend/zend.c)
            zend_vspprintf = utility_functions->vspprintf_function (which is actually assigned in main/main.c)
                zuf.vspprintf_function = vspprintf (which is defined in main/spprintf.c)
                    PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) (defined in main/spprintf.c)
                        static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap) (defined in main/spprintf.c)

case 'G' defines the behavior for %.*G. If I read the code correctly, '%.*H' wouldn’t be locale sensitive.

This means: we need something like _convert_to_string_but_ignore_locale_settings() (no, this is not a serious function name proposal) which does the same as _convert_to_string() but uses '%.*H' for floats.

@asmecher

Thanks for the feedback, Lars -- I've introduced convert_to_string_unlocalized and used it instead. I've attempted to keep code duplication to a minimum -- personally, I would have preferred to introduce an optional parameter to the existing _convert_to_string but I suspect that would not follow PHP coding conventions.

@lstrojny

What about convert_to_cstring (like in c locale?)

Btw: regarding locale, you could also try to iterate over a few variants (de_DE e.g. also uses "," as a decimal separator).

@asmecher

Agreed; changed.

@lstrojny

Just so that you know, I've written a mail to internals@php.net to get more people into this discussion: http://marc.info/?l=php-internals&m=134807980716416&w=2

@asmecher

Thanks, Lars. This has been helpful and informative for me and I hope it results in an accepted fix.

@asmecher
asmecher commented Oct 3, 2012

Unfortunately that round on the php-internals list wasn't too encouraging. What would you suggest for next steps? I'd like to see a general fix applied, but the idea didn't seem popular. Alternately, I could alter this to just affect pg_query_params, but that won't help maintainability going forward.

@smalyshev smalyshev and 1 other commented on an outdated diff Oct 27, 2012
ext/pgsql/pgsql.c
@@ -23,6 +23,7 @@
/* $Id$ */
#include <stdlib.h>
+#include <locale.h>
@smalyshev
smalyshev added a note Oct 27, 2012

why you need locale.h?

@lstrojny
lstrojny added a note Oct 27, 2012

Yep, that's no longer needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lstrojny

Could you squash the commits. I will apply your fix for the PHP 5.5 branch.

@asmecher

Done. Thanks for all your help, Lars.

@php-pulls

Comment on behalf of lstrojny at php.net:

Merged into 5.5 and master. Thanks for your contribution and your patience!

@php-pulls php-pulls closed this Jan 14, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.