Unix Technical Forum

thousands comma numeric formatting in psql

This is a discussion on thousands comma numeric formatting in psql within the Pgsql Patches forums, part of the PostgreSQL category; --> Hello, This is my first post to this list. Sorry if my english it's not so good. It's not ...


Go Back   Unix Technical Forum > Database Server Software > PostgreSQL > Pgsql Patches

Register FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 04-17-2008, 11:31 PM
Eugen Nedelcu
 
Posts: n/a
Default thousands comma numeric formatting in psql

Hello,

This is my first post to this list.
Sorry if my english it's not so good. It's not my native language.

I'm interrested to now if someone think that having a feature like
'thousands comma delimited numeric formatting' in psql it's a
usefull thing.

I've made a patch for psql that adds this feature, so issuing a
select like this:

my_database=> select 1234567.89;

results in:

?column?
--------------
1,234,567.89

This feature is toggle on/off with a backslash command ('\n'):

my_database=> \n
Numeric formatting is off.

my_database=> select 1234567.89;

?column?
--------------
1234567.89

For me, psql it's still the best client for postgres, faster and
flexible than graphic ones. And having tables with many numeric
columns witch contain huge numbers make difficult to read this
numbers.

One solution to deal with this is to use to_char function, but for
complex selects against multiple tables it's not a good option.

Another one is to make a custom function that works like this:

select my_function(... complex subselect ...);

but this seems ugly to me.

By adding the '\n' switch to psql I can make any complex select and
have all numeric fields in result formatted in easy readable form.

I'm not an expert in postgresql, so if someone thinks there is an
easier way to deal with numeric fields, please share.

If my idea is considered usefull I can post the patch to this list.

Best regards,
Eugen.

---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

http://archives.postgresql.org

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #2 (permalink)  
Old 04-17-2008, 11:31 PM
Bruno Wolff III
 
Posts: n/a
Default Re: thousands comma numeric formatting in psql

On Tue, Jun 21, 2005 at 08:42:16 +0300,
Eugen Nedelcu <eugen@sifolt.ro> wrote:
>
> One solution to deal with this is to use to_char function, but for
> complex selects against multiple tables it's not a good option.


Why not? You only have to apply it to the output expressions that
need it.

Note that if you output numbers like this, you also need to be able to
read them back in. I don't think adding complexity for doing that is
worth not having to add a few to_char calls in your select queries.

---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

http://archives.postgresql.org

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #3 (permalink)  
Old 04-17-2008, 11:31 PM
Eugen Nedelcu
 
Posts: n/a
Default Re: thousands comma numeric formatting in psql

On Tue, Jun 21, 2005 at 06:59:38AM -0500, Bruno Wolff III wrote:
> On Tue, Jun 21, 2005 at 08:42:16 +0300,
> Eugen Nedelcu <eugen@sifolt.ro> wrote:
> >
> > One solution to deal with this is to use to_char function, but for
> > complex selects against multiple tables it's not a good option.

>
> Why not? You only have to apply it to the output expressions that
> need it.


I think this:

select * from table_with_text_and_numeric_fields;

is much,much easier than:

select text_field1,text_field2,to_char(numeric_field1, '99G999G999'),
to_char(numeric_field2, '9G999G999G999'), text_field3,
text_field4, to_char(numeric_field3, 'MI90G999D99') from
table_with_text_and_numeric_fields;

>
> Note that if you output numbers like this, you also need to be able to
> read them back in. I don't think adding complexity for doing that is
> worth not having to add a few to_char calls in your select queries.
>


I don't know what 'read them back in' means to you.
This formatting is only done when the number is output to the screen.

Something like:
fputs(thousands_comma_number, fout)
instead of:
fputs(original_number, fout)

If you want to output to some file for reading back later, you could
turn the feature off with the backslash switch '\n'.

This is a patch for psql client and not for the backend. It's role
is to output numbers to screen in easy readable form (2,345,675,454,543
is much easier to read then 2345675454543.456). I think graphical
clients like pgAdmin or phppgadmin have a way to do this. I don't know
this for sure but I will investigate it.

Best Regards,
Eugen

---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to majordomo@postgresql.org so that your
message can get through to the mailing list cleanly

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #4 (permalink)  
Old 04-17-2008, 11:31 PM
Alvaro Herrera
 
Posts: n/a
Default Re: thousands comma numeric formatting in psql

On Tue, Jun 21, 2005 at 04:03:43PM +0300, Eugen Nedelcu wrote:

> This is a patch for psql client and not for the backend. It's role
> is to output numbers to screen in easy readable form (2,345,675,454,543
> is much easier to read then 2345675454543.456). I think graphical
> clients like pgAdmin or phppgadmin have a way to do this. I don't know
> this for sure but I will investigate it.


I think it would be much nicer if it was a backend setting. If it
depended on the locale setting (LC_NUMERIC, I think) and worked for both
input and output, it would be very good.

--
Alvaro Herrera (<alvherre[a]surnet.cl>)
"Uno puede defenderse de los ataques; contra los elogios se esta indefenso"

---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #5 (permalink)  
Old 04-17-2008, 11:31 PM
Bruno Wolff III
 
Posts: n/a
Default Re: thousands comma numeric formatting in psql

On Tue, Jun 21, 2005 at 16:03:43 +0300,
Eugen Nedelcu <eugen@sifolt.ro> wrote:
>
> This is a patch for psql client and not for the backend. It's role
> is to output numbers to screen in easy readable form (2,345,675,454,543
> is much easier to read then 2345675454543.456). I think graphical
> clients like pgAdmin or phppgadmin have a way to do this. I don't know
> this for sure but I will investigate it.


I did miss that this was a psql only feature. I still don't see a great
need, but it isn't going to cause a problem for copy or pg_dump that way.

---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faq

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #6 (permalink)  
Old 04-17-2008, 11:31 PM
Tom Lane
 
Posts: n/a
Default Re: thousands comma numeric formatting in psql

Alvaro Herrera <alvherre@surnet.cl> writes:
> On Tue, Jun 21, 2005 at 04:03:43PM +0300, Eugen Nedelcu wrote:
>> This is a patch for psql client and not for the backend.


> I think it would be much nicer if it was a backend setting.


Doing this as a backend setting has been proposed and rejected before.
The risk of breaking client code seems to outweigh any possible value.

As a psql setting, though, it seems relatively harmless --- certainly
no more dangerous than \x or the other pset formatting parameters.

> If it depended on the locale setting (LC_NUMERIC, I think)


Yes, I wanted to ask that too --- if the patch can cope with locales that
exchange the roles of comma and period, that would make a lot of people
very happy.

regards, tom lane

---------------------------(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

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #7 (permalink)  
Old 04-17-2008, 11:31 PM
Eugen Nedelcu
 
Posts: n/a
Default Re: thousands comma numeric formatting in psql

Hello,

I have included my patch attached to this mail.

I have made the changes to deal with locale settings from client
environment. So now you can start psql like this:

(export LC_ALL=ro_RO; psql -U user db)

and have numeric formatting with '.' as thousands separator and
',' as decimal point, or

(export LC_ALL=en_US; psql -U user db)

and have numeric formatting with ',' as thousands separator and
'.' as decimal point. This formatting is default when locale is 'C'

You can set any locale and numeric formatting code will take it in
consideration.

This patch is for version 7.3.2. The steps for install is:

1) cp thousands_comma.diff $POSTGRES_DIR/src/bin/psql
2) cd $POSTGRES_DIR/src/bin/psql
3) patch -p0 < thousands_comma.diff
4) ../../../configure && make


Best Regards,
Eugen

---------------------------(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

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #8 (permalink)  
Old 04-17-2008, 11:39 PM
Bruce Momjian
 
Posts: n/a
Default Re: thousands comma numeric formatting in psql

Eugen Nedelcu wrote:
> Hello,
>
> I have included my patch attached to this mail.
>
> I have made the changes to deal with locale settings from client
> environment. So now you can start psql like this:
>
> (export LC_ALL=ro_RO; psql -U user db)
>
> and have numeric formatting with '.' as thousands separator and
> ',' as decimal point, or
>
> (export LC_ALL=en_US; psql -U user db)
>
> and have numeric formatting with ',' as thousands separator and
> '.' as decimal point. This formatting is default when locale is 'C'
>
> You can set any locale and numeric formatting code will take it in
> consideration.
>
> This patch is for version 7.3.2. The steps for install is:
>
> 1) cp thousands_comma.diff $POSTGRES_DIR/src/bin/psql
> 2) cd $POSTGRES_DIR/src/bin/psql
> 3) patch -p0 < thousands_comma.diff
> 4) ../../../configure && make


I have heavily modified your patch and have applied it. Instead of
using langinfo, I used a \pset variable numericsep. (We can talk about
adding langinfo detection later.) By default, it is off, ''. If you
set it to '.', the decimal marker will be ','. This also allows
separators like ' ' too so numebers can appear as 100 000.

I have also added documentation.

--
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.145
diff -c -c -r1.145 psql-ref.sgml
*** doc/src/sgml/ref/psql-ref.sgml 14 Jun 2005 02:57:38 -0000 1.145
--- doc/src/sgml/ref/psql-ref.sgml 10 Jul 2005 03:24:16 -0000
***************
*** 1493,1498 ****
--- 1493,1510 ----
</varlistentry>

<varlistentry>
+ <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>
+
+ <varlistentry>
<term><literal>recordsep</literal></term>
<listitem>
<para>
Index: src/bin/psql/command.c
================================================== =================
RCS file: /cvsroot/pgsql/src/bin/psql/command.c,v
retrieving revision 1.146
diff -c -c -r1.146 command.c
*** src/bin/psql/command.c 13 Jun 2005 06:36:22 -0000 1.146
--- src/bin/psql/command.c 10 Jul 2005 03:24:17 -0000
***************
*** 838,844 ****
else if (strcmp(cmd, "x") == 0)
success = do_pset("expanded", NULL, &pset.popt, quiet);

-
/* \z -- list table rights (equivalent to \dp) */
else if (strcmp(cmd, "z") == 0)
{
--- 838,843 ----
***************
*** 1421,1426 ****
--- 1420,1436 ----
: _("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 */
else if (strcmp(param, "null") == 0)
{
Index: src/bin/psql/help.c
================================================== =================
RCS file: /cvsroot/pgsql/src/bin/psql/help.c,v
retrieving revision 1.103
diff -c -c -r1.103 help.c
*** src/bin/psql/help.c 6 Jul 2005 03:14:48 -0000 1.103
--- src/bin/psql/help.c 10 Jul 2005 03:24:18 -0000
***************
*** 239,245 ****
fprintf(output, _(" \\pset NAME [VALUE]\n"
" set table output option\n"
" (NAME := {format|border|expanded|fieldsep|footer|null|\n"
! " recordsep|tuples_only|title|tableattr|pager})\n")) ;
fprintf(output, _(" \\t show only rows (currently %s)\n"),
ON(pset.popt.topt.tuples_only));
fprintf(output, _(" \\T [STRING] set HTML <table> tag attributes, or unset if none\n"));
--- 239,245 ----
fprintf(output, _(" \\pset NAME [VALUE]\n"
" set table output option\n"
" (NAME := {format|border|expanded|fieldsep|footer|null|\n"
! " numericsep|recordsep|tuples_only|title|tableattr|p ager})\n"));
fprintf(output, _(" \\t show only rows (currently %s)\n"),
ON(pset.popt.topt.tuples_only));
fprintf(output, _(" \\T [STRING] set HTML <table> tag attributes, or unset if none\n"));
Index: src/bin/psql/print.c
================================================== =================
RCS file: /cvsroot/pgsql/src/bin/psql/print.c,v
retrieving revision 1.60
diff -c -c -r1.60 print.c
*** src/bin/psql/print.c 14 Jun 2005 22:15:57 -0000 1.60
--- src/bin/psql/print.c 10 Jul 2005 03:24:24 -0000
***************
*** 29,48 ****

#include "mbprint.h"

/*************************/
/* Unaligned text */
/*************************/


static void
! print_unaligned_text(const char *title, const char *const * headers,
! const char *const * cells, const char *const * footers,
! const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones,
! FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const * ptr;
bool need_recordsep = false;

if (!opt_fieldsep)
--- 29,135 ----

#include "mbprint.h"

+ static int
+ num_numericseps(const char *my_str)
+ {
+ int old_len, dec_len, int_len;
+
+ if (my_str[0] == '-')
+ my_str++;
+
+ old_len = strlen(my_str);
+ 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
+ len_with_numericsep(const char *my_str)
+ {
+ return strlen(my_str) + num_numericseps(my_str);
+ }
+
+ 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++;
+
+ 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 */
+
+ new_str = malloc(new_len);
+ if (!new_str)
+ {
+ fprintf(stderr, _("out of memory\n"));
+ exit(EXIT_FAILURE);
+ }
+
+ for (i=0, j=0; ; i++, j++)
+ {
+ /* 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);
+ break;
+ }
+
+ /* end of string */
+ if (my_str[i] == '\0')
+ {
+ new_str[j] = '\0';
+ break;
+ }
+
+ /* 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];
+ }
+
+ strcpy(my_str, new_str);
+ free(new_str);
+ }
+
/*************************/
/* Unaligned text */
/*************************/


static void
! print_unaligned_text(const char *title, const char *const *headers,
! const char *const *cells, const char *const *footers,
! const char *opt_align, const char *opt_fieldsep,
! const char *opt_recordsep, bool opt_barebones,
! char *opt_numericsep, FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const *ptr;
bool need_recordsep = false;

if (!opt_fieldsep)
***************
*** 77,83 ****
fputs(opt_recordsep, fout);
need_recordsep = false;
}
! fputs(*ptr, fout);
if ((i + 1) % col_count)
fputs(opt_fieldsep, fout);
else
--- 164,187 ----
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 = malloc(len_with_numericsep(*ptr));
!
! if (!my_cell)
! {
! fprintf(stderr, _("out of memory\n"));
! exit(EXIT_FAILURE);
! }
! strcpy(my_cell, *ptr);
! format_numericsep(my_cell, opt_numericsep);
! fputs(my_cell, fout);
! free(my_cell);
! }
! else
! fputs(*ptr, fout);
!
if ((i + 1) % col_count)
fputs(opt_fieldsep, fout);
else
***************
*** 107,120 ****


static void
! print_unaligned_vertical(const char *title, const char *const * headers,
! const char *const * cells, const char *const * footers,
! const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones,
! FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const * ptr;

if (!opt_fieldsep)
opt_fieldsep = "";
--- 211,225 ----


static void
! print_unaligned_vertical(const char *title, const char *const *headers,
! const char *const *cells,
! const char *const *footers, const char *opt_align,
! const char *opt_fieldsep, const char *opt_recordsep,
! bool opt_barebones, char *opt_numericsep, FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const *ptr;

if (!opt_fieldsep)
opt_fieldsep = "";
***************
*** 141,147 ****

fputs(headers[i % col_count], fout);
fputs(opt_fieldsep, fout);
! fputs(*ptr, fout);
}

/* print footers */
--- 246,268 ----

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 = malloc(len_with_numericsep(*ptr));
!
! if (!my_cell)
! {
! fprintf(stderr, _("out of memory\n"));
! exit(EXIT_FAILURE);
! }
! strcpy(my_cell, *ptr);
! format_numericsep(my_cell, opt_numericsep);
! fputs(my_cell, fout);
! free(my_cell);
! }
! else
! fputs(*ptr, fout);
}

/* print footers */
***************
*** 202,210 ****


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_barebones,
unsigned short int opt_border, int encoding,
FILE *fout)
{
--- 323,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_barebones, char *opt_numericsep,
unsigned short int opt_border, int encoding,
FILE *fout)
{
***************
*** 216,222 ****
tmp;
unsigned int *widths,
total_w;
! const char *const * ptr;

/* count columns */
for (ptr = headers; *ptr; ptr++)
--- 337,343 ----
tmp;
unsigned int *widths,
total_w;
! const char *const *ptr;

/* count columns */
for (ptr = headers; *ptr; ptr++)
***************
*** 271,277 ****

for (i = 0, ptr = cells; *ptr; ptr++, i++)
{
! tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding);
if (tmp > widths[i % col_count])
widths[i % col_count] = tmp;
cell_w[i] = tmp;
--- 392,406 ----

for (i = 0, ptr = cells; *ptr; ptr++, i++)
{
! 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;
!
! tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding) + numericseps;
if (tmp > widths[i % col_count])
widths[i % col_count] = tmp;
cell_w[i] = tmp;
***************
*** 351,358 ****
/* content */
if (opt_align[i % col_count] == 'r')
{
! fprintf(fout, "%*s%s",
! widths[i % col_count] - cell_w[i], "", cells[i]);
}
else
{
--- 480,501 ----
/* content */
if (opt_align[i % col_count] == 'r')
{
! if (strlen(*ptr) > 0 && opt_numericsep != NULL && strlen(opt_numericsep) > 0)
! {
! char *my_cell = malloc(cell_w[i]);
!
! if (!my_cell)
! {
! fprintf(stderr, _("out of memory\n"));
! exit(EXIT_FAILURE);
! }
! 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);
! }
! else
! fprintf(fout, "%*s%s", widths[i % col_count] - cell_w[i], "", *ptr);
}
else
{
***************
*** 406,419 ****


static void
! print_aligned_vertical(const char *title, const char *const * headers,
! const char *const * cells, const char *const * footers,
! bool opt_barebones, unsigned short int opt_border,
int encoding, FILE *fout)
{
unsigned int col_count = 0;
unsigned int record = 1;
! const char *const * ptr;
unsigned int i,
tmp = 0,
hwidth = 0,
--- 549,563 ----


static void
! print_aligned_vertical(const char *title, const char *const *headers,
! const char *const *cells, const char *const *footers,
! const char *opt_align, bool opt_barebones,
! char *opt_numericsep, unsigned short int opt_border,
int encoding, FILE *fout)
{
unsigned int col_count = 0;
unsigned int record = 1;
! const char *const *ptr;
unsigned int i,
tmp = 0,
hwidth = 0,
***************
*** 471,477 ****
/* find longest data cell */
for (i = 0, ptr = cells; *ptr; ptr++, i++)
{
! tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding);
if (tmp > dwidth)
dwidth = tmp;
cell_w[i] = tmp;
--- 615,629 ----
/* find longest data cell */
for (i = 0, ptr = cells; *ptr; ptr++, i++)
{
! 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;
!
! tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding) + numericseps;
if (tmp > dwidth)
dwidth = tmp;
cell_w[i] = tmp;
***************
*** 556,565 ****
else
fputs(" ", fout);

! if (opt_border < 2)
! fprintf(fout, "%s\n", *ptr);
! else
! fprintf(fout, "%-s%*s |\n", *ptr, dwidth - cell_w[i], "");
}

if (opt_border == 2)
--- 708,731 ----
else
fputs(" ", fout);

! {
! char *my_cell = malloc(cell_w[i]);
!
! if (!my_cell)
! {
! fprintf(stderr, _("out of memory\n"));
! exit(EXIT_FAILURE);
! }
! 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
! fprintf(fout, "%-s%*s |\n", my_cell, dwidth - cell_w[i], "");
! free(my_cell);
! }
}

if (opt_border == 2)
***************
*** 637,651 ****


static void
! print_html_text(const char *title, const char *const * headers,
! const char *const * cells, const char *const * footers,
! const char *opt_align, bool opt_barebones, unsigned short int opt_border,
! const char *opt_table_attr,
! FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const * ptr;

fprintf(fout, "<table border=\"%d\"", opt_border);
if (opt_table_attr)
--- 803,817 ----


static void
! print_html_text(const char *title, const char *const *headers,
! const char *const *cells, const char *const *footers,
! const char *opt_align, bool opt_barebones,
! char *opt_numericsep, unsigned short int opt_border,
! const char *opt_table_attr, FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const *ptr;

fprintf(fout, "<table border=\"%d\"", opt_border);
if (opt_table_attr)
***************
*** 683,693 ****
fputs(" <tr valign=\"top\">\n", fout);

fprintf(fout, " <td align=\"%s\">", opt_align[(i) % col_count] == 'r' ? "right" : "left");
! if ((*ptr)[strspn(*ptr, " \t")] == '\0') /* is string only
! * whitespace? */
fputs("&nbsp; ", fout);
else
html_escaped_print(*ptr, fout);
fputs("</td>\n", fout);

if ((i + 1) % col_count == 0)
--- 849,875 ----
fputs(" <tr valign=\"top\">\n", fout);

fprintf(fout, " <td align=\"%s\">", opt_align[(i) % col_count] == 'r' ? "right" : "left");
! /* 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 = malloc(len_with_numericsep(*ptr));
+
+ if (!my_cell)
+ {
+ fprintf(stderr, _("out of memory\n"));
+ exit(EXIT_FAILURE);
+ }
+ strcpy(my_cell, *ptr);
+ format_numericsep(my_cell, opt_numericsep);
+ html_escaped_print(my_cell, fout);
+ free(my_cell);
+ }
else
html_escaped_print(*ptr, fout);
+
fputs("</td>\n", fout);

if ((i + 1) % col_count == 0)
***************
*** 714,729 ****


static void
! print_html_vertical(const char *title, const char *const * headers,
! const char *const * cells, const char *const * footers,
! const char *opt_align, bool opt_barebones, unsigned short int opt_border,
! const char *opt_table_attr,
! FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
unsigned int record = 1;
! const char *const * ptr;

fprintf(fout, "<table border=\"%d\"", opt_border);
if (opt_table_attr)
--- 896,911 ----


static void
! print_html_vertical(const char *title, const char *const *headers,
! const char *const *cells, const char *const *footers,
! const char *opt_align, bool opt_barebones,
! char *opt_numericsep, unsigned short int opt_border,
! const char *opt_table_attr, FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
unsigned int record = 1;
! const char *const *ptr;

fprintf(fout, "<table border=\"%d\"", opt_border);
if (opt_table_attr)
***************
*** 758,768 ****
fputs("</th>\n", fout);

fprintf(fout, " <td align=\"%s\">", opt_align[i % col_count] == 'r' ? "right" : "left");
! if ((*ptr)[strspn(*ptr, " \t")] == '\0') /* is string only
! * whitespace? */
fputs("&nbsp; ", fout);
else
html_escaped_print(*ptr, fout);
fputs("</td>\n </tr>\n", fout);
}

--- 940,966 ----
fputs("</th>\n", fout);

fprintf(fout, " <td align=\"%s\">", opt_align[i % col_count] == 'r' ? "right" : "left");
! /* 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 = malloc(len_with_numericsep(*ptr));
+
+ if (!my_cell)
+ {
+ fprintf(stderr, _("out of memory\n"));
+ exit(EXIT_FAILURE);
+ }
+ strcpy(my_cell, *ptr);
+ format_numericsep(my_cell, opt_numericsep);
+ html_escaped_print(my_cell, fout);
+ free(my_cell);
+ }
else
html_escaped_print(*ptr, fout);
+
fputs("</td>\n </tr>\n", fout);
}

***************
*** 829,842 ****


static void
! print_latex_text(const char *title, const char *const * headers,
! const char *const * cells, const char *const * footers,
! const char *opt_align, bool opt_barebones, unsigned short int opt_border,
! FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const * ptr;


/* print title */
--- 1027,1040 ----


static void
! print_latex_text(const char *title, const char *const *headers,
! const char *const *cells, const char *const *footers,
! const char *opt_align, bool opt_barebones,
! unsigned short int opt_border, FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const *ptr;


/* print title */
***************
*** 921,934 ****


static void
! print_latex_vertical(const char *title, const char *const * headers,
! const char *const * cells, const char *const * footers,
! const char *opt_align, bool opt_barebones, unsigned short int opt_border,
! FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const * ptr;
unsigned int record = 1;

(void) opt_align; /* currently unused parameter */
--- 1119,1132 ----


static void
! print_latex_vertical(const char *title, const char *const *headers,
! const char *const *cells, const char *const *footers,
! const char *opt_align, bool opt_barebones,
! unsigned short int opt_border, FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const *ptr;
unsigned int record = 1;

(void) opt_align; /* currently unused parameter */
***************
*** 1027,1040 ****


static void
! 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_barebones, unsigned short int opt_border,
! FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const * ptr;


/* print title */
--- 1225,1238 ----


static void
! 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_barebones,
! unsigned short int opt_border, FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const *ptr;


/* print title */
***************
*** 1111,1124 ****


static void
! 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_barebones, unsigned short int opt_border,
! FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const * ptr;
unsigned int record = 1;
unsigned short current_format = 0; /* 0=none, 1=header, 2=body */

--- 1309,1322 ----


static void
! 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_barebones,
! unsigned short int opt_border, FILE *fout)
{
unsigned int col_count = 0;
unsigned int i;
! const char *const *ptr;
unsigned int record = 1;
unsigned short current_format = 0; /* 0=none, 1=header, 2=body */

***************
*** 1263,1271 ****

void
printTable(const char *title,
! const char *const * headers,
! const char *const * cells,
! const char *const * footers,
const char *align,
const printTableOpt *opt, FILE *fout, FILE *flog)
{
--- 1461,1469 ----

void
printTable(const char *title,
! const char *const *headers,
! const char *const *cells,
! const char *const *footers,
const char *align,
const printTableOpt *opt, FILE *fout, FILE *flog)
{
***************
*** 1298,1304 ****
int col_count = 0,
row_count = 0,
lines;
! const char *const * ptr;

/* rough estimate of columns and rows */
if (headers)
--- 1496,1502 ----
int col_count = 0,
row_count = 0,
lines;
! const char *const *ptr;

/* rough estimate of columns and rows */
if (headers)
***************
*** 1325,1362 ****
/* print the stuff */

if (flog)
! print_aligned_text(title, headers, cells, footers, align, opt->tuples_only, border, opt->encoding, flog);

switch (opt->format)
{
case PRINT_UNALIGNED:
if (use_expanded)
! print_unaligned_vertical(title, headers, cells, footers,
opt->fieldSep, opt->recordSep,
! opt->tuples_only, output);
else
! print_unaligned_text(title, headers, cells, footers,
opt->fieldSep, opt->recordSep,
! opt->tuples_only, output);
break;
case PRINT_ALIGNED:
if (use_expanded)
! print_aligned_vertical(title, headers, cells, footers,
! opt->tuples_only, border,
opt->encoding, output);
else
! print_aligned_text(title, headers, cells, footers,
! align, opt->tuples_only,
border, opt->encoding, output);
break;
case PRINT_HTML:
if (use_expanded)
! print_html_vertical(title, headers, cells, footers,
! align, opt->tuples_only,
border, opt->tableAttr, output);
else
print_html_text(title, headers, cells, footers,
! align, opt->tuples_only, border,
opt->tableAttr, output);
break;
case PRINT_LATEX:
--- 1523,1560 ----
/* print the stuff */

if (flog)
! print_aligned_text(title, headers, cells, footers, align, opt->tuples_only, opt->numericSep, border, opt->encoding, flog);

switch (opt->format)
{
case PRINT_UNALIGNED:
if (use_expanded)
! print_unaligned_vertical(title, headers, cells, footers, align,
opt->fieldSep, opt->recordSep,
! opt->tuples_only, opt->numericSep, output);
else
! print_unaligned_text(title, headers, cells, footers, align,
opt->fieldSep, opt->recordSep,
! opt->tuples_only, opt->numericSep, output);
break;
case PRINT_ALIGNED:
if (use_expanded)
! print_aligned_vertical(title, headers, cells, footers, align,
! opt->tuples_only, opt->numericSep, border,
opt->encoding, output);
else
! print_aligned_text(title, headers, cells, footers, align,
! opt->tuples_only, opt->numericSep,
border, opt->encoding, output);
break;
case PRINT_HTML:
if (use_expanded)
! print_html_vertical(title, headers, cells, footers, align,
! opt->tuples_only, opt->numericSep,
border, opt->tableAttr, output);
else
print_html_text(title, headers, cells, footers,
! align, opt->tuples_only, opt->numericSep, border,
opt->tableAttr, output);
break;
case PRINT_LATEX:
Index: src/bin/psql/print.h
================================================== =================
RCS file: /cvsroot/pgsql/src/bin/psql/print.h,v
retrieving revision 1.25
diff -c -c -r1.25 print.h
*** src/bin/psql/print.h 14 Jun 2005 02:57:41 -0000 1.25
--- src/bin/psql/print.h 10 Jul 2005 03:24:24 -0000
***************
*** 40,45 ****
--- 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


---------------------------(end of broadcast)---------------------------
TIP 1: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to majordomo@postgresql.org so that your
message can get through to the mailing list cleanly

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #9 (permalink)  
Old 04-17-2008, 11:40 PM
Peter Eisentraut
 
Posts: n/a
Default Re: thousands comma numeric formatting in psql

Bruce Momjian wrote:
> I have heavily modified your patch and have applied it. Instead of
> using langinfo, I used a \pset variable numericsep.


Why?

--
Peter Eisentraut
http://developer.postgresql.org/~petere/

---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #10 (permalink)  
Old 04-17-2008, 11:40 PM
Bruce Momjian
 
Posts: n/a
Default Re: thousands comma numeric formatting in psql

Peter Eisentraut wrote:
> Bruce Momjian wrote:
> > I have heavily modified your patch and have applied it. Instead of
> > using langinfo, I used a \pset variable numericsep.

>
> Why?


Because I don't have langinfo on my system, so I can't test it, nor add
configure code for it. It also prevents us from using space as the
separator, which is the international standard.

If you think we should use langinfo, we can discuss it, but at this
point, it is not used.

--
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

---------------------------(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

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Forum Jump


All times are GMT. The time now is 04:25 AM.


Powered by vBulletin® Version 3.6.5
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.2.0
www.UnixAdminTalk.com