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 ...
| |||||||
| Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
| ||||
| 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 |
| |||
| 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 |
| |||
| 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 |
| |||
| 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 |
| |||
| 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 |
| |||
| 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 |
| |||
| 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 |
| |||
| 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(" ", 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(" ", 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(" ", 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(" ", 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 |
| |||
| 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 |
| ||||
| 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 |