Eugen Nedelcu wrote:
> Regarding locale aproach, it is trivial to replace langinfo with
> localeconv:
> 
> struct lconv *l = localeconv();
> char *dec_point = l->decimal_point;
> 
> instead of:
> 
> #include langinfo.h
> char *dec_point = nl_langinfo(__DECIMAL_POINT);
> 
> I used langinfo because in linux libc it is considered
> "The Elegant and Fast Way" of using locale and conforms with
> X/Open portability guide that every modern Unix follows
> (Solaris, Linux, latest FreeBSD).
> 
> Regarding locale vs. \pset numericsep, for me it doesn't matter
> which one is used. I consider the patch very usefull, and I think 
> that other guys that use psql daily for working with financial data
> will appreciate it too.
> 
> With a quick setting like \pset numericsep ',' all my numeric fields
> will appear in easy readable form. I must underline that to_char is
> a backend function and we talk here about a little psql feature which
> makes life a little easier (for me at least).

OK, I have applied the following patch to make numerisep a boolean, made
it locale-aware, set defaults if the locale doesn't return meaningful
values, added code to handle locale-reported groupings, and updated the
documentation.  

The only question I have is whether those locale values are single-byte
strings in all locals, or could they be multi-byte or multi-character,
in which case I have to treat them as strings.  For now, I added a code
comment that we treat them as single-byte strings.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: doc/src/sgml/ref/psql-ref.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v
retrieving revision 1.146
retrieving revision 1.147
diff -c -r1.146 -r1.147
*** doc/src/sgml/ref/psql-ref.sgml      10 Jul 2005 03:46:12 -0000      1.146
--- doc/src/sgml/ref/psql-ref.sgml      14 Jul 2005 08:42:36 -0000      1.147
***************
*** 1,5 ****
  <!--
! $PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.146 2005/07/10 03:46:12 
momjian Exp $
  PostgreSQL documentation
  -->
  
--- 1,5 ----
  <!--
! $PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.147 2005/07/14 08:42:36 
momjian Exp $
  PostgreSQL documentation
  -->
  
***************
*** 1496,1505 ****
            <term><literal>numericsep</literal></term>
            <listitem>
            <para>
!           Specifies the character separator between groups of three digits
!           to the left of the decimal marker.  The default is <literal>''</>
!           (none).  Setting this to a period also changes the decimal marker 
!           to a comma.
            </para>
            </listitem>
            </varlistentry>
--- 1496,1504 ----
            <term><literal>numericsep</literal></term>
            <listitem>
            <para>
!           Toggles the display of a locale-aware character to separate groups
!           of digits to the left of the decimal marker.  It also enables
!           a locale-aware decimal marker.
            </para>
            </listitem>
            </varlistentry>
Index: src/bin/psql/command.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/command.c,v
retrieving revision 1.148
retrieving revision 1.149
diff -c -r1.148 -r1.149
*** src/bin/psql/command.c      14 Jul 2005 06:49:58 -0000      1.148
--- src/bin/psql/command.c      14 Jul 2005 08:42:37 -0000      1.149
***************
*** 3,9 ****
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.148 2005/07/14 06:49:58 
momjian Exp $
   */
  #include "postgres_fe.h"
  #include "command.h"
--- 3,9 ----
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.149 2005/07/14 08:42:37 
momjian Exp $
   */
  #include "postgres_fe.h"
  #include "command.h"
***************
*** 1420,1434 ****
                                   : _("Expanded display is off.\n"));
        }
  
        else if (strcmp(param, "numericsep") == 0)
        {
!               if (value)
                {
!                       free(popt->topt.numericSep);
!                       popt->topt.numericSep = pg_strdup(value);
                }
-               if (!quiet)
-                       printf(_("Numeric separator is \"%s\".\n"), 
popt->topt.numericSep);
        }
  
        /* null display */
--- 1420,1436 ----
                                   : _("Expanded display is off.\n"));
        }
  
+       /* numeric separators */
        else if (strcmp(param, "numericsep") == 0)
        {
!               popt->topt.numericSep = !popt->topt.numericSep;
!               if (!quiet)
                {
!                       if (popt->topt.numericSep)
!                               puts(_("Showing numeric separators."));
!                       else
!                               puts(_("Numeric separators are off."));
                }
        }
  
        /* null display */
Index: src/bin/psql/print.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/print.c,v
retrieving revision 1.66
retrieving revision 1.67
diff -c -r1.66 -r1.67
*** src/bin/psql/print.c        14 Jul 2005 07:32:01 -0000      1.66
--- src/bin/psql/print.c        14 Jul 2005 08:42:37 -0000      1.67
***************
*** 3,9 ****
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.66 2005/07/14 07:32:01 momjian 
Exp $
   */
  #include "postgres_fe.h"
  #include "common.h"
--- 3,9 ----
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.67 2005/07/14 08:42:37 momjian 
Exp $
   */
  #include "postgres_fe.h"
  #include "common.h"
***************
*** 24,34 ****
--- 24,40 ----
  #include <termios.h>
  #endif
  
+ #include <locale.h>
+ 
  #include "pqsignal.h"
  #include "libpq-fe.h"
  
  #include "mbprint.h"
  
+ static char *decimal_point;
+ static char *grouping;
+ static char *thousands_sep;
+ 
  static void *
  pg_local_malloc(size_t size)
  {
***************
*** 47,52 ****
--- 53,59 ----
  num_numericseps(const char *my_str)
  {
        int old_len, dec_len, int_len;
+       int     groupdigits = atoi(grouping);
  
        if (my_str[0] == '-')
                my_str++;
***************
*** 55,64 ****
        dec_len = strchr(my_str, '.') ? strlen(strchr(my_str, '.')) : 0;
  
        int_len = old_len - dec_len;
!       if (int_len % 3 != 0)
!               return int_len / 3;
        else
!               return int_len / 3 - 1; /* no leading separator */
  }
  
  static int
--- 62,71 ----
        dec_len = strchr(my_str, '.') ? strlen(strchr(my_str, '.')) : 0;
  
        int_len = old_len - dec_len;
!       if (int_len % groupdigits != 0)
!               return int_len / groupdigits;
        else
!               return int_len / groupdigits - 1;       /* no leading separator 
*/
  }
  
  static int
***************
*** 68,84 ****
  }
  
  static void 
! format_numericsep(char *my_str, char *numericsep)
  {
        int i, j, digits_before_sep, old_len, new_len, dec_len, int_len;
-       char *dec_point;
        char *new_str;
        char *dec_value;
!     
!       if (strcmp(numericsep, ".") != 0)
!               dec_point = ".";
!       else
!               dec_point = ",";
      
        if (my_str[0] == '-')
                my_str++;
--- 75,86 ----
  }
  
  static void 
! format_numericsep(char *my_str)
  {
        int i, j, digits_before_sep, old_len, new_len, dec_len, int_len;
        char *new_str;
        char *dec_value;
!       int     groupdigits = atoi(grouping);
      
        if (my_str[0] == '-')
                my_str++;
***************
*** 86,94 ****
        old_len = strlen(my_str);
        dec_len = strchr(my_str, '.') ? strlen(strchr(my_str, '.')) : 0;
        int_len = old_len - dec_len;
!       digits_before_sep = int_len % 3;
  
!       new_len = int_len + int_len / 3 + dec_len;
        if (digits_before_sep == 0)
                new_len--;      /* no leading separator */
  
--- 88,96 ----
        old_len = strlen(my_str);
        dec_len = strchr(my_str, '.') ? strlen(strchr(my_str, '.')) : 0;
        int_len = old_len - dec_len;
!       digits_before_sep = int_len % groupdigits;
  
!       new_len = int_len + int_len / groupdigits + dec_len;
        if (digits_before_sep == 0)
                new_len--;      /* no leading separator */
  
***************
*** 99,105 ****
                /* hit decimal point */
                if (my_str[i] == '.')
                {
!                       new_str[j] = *dec_point;
                        new_str[j+1] = '\0';
                        dec_value = strchr(my_str, '.');
                        strcat(new_str, ++dec_value);
--- 101,107 ----
                /* hit decimal point */
                if (my_str[i] == '.')
                {
!                       new_str[j] = *decimal_point;
                        new_str[j+1] = '\0';
                        dec_value = strchr(my_str, '.');
                        strcat(new_str, ++dec_value);
***************
*** 115,122 ****
      
                /* add separator? */
                if (i != 0 &&
!                       (i - (digits_before_sep ? digits_before_sep : 3)) % 3 
== 0)
!                       new_str[j++] = *numericsep;
  
                new_str[j] = my_str[i];
        }
--- 117,125 ----
      
                /* add separator? */
                if (i != 0 &&
!                       (i - (digits_before_sep ? digits_before_sep : 
groupdigits))
!                               % groupdigits == 0)
!                       new_str[j++] = *thousands_sep;
  
                new_str[j] = my_str[i];
        }
***************
*** 135,141 ****
                                         const char *const *cells, const char 
*const *footers,
                                         const char *opt_align, const char 
*opt_fieldsep,
                                         const char *opt_recordsep, bool 
opt_tuples_only,
!                                        char *opt_numericsep, FILE *fout)
  {
        unsigned int col_count = 0;
        unsigned int i;
--- 138,144 ----
                                         const char *const *cells, const char 
*const *footers,
                                         const char *opt_align, const char 
*opt_fieldsep,
                                         const char *opt_recordsep, bool 
opt_tuples_only,
!                                        bool opt_numericsep, FILE *fout)
  {
        unsigned int col_count = 0;
        unsigned int i;
***************
*** 174,186 ****
                        fputs(opt_recordsep, fout);
                        need_recordsep = false;
                }
!               if ((opt_align[i % col_count] == 'r') && strlen(*ptr) > 0 &&
!                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                
                        strcpy(my_cell, *ptr);
!                       format_numericsep(my_cell, opt_numericsep);
                        fputs(my_cell, fout);
                        free(my_cell);
                }
--- 177,188 ----
                        fputs(opt_recordsep, fout);
                        need_recordsep = false;
                }
!               if (opt_align[i % col_count] == 'r' && opt_numericsep)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                
                        strcpy(my_cell, *ptr);
!                       format_numericsep(my_cell);
                        fputs(my_cell, fout);
                        free(my_cell);
                }
***************
*** 220,226 ****
                                                 const char *const *cells,
                                                 const char *const *footers, 
const char *opt_align,
                                                 const char *opt_fieldsep, 
const char *opt_recordsep,
!                                                bool opt_tuples_only, char 
*opt_numericsep, FILE *fout)
  {
        unsigned int col_count = 0;
        unsigned int i;
--- 222,228 ----
                                                 const char *const *cells,
                                                 const char *const *footers, 
const char *opt_align,
                                                 const char *opt_fieldsep, 
const char *opt_recordsep,
!                                                bool opt_tuples_only, bool 
opt_numericsep, FILE *fout)
  {
        unsigned int col_count = 0;
        unsigned int i;
***************
*** 251,263 ****
  
                fputs(headers[i % col_count], fout);
                fputs(opt_fieldsep, fout);
!               if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 &&
!                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                
                        strcpy(my_cell, *ptr);
!                       format_numericsep(my_cell, opt_numericsep);
                        fputs(my_cell, fout);
                        free(my_cell);
                }
--- 253,264 ----
  
                fputs(headers[i % col_count], fout);
                fputs(opt_fieldsep, fout);
!               if (opt_align[i % col_count] == 'r' && opt_numericsep)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                
                        strcpy(my_cell, *ptr);
!                       format_numericsep(my_cell);
                        fputs(my_cell, fout);
                        free(my_cell);
                }
***************
*** 325,331 ****
  static void
  print_aligned_text(const char *title, const char *const *headers,
                                   const char *const *cells, const char *const 
*footers,
!                                  const char *opt_align, bool opt_tuples_only, 
char *opt_numericsep,
                                   unsigned short int opt_border, int encoding,
                                   FILE *fout)
  {
--- 326,332 ----
  static void
  print_aligned_text(const char *title, const char *const *headers,
                                   const char *const *cells, const char *const 
*footers,
!                                  const char *opt_align, bool opt_tuples_only, 
bool opt_numericsep,
                                   unsigned short int opt_border, int encoding,
                                   FILE *fout)
  {
***************
*** 394,401 ****
        {
                int numericseps;
  
!               if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 &&
!                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
                    numericseps = num_numericseps(*ptr);
                else 
                    numericseps = 0;
--- 395,401 ----
        {
                int numericseps;
  
!               if (opt_align[i % col_count] == 'r' && opt_numericsep)
                    numericseps = num_numericseps(*ptr);
                else 
                    numericseps = 0;
***************
*** 480,491 ****
                /* content */
                if (opt_align[i % col_count] == 'r')
                {
!                   if (strlen(*ptr) > 0 && opt_numericsep != NULL && 
strlen(opt_numericsep) > 0)
                    {
                                char *my_cell = pg_local_malloc(cell_w[i] + 1);
  
                                strcpy(my_cell, *ptr);
!                               format_numericsep(my_cell, opt_numericsep);
                                fprintf(fout, "%*s%s", widths[i % col_count] - 
cell_w[i], "", my_cell);
                                free(my_cell);
                    }
--- 480,491 ----
                /* content */
                if (opt_align[i % col_count] == 'r')
                {
!                   if (opt_numericsep)
                    {
                                char *my_cell = pg_local_malloc(cell_w[i] + 1);
  
                                strcpy(my_cell, *ptr);
!                               format_numericsep(my_cell);
                                fprintf(fout, "%*s%s", widths[i % col_count] - 
cell_w[i], "", my_cell);
                                free(my_cell);
                    }
***************
*** 547,553 ****
  print_aligned_vertical(const char *title, const char *const *headers,
                                           const char *const *cells, const char 
*const *footers,
                                           const char *opt_align, bool 
opt_tuples_only,
!                                          char *opt_numericsep, unsigned short 
int opt_border,
                                           int encoding, FILE *fout)
  {
        unsigned int col_count = 0;
--- 547,553 ----
  print_aligned_vertical(const char *title, const char *const *headers,
                                           const char *const *cells, const char 
*const *footers,
                                           const char *opt_align, bool 
opt_tuples_only,
!                                          bool opt_numericsep, unsigned short 
int opt_border,
                                           int encoding, FILE *fout)
  {
        unsigned int col_count = 0;
***************
*** 612,619 ****
        {
                int numericseps;
  
!               if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 &&
!                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
                    numericseps = num_numericseps(*ptr);
                else 
                    numericseps = 0;
--- 612,618 ----
        {
                int numericseps;
  
!               if (opt_align[i % col_count] == 'r' && opt_numericsep)
                    numericseps = num_numericseps(*ptr);
                else 
                    numericseps = 0;
***************
*** 696,704 ****
                        char *my_cell = pg_local_malloc(cell_w[i] + 1);
  
                        strcpy(my_cell, *ptr);
!                       if ((opt_align[i % col_count] == 'r') && strlen(*ptr) 
!= 0 &&
!                               opt_numericsep != NULL && 
strlen(opt_numericsep) > 0)
!                           format_numericsep(my_cell, opt_numericsep);
                        if (opt_border < 2)
                                puts(my_cell);
                        else
--- 695,702 ----
                        char *my_cell = pg_local_malloc(cell_w[i] + 1);
  
                        strcpy(my_cell, *ptr);
!                       if (opt_align[i % col_count] == 'r' && opt_numericsep)
!                           format_numericsep(my_cell);
                        if (opt_border < 2)
                                puts(my_cell);
                        else
***************
*** 785,791 ****
  print_html_text(const char *title, const char *const *headers,
                                const char *const *cells, const char *const 
*footers,
                                const char *opt_align, bool opt_tuples_only,
!                               char *opt_numericsep, unsigned short int 
opt_border,
                                const char *opt_table_attr, FILE *fout)
  {
        unsigned int col_count = 0;
--- 783,789 ----
  print_html_text(const char *title, const char *const *headers,
                                const char *const *cells, const char *const 
*footers,
                                const char *opt_align, bool opt_tuples_only,
!                               bool opt_numericsep, unsigned short int 
opt_border,
                                const char *opt_table_attr, FILE *fout)
  {
        unsigned int col_count = 0;
***************
*** 831,843 ****
                /* is string only whitespace? */
                if ((*ptr)[strspn(*ptr, " \t")] == '\0')                
                        fputs("&nbsp; ", fout);
!               else if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 
&&
!                                opt_numericsep != NULL && 
strlen(opt_numericsep) > 0)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
  
                    strcpy(my_cell, *ptr);
!                   format_numericsep(my_cell, opt_numericsep);
                    html_escaped_print(my_cell, fout);
                    free(my_cell);
                }
--- 829,840 ----
                /* is string only whitespace? */
                if ((*ptr)[strspn(*ptr, " \t")] == '\0')                
                        fputs("&nbsp; ", fout);
!               else if (opt_align[i % col_count] == 'r' && opt_numericsep)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
  
                    strcpy(my_cell, *ptr);
!                   format_numericsep(my_cell);
                    html_escaped_print(my_cell, fout);
                    free(my_cell);
                }
***************
*** 873,879 ****
  print_html_vertical(const char *title, const char *const *headers,
                                  const char *const *cells, const char *const 
*footers,
                                  const char *opt_align, bool opt_tuples_only,
!                                 char *opt_numericsep, unsigned short int 
opt_border,
                                  const char *opt_table_attr, FILE *fout)
  {
        unsigned int col_count = 0;
--- 870,876 ----
  print_html_vertical(const char *title, const char *const *headers,
                                  const char *const *cells, const char *const 
*footers,
                                  const char *opt_align, bool opt_tuples_only,
!                                 bool opt_numericsep, unsigned short int 
opt_border,
                                  const char *opt_table_attr, FILE *fout)
  {
        unsigned int col_count = 0;
***************
*** 917,929 ****
                /* is string only whitespace? */
                if ((*ptr)[strspn(*ptr, " \t")] == '\0')                
                        fputs("&nbsp; ", fout);
!               else if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 
&&
!                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                    
                    strcpy(my_cell, *ptr);
!                   format_numericsep(my_cell, opt_numericsep);
                    html_escaped_print(my_cell, fout);
                    free(my_cell);
                }
--- 914,925 ----
                /* is string only whitespace? */
                if ((*ptr)[strspn(*ptr, " \t")] == '\0')                
                        fputs("&nbsp; ", fout);
!               else if (opt_align[i % col_count] == 'r' && opt_numericsep)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                    
                    strcpy(my_cell, *ptr);
!                   format_numericsep(my_cell);
                    html_escaped_print(my_cell, fout);
                    free(my_cell);
                }
***************
*** 999,1005 ****
  print_latex_text(const char *title, const char *const *headers,
                                 const char *const *cells, const char *const 
*footers,
                                 const char *opt_align, bool opt_tuples_only,
!                                char *opt_numericsep, unsigned short int 
opt_border,
                                 FILE *fout)
  {
        unsigned int col_count = 0;
--- 995,1001 ----
  print_latex_text(const char *title, const char *const *headers,
                                 const char *const *cells, const char *const 
*footers,
                                 const char *opt_align, bool opt_tuples_only,
!                                bool opt_numericsep, unsigned short int 
opt_border,
                                 FILE *fout)
  {
        unsigned int col_count = 0;
***************
*** 1060,1072 ****
        /* print cells */
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
        {
!               if (strlen(*ptr) != 0 &&
!                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                    
                        strcpy(my_cell, *ptr);
!                       format_numericsep(my_cell, opt_numericsep);
                        latex_escaped_print(my_cell, fout);
                        free(my_cell);
                }
--- 1056,1067 ----
        /* print cells */
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
        {
!               if (opt_numericsep)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                    
                        strcpy(my_cell, *ptr);
!                       format_numericsep(my_cell);
                        latex_escaped_print(my_cell, fout);
                        free(my_cell);
                }
***************
*** 1103,1109 ****
  print_latex_vertical(const char *title, const char *const *headers,
                                  const char *const *cells, const char *const 
*footers,
                                  const char *opt_align, bool opt_tuples_only,
!                                 char *opt_numericsep, unsigned short int 
opt_border,
                                  FILE *fout)
  {
        unsigned int col_count = 0;
--- 1098,1104 ----
  print_latex_vertical(const char *title, const char *const *headers,
                                  const char *const *cells, const char *const 
*footers,
                                  const char *opt_align, bool opt_tuples_only,
!                                 bool opt_numericsep, unsigned short int 
opt_border,
                                  FILE *fout)
  {
        unsigned int col_count = 0;
***************
*** 1174,1186 ****
        if (footers && !opt_tuples_only)
                for (ptr = footers; *ptr; ptr++)
                {
!                       if (strlen(*ptr) != 0 &&
!                               opt_numericsep != NULL && 
strlen(opt_numericsep) > 0)
                        {
                                char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
  
                                strcpy(my_cell, *ptr);
!                               format_numericsep(my_cell, opt_numericsep);
                                latex_escaped_print(my_cell, fout);
                                free(my_cell);
                        }
--- 1169,1180 ----
        if (footers && !opt_tuples_only)
                for (ptr = footers; *ptr; ptr++)
                {
!                       if (opt_numericsep)
                        {
                                char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
  
                                strcpy(my_cell, *ptr);
!                               format_numericsep(my_cell);
                                latex_escaped_print(my_cell, fout);
                                free(my_cell);
                        }
***************
*** 1221,1227 ****
  print_troff_ms_text(const char *title, const char *const *headers,
                                 const char *const *cells, const char *const 
*footers,
                                 const char *opt_align, bool opt_tuples_only,
!                                char *opt_numericsep, unsigned short int 
opt_border,
                                 FILE *fout)
  {
        unsigned int col_count = 0;
--- 1215,1221 ----
  print_troff_ms_text(const char *title, const char *const *headers,
                                 const char *const *cells, const char *const 
*footers,
                                 const char *opt_align, bool opt_tuples_only,
!                                bool opt_numericsep, unsigned short int 
opt_border,
                                 FILE *fout)
  {
        unsigned int col_count = 0;
***************
*** 1275,1287 ****
        /* print cells */
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
        {
!               if (strlen(*ptr) != 0 &&
!                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                    
                        strcpy(my_cell, *ptr);
!                       format_numericsep(my_cell, opt_numericsep);
                        troff_ms_escaped_print(my_cell, fout);
                        free(my_cell);
                }
--- 1269,1280 ----
        /* print cells */
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
        {
!               if (opt_numericsep)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                    
                        strcpy(my_cell, *ptr);
!                       format_numericsep(my_cell);
                        troff_ms_escaped_print(my_cell, fout);
                        free(my_cell);
                }
***************
*** 1315,1321 ****
  print_troff_ms_vertical(const char *title, const char *const *headers,
                                  const char *const *cells, const char *const 
*footers,
                                  const char *opt_align, bool opt_tuples_only,
!                                 char *opt_numericsep, unsigned short int 
opt_border,
                                  FILE *fout)
  {
        unsigned int col_count = 0;
--- 1308,1314 ----
  print_troff_ms_vertical(const char *title, const char *const *headers,
                                  const char *const *cells, const char *const 
*footers,
                                  const char *opt_align, bool opt_tuples_only,
!                                 bool opt_numericsep, unsigned short int 
opt_border,
                                  FILE *fout)
  {
        unsigned int col_count = 0;
***************
*** 1345,1356 ****
          if (opt_tuples_only)
                fputs("c l;\n", fout);
  
- 
        /* count columns */
        for (ptr = headers; *ptr; ptr++)
                col_count++;
  
- 
        /* print records */
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
        {
--- 1338,1347 ----
***************
*** 1390,1402 ****
  
                troff_ms_escaped_print(headers[i % col_count], fout);
                fputc('\t', fout);
!               if (strlen(*ptr) != 0 &&
!                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                    
                        strcpy(my_cell, *ptr);
!                       format_numericsep(my_cell, opt_numericsep);
                        troff_ms_escaped_print(my_cell, fout);
                        free(my_cell);
                }
--- 1381,1392 ----
  
                troff_ms_escaped_print(headers[i % col_count], fout);
                fputc('\t', fout);
!               if (opt_numericsep)
                {
                        char *my_cell = 
pg_local_malloc(len_with_numericsep(*ptr) + 1);
                    
                        strcpy(my_cell, *ptr);
!                       format_numericsep(my_cell);
                        troff_ms_escaped_print(my_cell, fout);
                        free(my_cell);
                }
***************
*** 1714,1717 ****
  }
  
  
! /* the end */
--- 1704,1729 ----
  }
  
  
! void
! setDecimalLocale(void)
! {
!       struct lconv *extlconv;
! 
!       extlconv = localeconv();
! 
!       /* These are treated as single-byte strings in the code */
!       if (*extlconv->decimal_point)
!               decimal_point = strdup(extlconv->decimal_point);
!       else
!               decimal_point = ".";    /* SQL output standard */
!       if (*extlconv->grouping && atoi(extlconv->grouping) > 0)
!               grouping = strdup(extlconv->grouping);
!       else
!               grouping = "3";         /* most common */
!       if (*extlconv->thousands_sep)
!               thousands_sep = strdup(extlconv->thousands_sep);
!       else
!               thousands_sep = ",";    /* matches SQL standard decimal marker 
*/
! }
!       
! 
Index: src/bin/psql/print.h
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/print.h,v
retrieving revision 1.26
retrieving revision 1.27
diff -c -r1.26 -r1.27
*** src/bin/psql/print.h        10 Jul 2005 03:46:13 -0000      1.26
--- src/bin/psql/print.h        14 Jul 2005 08:42:37 -0000      1.27
***************
*** 3,9 ****
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.26 2005/07/10 03:46:13 momjian 
Exp $
   */
  #ifndef PRINT_H
  #define PRINT_H
--- 3,9 ----
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.27 2005/07/14 08:42:37 momjian 
Exp $
   */
  #ifndef PRINT_H
  #define PRINT_H
***************
*** 40,46 ****
        char       *fieldSep;           /* field separator for unaligned text 
mode */
        char       *recordSep;          /* record separator for unaligned text
                                                                 * mode */
!       char       *numericSep;         /* numeric units separator */
        char       *tableAttr;          /* attributes for HTML <table ...> */
        int                     encoding;               /* character encoding */
        bool            normal_query;   /* are we presenting the results of a
--- 40,47 ----
        char       *fieldSep;           /* field separator for unaligned text 
mode */
        char       *recordSep;          /* record separator for unaligned text
                                                                 * mode */
!       bool            numericSep;             /* locale-aware numeric units 
separator and
!                                                                *  decimal 
marker */
        char       *tableAttr;          /* attributes for HTML <table ...> */
        int                     encoding;               /* character encoding */
        bool            normal_query;   /* are we presenting the results of a
***************
*** 86,91 ****
--- 87,94 ----
  void          printQuery(const PGresult *result, const printQueryOpt *opt,
                                           FILE *fout, FILE *flog);
  
+ void  setDecimalLocale(void);
+ 
  #ifndef __CYGWIN__
  #define DEFAULT_PAGER "more"
  #else
Index: src/bin/psql/startup.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/startup.c,v
retrieving revision 1.118
retrieving revision 1.119
diff -c -r1.118 -r1.119
*** src/bin/psql/startup.c      21 Jun 2005 04:02:33 -0000      1.118
--- src/bin/psql/startup.c      14 Jul 2005 08:42:37 -0000      1.119
***************
*** 3,9 ****
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.118 2005/06/21 04:02:33 tgl 
Exp $
   */
  #include "postgres_fe.h"
  
--- 3,9 ----
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.119 2005/07/14 08:42:37 
momjian Exp $
   */
  #include "postgres_fe.h"
  
***************
*** 130,135 ****
--- 130,136 ----
        setvbuf(stderr, NULL, _IONBF, 0);
        setup_win32_locks();
  #endif
+       setDecimalLocale();
        pset.cur_cmd_source = stdin;
        pset.cur_cmd_interactive = false;
        pset.encoding = PQenv2encoding();
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match

Reply via email to