Talk About Network

Google


Register and Login
Nick
Password
Register create new account Sign up is FREE and you can post replies, new topics, bookmark posts and more!
Recover lost password


Data Bases > Pgsql Patches > Re: [HACKERS] P...
Latest [ Topics | Posts ] Archive Post A New Topic Post a Reply
<< Topic < Post Post 1 of 7 Topic 3637 of 3917
Post > Topic >>

Re: [HACKERS] Proposed patch - psql wraps at window width

by bruce@[EMAIL PROTECTED] (Bruce Momjian) Apr 28, 2008 at 10:11 PM

--ELM1209435076-22521-0_
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="US-ASCII"


I have updated the do***entation for this patch.  I consider it ready to
apply.  I think it is as close to a middle ground as we are going to
get.  Further adjustment will have to happen when we have more re****ts
from the field.

---------------------------------------------------------------------------

Bruce Momjian wrote:
> I have moved this discussion to hackers in hopes of getting more
> feedback, and moved the patch to a static URL:
> 
> 	ftp://momjian.us/pub/postgresql/mypatches/wrap
> 
> This patch adds a new '\pset format wrapped' mode that wraps long values
> to fit the table on the user's screen, or in '\pset columns' columns in
> an output to file or pipe.  The do***entation additions are at the top
> of the patch.
> 
> Sample:
> 
> 	\pset format wrapped
> 	Output format is wrapped.
> 
> 	\pset columns 70
> 	Target column width for "wrap" format is 70.
> 
> 	SELECT 1, 2, repeat('a', 80), repeat('b', 80), E'a\nb\nc', 1
> 	FROM generate_series(1,2)\g
> 	
> 	 ?column? | ?column? |   repeat   |   repeat    | ?column? | ?column? 
> 	----------+----------+------------+-------------+----------+----------
> 	        1 |        2 | aaaaaaaaaa | bbbbbbbbbbb | a        |        1
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb : b                  
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb : c                  
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb                      
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb                      
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb                      
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb                      
> 	                     ; aaaaaaaaaa ; bbb                              
> 	        1 |        2 | aaaaaaaaaa | bbbbbbbbbbb | a        |        1
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb : b                  
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb : c                  
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb                      
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb                      
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb                      
> 	                     ; aaaaaaaaaa ; bbbbbbbbbbb                      
> 	                     ; aaaaaaaaaa ; bbb                              
> 	(2 rows)
> 
> You will notice:
> 
> 	o  I have pulled up newline values to appear in the same rows
> 	   as the wrapped text
> 	o  Colons are used on the left for newline values
> 	o  Semicolons are used on the left for wrapped values
> 	o  There are no vertical bars for values that don't extend
> 	   to the wrapped or newline rows.  This is how our
> 	   newline display has always worked so it was copied
> 	   by the wrapped code
> 	o  The left column has no indicator of wrapping or newlines
> 	   because there is no left border
> 
> We could use dashes to indicated wrapped values, but we don't.  It would
> be nice if someone could do some multi-byte testing of this,
> particularly for characters that have a display width greater than one.
> 
> I think this patch is ready for application.
> 
> Should 'wrapped' be the default for certain operations, like \df?
> 'wrapped' mode is really good for a table that would fit the screen
> width except for a few wide values.

-- 
  Bruce Momjian  <bruce@[EMAIL PROTECTED]
>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +

--ELM1209435076-22521-0_
Content-Transfer-Encoding: 7bit
Content-Type: text/x-diff
Content-Disposition: inline; filename="/pgpatches/wrap"

Index: doc/src/sgml/ref/psql-ref.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v
retrieving revision 1.199
diff -c -c -r1.199 psql-ref.sgml
*** doc/src/sgml/ref/psql-ref.sgml	30 Mar 2008 18:10:20 -0000	1.199
--- doc/src/sgml/ref/psql-ref.sgml	29 Apr 2008 01:24:44 -0000
***************
*** 1513,1519 ****
            <listitem>
            <para>
            Sets the output format to one of <literal>unaligned</literal>,
!           <literal>aligned</literal>, <literal>html</literal>,
            <literal>latex</literal>, or <literal>troff-ms</literal>.
            Unique abbreviations are allowed.  (That would mean one letter
            is enough.)
--- 1513,1520 ----
            <listitem>
            <para>
            Sets the output format to one of <literal>unaligned</literal>,
!           <literal>aligned</literal>, <literal>wrapped</literal>, 
!           <literal>html</literal>,
            <literal>latex</literal>, or <literal>troff-ms</literal>.
            Unique abbreviations are allowed.  (That would mean one letter
            is enough.)
***************
*** 1525,1531 ****
            is intended to create output that might be intended to be read
            in by other programs (tab-separated, comma-separated).
            <quote>Aligned</quote> mode is the standard, human-readable,
!           nicely formatted text output that is default. The
            <quote><acronym>HTML</acronym></quote> and
            <quote>LaTeX</quote> modes put out tables that are intended to
            be included in do***ents using the respective mark-up
--- 1526,1535 ----
            is intended to create output that might be intended to be read
            in by other programs (tab-separated, comma-separated).
            <quote>Aligned</quote> mode is the standard, human-readable,
!           nicely formatted text output that is default.
!           <quote>Wrapped</quote> is like <literal>aligned</> but wraps
!           to a target width of <literal>\pset columns</> or the
!           width of the screen.  The
            <quote><acronym>HTML</acronym></quote> and
            <quote>LaTeX</quote> modes put out tables that are intended to
            be included in do***ents using the respective mark-up
***************
*** 1537,1542 ****
--- 1541,1557 ----
            </varlistentry>
  
            <varlistentry>
+           <term><literal>columns</literal></term>
+           <listitem>
+           <para>
+           Controls the target width for the <literal>wrapped</> format.
+           Zero (the default) causes the <literal>wrapped</> format to
+           affect only screen output.
+           </para>
+           </listitem>
+           </varlistentry>
+ 
+           <varlistentry>
            <term><literal>border</literal></term>
            <listitem>
            <para>
***************
*** 2707,2712 ****
--- 2722,2739 ----
    <title>Environment</title>
  
    <variablelist>
+ 
+    <varlistentry>
+     <term><envar>COLUMNS</envar></term>
+ 
+     <listitem>
+      <para>
+       Used for the <literal>wrapped</> format when screen width
+       detection fails.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
     <varlistentry>
      <term><envar>PAGER</envar></term>
  
Index: src/bin/psql/command.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/command.c,v
retrieving revision 1.186
diff -c -c -r1.186 command.c
*** src/bin/psql/command.c	1 Jan 2008 19:45:55 -0000	1.186
--- src/bin/psql/command.c	29 Apr 2008 01:24:45 -0000
***************
*** 1526,1531 ****
--- 1526,1534 ----
  		case PRINT_ALIGNED:
  			return "aligned";
  			break;
+ 		case PRINT_WRAPPED:
+ 			return "wrapped";
+ 			break;
  		case PRINT_HTML:
  			return "html";
  			break;
***************
*** 1559,1564 ****
--- 1562,1569 ----
  			popt->topt.format = PRINT_UNALIGNED;
  		else if (pg_strncasecmp("aligned", value, vallen) == 0)
  			popt->topt.format = PRINT_ALIGNED;
+ 		else if (pg_strncasecmp("wrapped", value, vallen) == 0)
+ 			popt->topt.format = PRINT_WRAPPED;
  		else if (pg_strncasecmp("html", value, vallen) == 0)
  			popt->topt.format = PRINT_HTML;
  		else if (pg_strncasecmp("latex", value, vallen) == 0)
***************
*** 1567,1573 ****
  			popt->topt.format = PRINT_TROFF_MS;
  		else
  		{
! 			psql_error("\\pset: allowed formats are unaligned, aligned, html,
latex, troff-ms\n");
  			return false;
  		}
  
--- 1572,1578 ----
  			popt->topt.format = PRINT_TROFF_MS;
  		else
  		{
! 			psql_error("\\pset: allowed formats are unaligned, aligned, wrapped,
html, latex, troff-ms\n");
  			return false;
  		}
  
***************
*** 1748,1753 ****
--- 1753,1768 ----
  		}
  	}
  
+ 	/* set border style/width */
+ 	else if (strcmp(param, "columns") == 0)
+ 	{
+ 		if (value)
+ 			popt->topt.columns = atoi(value);
+ 
+ 		if (!quiet)
+ 			printf(_("Target width for \"wrapped\" format is %d.\n"),
popt->topt.columns);
+ 	}
+ 
  	else
  	{
  		psql_error("\\pset: unknown option: %s\n", param);
Index: src/bin/psql/mbprint.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/mbprint.c,v
retrieving revision 1.30
diff -c -c -r1.30 mbprint.c
*** src/bin/psql/mbprint.c	16 Apr 2008 18:18:00 -0000	1.30
--- src/bin/psql/mbprint.c	29 Apr 2008 01:24:47 -0000
***************
*** 204,211 ****
  /*
   * pg_wcssize takes the given string in the given encoding and returns
three
   * values:
!  *	  result_width: Width in display character of longest line in string
!  *	  result_height: Number of lines in display output
   *	  result_format_size: Number of bytes required to store formatted
representation of string
   */
  int
--- 204,211 ----
  /*
   * pg_wcssize takes the given string in the given encoding and returns
three
   * values:
!  *	  result_width: Width in display characters of the longest line in
string
!  *	  result_height: Number of newlines in display output
   *	  result_format_size: Number of bytes required to store formatted
representation of string
   */
  int
***************
*** 279,287 ****
  	return width;
  }
  
  void
  pg_wcsformat(unsigned char *pwcs, size_t len, int encoding,
! 			 struct lineptr * lines, int count)
  {
  	int			w,
  				chlen = 0;
--- 279,292 ----
  	return width;
  }
  
+ /*
+  *  Filter out unprintable characters, companion to wcs_size.
+  *  Break input into lines based on \n.  lineptr[i].ptr == NULL
+  *	indicates the end of the array.
+  */
  void
  pg_wcsformat(unsigned char *pwcs, size_t len, int encoding,
! 			 struct lineptr *lines, int count)
  {
  	int			w,
  				chlen = 0;
***************
*** 307,312 ****
--- 312,318 ----
  				if (count == 0)
  					exit(1);	/* Screwup */
  
+ 				/* make next line point to remaining memory */
  				lines->ptr = ptr;
  			}
  			else if (*pwcs == '\r')		/* Linefeed */
***************
*** 353,364 ****
  		}
  		len -= chlen;
  	}
- 	*ptr++ = '\0';
  	lines->width = linewidth;
! 	lines++;
! 	count--;
! 	if (count > 0)
! 		lines->ptr = NULL;
  }
  
  unsigned char *
--- 359,371 ----
  		}
  		len -= chlen;
  	}
  	lines->width = linewidth;
! 	*ptr++ = '\0';			/* Terminate formatted string */
! 
! 	if (count == 0)
! 		exit(1);	/* Screwup */
! 
! 	(lines+1)->ptr = NULL;	/* terminate line array */
  }
  
  unsigned char *
Index: src/bin/psql/print.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/print.c,v
retrieving revision 1.97
diff -c -c -r1.97 print.c
*** src/bin/psql/print.c	27 Mar 2008 03:57:34 -0000	1.97
--- src/bin/psql/print.c	29 Apr 2008 01:24:48 -0000
***************
*** 28,33 ****
--- 28,35 ----
  
  #include "mbprint.h"
  
+ static int strlen_max_width(unsigned char *str, int *target_width, int
encoding);
+ 
  /*
   * We define the cancel_pressed flag in this file, rather than common.c
where
   * it naturally belongs, because this file is also used by non-psql
programs
***************
*** 43,48 ****
--- 45,51 ----
  static char *grouping;
  static char *thousands_sep;
  
+ 
  static void *
  pg_local_malloc(size_t size)
  {
***************
*** 396,401 ****
--- 399,407 ----
  }
  
  
+ /*
+  *	Prety pretty boxes around cells.
+  */
  static void
  print_aligned_text(const char *title, const char *const * headers,
  				   const char *const * cells, const char *const * footers,
***************
*** 404,429 ****
  {
  	bool		opt_tuples_only = opt->tuples_only;
  	bool		opt_numeric_locale = opt->numericLocale;
- 	unsigned short int opt_border = opt->border;
  	int			encoding = opt->encoding;
! 	unsigned int col_count = 0;
! 	unsigned int cell_count = 0;
! 	unsigned int i;
! 	int			tmp;
! 	unsigned int *widths,
! 				total_w;
! 	unsigned int *heights;
! 	unsigned int *format_space;
  	unsigned char **format_buf;
  
! 	const char *const * ptr;
  
! 	struct lineptr **col_lineptrs;		/* pointers to line pointer for each
! 										 * column */
! 	struct lineptr *lineptr_list;		/* complete list of linepointers */
  
! 	int		   *complete;		/* Array remembering which columns have
! 								 * completed output */
  
  	if (cancel_pressed)
  		return;
--- 410,441 ----
  {
  	bool		opt_tuples_only = opt->tuples_only;
  	bool		opt_numeric_locale = opt->numericLocale;
  	int			encoding = opt->encoding;
! 	unsigned short int opt_border = opt->border;
! 
! 	unsigned int col_count = 0, cell_count = 0;
! 
! 	unsigned int i,
! 				j;
! 
! 	unsigned int *width_header,
! 			   *max_width,
! 			   *width_wrap,
! 			   *width_average;
! 	unsigned int *max_nl_lines,	/* value split by newlines */
! 				*curr_nl_line,
! 				*max_bytes;
  	unsigned char **format_buf;
+ 	unsigned int width_total;
+ 	unsigned int total_header_width;
  
! 	const char * const *ptr;
  
! 	struct lineptr **col_lineptrs;		/* pointers to line pointer per column
*/
  
! 	bool	   *header_done;	/* Have all header lines been output? */
! 	int		   *bytes_output;	/* Bytes output for column value */
! 	int			output_columns = 0;	/* Width of interactive console */
  
  	if (cancel_pressed)
  		return;
***************
*** 437,711 ****
  
  	if (col_count > 0)
  	{
! 		widths = pg_local_calloc(col_count, sizeof(*widths));
! 		heights = pg_local_calloc(col_count, sizeof(*heights));
  		col_lineptrs = pg_local_calloc(col_count, sizeof(*col_lineptrs));
! 		format_space = pg_local_calloc(col_count, sizeof(*format_space));
  		format_buf = pg_local_calloc(col_count, sizeof(*format_buf));
! 		complete = pg_local_calloc(col_count, sizeof(*complete));
  	}
  	else
  	{
! 		widths = NULL;
! 		heights = NULL;
  		col_lineptrs = NULL;
! 		format_space = NULL;
  		format_buf = NULL;
! 		complete = NULL;
  	}
  
! 	/* count cells (rows * cols) */
! 	for (ptr = cells; *ptr; ptr++)
! 		cell_count++;
! 
! 	/* calc column widths */
  	for (i = 0; i < col_count; i++)
  	{
! 		/* Get width & height */
! 		int			height,
! 					space;
! 
! 		pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding,
&tmp, &height, &space);
! 		if (tmp > widths[i])
! 			widths[i] = tmp;
! 		if (height > heights[i])
! 			heights[i] = height;
! 		if (space > format_space[i])
! 			format_space[i] = space;
  	}
  
! 	for (i = 0, ptr = cells; *ptr; ptr++, i++)
  	{
! 		int			numeric_locale_len;
! 		int			height,
! 					space;
  
! 		if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
! 			numeric_locale_len = additional_numeric_locale_len(*ptr);
! 		else
! 			numeric_locale_len = 0;
  
! 		/* Get width, ignore height */
! 		pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &tmp,
&height, &space);
! 		tmp += numeric_locale_len;
! 		if (tmp > widths[i % col_count])
! 			widths[i % col_count] = tmp;
! 		if (height > heights[i % col_count])
! 			heights[i % col_count] = height;
! 		if (space > format_space[i % col_count])
! 			format_space[i % col_count] = space;
  	}
  
  	if (opt_border == 0)
! 		total_w = col_count - 1;
  	else if (opt_border == 1)
! 		total_w = col_count * 3 - 1;
  	else
! 		total_w = col_count * 3 + 1;
  
  	for (i = 0; i < col_count; i++)
! 		total_w += widths[i];
  
  	/*
! 	 * At this point: widths contains the max width of each column heights
! 	 * contains the max height of a cell of each column format_space
contains
! 	 * maximum space required to store formatted string so we prepare the
! 	 * formatting structures
  	 */
! 	if (col_count > 0)
  	{
! 		int			heights_total = 0;
! 		struct lineptr *lineptr;
  
! 		for (i = 0; i < col_count; i++)
! 			heights_total += heights[i];
  
! 		lineptr = lineptr_list = pg_local_calloc(heights_total,
sizeof(*lineptr_list));
  
! 		for (i = 0; i < col_count; i++)
  		{
! 			col_lineptrs[i] = lineptr;
! 			lineptr += heights[i];
  
! 			format_buf[i] = pg_local_malloc(format_space[i]);
  
! 			col_lineptrs[i]->ptr = format_buf[i];
  		}
  	}
- 	else
- 		lineptr_list = NULL;
  
  	if (opt->start_table)
  	{
  		/* print title */
  		if (title && !opt_tuples_only)
  		{
! 			/* Get width & height */
! 			int			height;
  
! 			pg_wcssize((unsigned char *) title, strlen(title), encoding, &tmp,
&height, NULL);
! 			if (tmp >= total_w)
! 				fprintf(fout, "%s\n", title);
  			else
! 				fprintf(fout, "%-*s%s\n", (total_w - tmp) / 2, "", title);
  		}
  
  		/* print headers */
  		if (!opt_tuples_only)
  		{
! 			int			cols_todo;
! 			int			line_count;
  
  			if (opt_border == 2)
! 				_print_horizontal_line(col_count, widths, opt_border, fout);
  
  			for (i = 0; i < col_count; i++)
! 				pg_wcsformat((unsigned char *) headers[i], strlen(headers[i]),
encoding, col_lineptrs[i], heights[i]);
  
! 			cols_todo = col_count;
! 			line_count = 0;
! 			memset(complete, 0, col_count * sizeof(int));
! 			while (cols_todo)
  			{
  				if (opt_border == 2)
! 					fprintf(fout, "|%c", line_count ? '+' : ' ');
  				else if (opt_border == 1)
! 					fputc(line_count ? '+' : ' ', fout);
  
  				for (i = 0; i < col_count; i++)
  				{
  					unsigned int nbspace;
  
! 					struct lineptr *this_line = col_lineptrs[i] + line_count;
  
! 					if (!complete[i])
  					{
! 						nbspace = widths[i] - this_line->width;
  
  						/* centered */
  						fprintf(fout, "%-*s%s%-*s",
  								nbspace / 2, "", this_line->ptr, (nbspace + 1) / 2, "");
  
! 						if (line_count == (heights[i] - 1) || !(this_line + 1)->ptr)
  						{
! 							cols_todo--;
! 							complete[i] = 1;
  						}
  					}
  					else
! 						fprintf(fout, "%*s", widths[i], "");
  					if (i < col_count - 1)
  					{
  						if (opt_border == 0)
! 							fputc(line_count ? '+' : ' ', fout);
  						else
! 							fprintf(fout, " |%c", line_count ? '+' : ' ');
  					}
  				}
! 				line_count++;
  
  				if (opt_border == 2)
  					fputs(" |", fout);
  				else if (opt_border == 1)
! 					fputc(' ', fout);;
  				fputc('\n', fout);
  			}
  
! 			_print_horizontal_line(col_count, widths, opt_border, fout);
  		}
  	}
  
! 	/* print cells */
  	for (i = 0, ptr = cells; *ptr; i += col_count, ptr += col_count)
  	{
! 		int			j;
! 		int			cols_todo = col_count;
! 		int			line_count; /* Number of lines output so far in row */
  
  		if (cancel_pressed)
  			break;
  
  		for (j = 0; j < col_count; j++)
! 			pg_wcsformat((unsigned char *) ptr[j], strlen(ptr[j]), encoding,
col_lineptrs[j], heights[j]);
  
! 		line_count = 0;
! 		memset(complete, 0, col_count * sizeof(int));
! 		while (cols_todo)
  		{
! 			/* beginning of line */
  			if (opt_border == 2)
  				fputs("| ", fout);
  			else if (opt_border == 1)
  				fputc(' ', fout);
  
  			for (j = 0; j < col_count; j++)
  			{
! 				struct lineptr *this_line = col_lineptrs[j] + line_count;
! 				bool		finalspaces = (opt_border == 2 || j != col_count - 1);
! 
! 				if (complete[j])	/* Just print spaces... */
! 				{
! 					if (finalspaces)
! 						fprintf(fout, "%*s", widths[j], "");
! 				}
  				else
  				{
! 					/* content */
! 					if (opt_align[j] == 'r')
  					{
! 						if (opt_numeric_locale)
! 						{
! 							/*
! 							 * Assumption: This code used only on strings
! 							 * without multibyte characters, otherwise
! 							 * this_line->width < strlen(this_ptr) and we get
! 							 * an overflow
! 							 */
! 							char	   *my_cell = format_numeric_locale((char *)
this_line->ptr);
! 
! 							fprintf(fout, "%*s%s",
! 									(int) (widths[i % col_count] - strlen(my_cell)), "",
! 									my_cell);
! 							free(my_cell);
! 						}
! 						else
! 							fprintf(fout, "%*s%s",
! 									widths[j] - this_line->width, "",
! 									this_line->ptr);
  					}
  					else
- 						fprintf(fout, "%-s%*s", this_line->ptr,
- 						finalspaces ? (widths[j] - this_line->width) : 0, "");
- 					/* If at the right height, done this col */
- 					if (line_count == heights[j] - 1 || !this_line[1].ptr)
  					{
! 						complete[j] = 1;
! 						cols_todo--;
  					}
  				}
  
! 				/* divider */
  				if ((j + 1) % col_count)
  				{
  					if (opt_border == 0)
  						fputc(' ', fout);
! 					else if (line_count == 0)
! 						fputs(" | ", fout);
  					else
! 						fprintf(fout, " %c ", complete[j + 1] ? ' ' : ':');
  				}
  			}
  			if (opt_border == 2)
  				fputs(" |", fout);
  			fputc('\n', fout);
! 			line_count++;
! 		}
  	}
  
  	if (opt->stop_table)
  	{
  		if (opt_border == 2 && !cancel_pressed)
! 			_print_horizontal_line(col_count, widths, opt_border, fout);
  
  		/* print footers */
  		if (footers && !opt_tuples_only && !cancel_pressed)
--- 449,856 ----
  
  	if (col_count > 0)
  	{
! 		width_header = pg_local_calloc(col_count, sizeof(*width_header));
! 		width_average = pg_local_calloc(col_count, sizeof(*width_average));
! 		max_width = pg_local_calloc(col_count, sizeof(*max_width));
! 		width_wrap = pg_local_calloc(col_count, sizeof(*width_wrap));
! 		max_nl_lines = pg_local_calloc(col_count, sizeof(*max_nl_lines));
! 		curr_nl_line = pg_local_calloc(col_count, sizeof(*curr_nl_line));
  		col_lineptrs = pg_local_calloc(col_count, sizeof(*col_lineptrs));
! 		max_bytes = pg_local_calloc(col_count, sizeof(*max_bytes));
  		format_buf = pg_local_calloc(col_count, sizeof(*format_buf));
! 		header_done = pg_local_calloc(col_count, sizeof(*header_done));
! 		bytes_output = pg_local_calloc(col_count, sizeof(*bytes_output));
  	}
  	else
  	{
! 		width_header = NULL;
! 		width_average = NULL;
! 		max_width = NULL;
! 		width_wrap = NULL;
! 		max_nl_lines = NULL;
! 		curr_nl_line = NULL;
  		col_lineptrs = NULL;
! 		max_bytes = NULL;
  		format_buf = NULL;
! 		header_done = NULL;
! 		bytes_output = NULL;
  	}
  
! 	/* scan all column headers, find maximum width and max max_nl_lines */
  	for (i = 0; i < col_count; i++)
  	{
! 		int			width,
! 					nl_lines,
! 					bytes_required;
! 
! 		pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding,
&width, &nl_lines, &bytes_required);
! 		if (width > max_width[i])
! 			max_width[i] = width;
! 		if (nl_lines > max_nl_lines[i])
! 			max_nl_lines[i] = nl_lines;
! 		if (bytes_required > max_bytes[i])
! 			max_bytes[i] = bytes_required;
! 
! 		width_header[i] = width;
  	}
  
! 	/* scan all cells, find maximum width, compute cell_count */
! 	for (i = 0, ptr = cells; *ptr; ptr++, i++, cell_count++)
  	{
! 		int			width,
! 					nl_lines,
! 					bytes_required;
  
! 		/* Get width, ignore nl_lines */
! 		pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &width,
&nl_lines, &bytes_required);
! 		if (opt_numeric_locale && opt_align[i % col_count] == 'r')
! 		{
! 			width += additional_numeric_locale_len(*ptr);
! 			bytes_required += additional_numeric_locale_len(*ptr);
! 		}
! 
! 		if (width > max_width[i % col_count])
! 			max_width[i % col_count] = width;
! 		if (nl_lines > max_nl_lines[i % col_count])
! 			max_nl_lines[i % col_count] = nl_lines;
! 		if (bytes_required > max_bytes[i % col_count])
! 			max_bytes[i % col_count] = bytes_required;
  
! 		width_average[i % col_count] += width;
  	}
  
+ 	/* If we have rows, compute average */
+ 	if (col_count != 0 && cell_count != 0)
+ 	{
+ 		int rows = cell_count / col_count;
+ 		
+ 		for (i = 0; i < col_count; i++)
+ 			width_average[i % col_count] /= rows;
+ 	}
+ 
+ 	/* adjust the total display width based on border style */
  	if (opt_border == 0)
! 		width_total = col_count - 1;
  	else if (opt_border == 1)
! 		width_total = col_count * 3 - 1;
  	else
! 		width_total = col_count * 3 + 1;
! 	total_header_width = width_total;
  
  	for (i = 0; i < col_count; i++)
! 	{
! 		width_total += max_width[i];
! 		total_header_width += width_header[i];
! 	}
  
  	/*
! 	 * At this point: max_width[] contains the max width of each column,
! 	 * max_nl_lines[] contains the max number of lines in each column,
! 	 * max_bytes[] contains the maximum storage space for formatting
! 	 * strings, width_total contains the giant width sum.  Now we allocate
! 	 * some memory for line pointers.
  	 */
! 	for (i = 0; i < col_count; i++)
  	{
! 		/* Add entry for ptr == NULL array termination */
! 		col_lineptrs[i] = pg_local_calloc(max_nl_lines[i] + 1,
! 											sizeof(**col_lineptrs));
  
! 		format_buf[i] = pg_local_malloc(max_bytes[i] + 1);
  
! 		col_lineptrs[i]->ptr = format_buf[i];
! 	}
  
! 	/* Default word wrap to the full width, i.e. no word wrap */
! 	for (i = 0; i < col_count; i++)
! 		width_wrap[i] = max_width[i];
! 
! 	/*
! 	 * Optional optimized word wrap. Shrink columns with a high max/avg
ratio.
! 	 * Slighly bias against wider columns. (Increases chance a narrow
column
! 	 * will fit in its cell.)
! 	 */
! 	if (opt->format == PRINT_WRAPPED)
! 	{
! 		/* Get terminal width */
! 		if (opt->columns > 0)
! 			output_columns = opt->columns;
! 		else if (fout == stdout && isatty(fileno(stdout)))
! 		{
! #ifdef TIOCGWINSZ
! 			struct winsize screen_size;
! 
! 			if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1)
! 				output_columns = screen_size.ws_col;
! 			else
! #endif
! 			{
! 				const char *columns_env = getenv("COLUMNS");
! 
! 				if (columns_env)
! 					output_columns = atoi(columns_env);
! 			}
! 		}
! 
! 		/*
! 		 * If available columns is positive...
! 		 * and greater than the width of the unshrinkable column headers
! 		 */
! 		if (output_columns > 0 && output_columns >= total_header_width)
  		{
! 			/* While there is still excess width... */
! 			while (width_total > output_columns)
! 			{
! 				double		max_ratio = 0;
! 				int			worst_col = -1;
  
! 				/*
! 				 *	Find column that has the highest ratio of its maximum
! 				 *	width compared to its average width.  This tells us which
! 				 *	column will produce the fewest wrapped values if shortened.
! 				 *	width_wrap starts as equal to max_width.
! 				 */
! 				for (i = 0; i < col_count; i++)
! 				{
! 					if (width_average[i] && width_wrap[i] > width_header[i])
! 					{
! 						/* Penalize wide columns by +1% of their width (0.01) */
! 						double ratio = (double)width_wrap[i] / width_average[i] +
! 									max_width[i] * 0.01;
! 
! 						if (ratio > max_ratio)
! 						{
! 							max_ratio = ratio;
! 							worst_col = i;
! 						}
! 					}
! 				}
  
! 				/* Exit loop if we can't squeeze any more. */
! 				if (worst_col == -1)
! 					break;
! 
! 				/* Decrease width of target column by one. */
! 				width_wrap[worst_col]--;
! 				width_total--;
! 			}
  		}
  	}
  
+ 	/* time to output */
  	if (opt->start_table)
  	{
  		/* print title */
  		if (title && !opt_tuples_only)
  		{
! 			int			width, height;
  
! 			pg_wcssize((unsigned char *) title, strlen(title), encoding, &width,
&height, NULL);
! 			if (width >= width_total)
! 				fprintf(fout, "%s\n", title);	/* Aligned */
  			else
! 				fprintf(fout, "%-*s%s\n", (width_total - width) / 2, "", title);		/*
Centered */
  		}
  
  		/* print headers */
  		if (!opt_tuples_only)
  		{
! 			int			more_col_wrapping;
! 			int			curr_nl_line;
  
  			if (opt_border == 2)
! 				_print_horizontal_line(col_count, width_wrap, opt_border, fout);
  
  			for (i = 0; i < col_count; i++)
! 				pg_wcsformat((unsigned char *) headers[i], strlen(headers[i]),
! 							 encoding, col_lineptrs[i], max_nl_lines[i]);
  
! 			more_col_wrapping = col_count;
! 			curr_nl_line = 0;
! 			memset(header_done, false, col_count * sizeof(bool));
! 			while (more_col_wrapping)
  			{
  				if (opt_border == 2)
! 					fprintf(fout, "|%c", curr_nl_line ? '+' : ' ');
  				else if (opt_border == 1)
! 					fputc(curr_nl_line ? '+' : ' ', fout);
  
  				for (i = 0; i < col_count; i++)
  				{
  					unsigned int nbspace;
  
! 					struct lineptr *this_line = col_lineptrs[i] + curr_nl_line;
  
! 					if (!header_done[i])
  					{
! 						nbspace = width_wrap[i] - this_line->width;
  
  						/* centered */
  						fprintf(fout, "%-*s%s%-*s",
  								nbspace / 2, "", this_line->ptr, (nbspace + 1) / 2, "");
  
! 						if (!(this_line + 1)->ptr)
  						{
! 							more_col_wrapping--;
! 							header_done[i] = 1;
  						}
  					}
  					else
! 						fprintf(fout, "%*s", width_wrap[i], "");
  					if (i < col_count - 1)
  					{
  						if (opt_border == 0)
! 							fputc(curr_nl_line ? '+' : ' ', fout);
  						else
! 							fprintf(fout, " |%c", curr_nl_line ? '+' : ' ');
  					}
  				}
! 				curr_nl_line++;
  
  				if (opt_border == 2)
  					fputs(" |", fout);
  				else if (opt_border == 1)
! 					fputc(' ', fout);
  				fputc('\n', fout);
  			}
  
! 			_print_horizontal_line(col_count, width_wrap, opt_border, fout);
  		}
  	}
  
! 	/* print cells, one loop per row */
  	for (i = 0, ptr = cells; *ptr; i += col_count, ptr += col_count)
  	{
! 		bool		more_lines;
  
  		if (cancel_pressed)
  			break;
  
+ 		/*
+ 		 * Format each cell.  Format again, it is a numeric formatting locale
+ 		 * (e.g. 123,456 vs. 123456)
+ 		 */
  		for (j = 0; j < col_count; j++)
! 		{
! 			pg_wcsformat((unsigned char *) ptr[j], strlen(ptr[j]), encoding,
col_lineptrs[j], max_nl_lines[j]);
! 			curr_nl_line[j] = 0;
  
! 			if (opt_numeric_locale && opt_align[j % col_count] == 'r')
! 			{
! 				char	   *my_cell;
! 
! 				my_cell = format_numeric_locale((char *) col_lineptrs[j]->ptr);
! 				strcpy((char *) col_lineptrs[j]->ptr, my_cell); /* Buffer IS large
! 																 * enough... now */
! 				free(my_cell);
! 			}
! 		}
! 
! 		memset(bytes_output, 0, col_count * sizeof(int));
! 
! 		/*
! 		 *	Each time through this loop, one display line is output.
! 		 *	It can either be a full value or a partial value if embedded
! 		 *	newlines exist or if 'format=wrapping' mode is enabled.
! 		 */
! 		do
  		{
! 			more_lines = false;
! 
! 			/* left border */
  			if (opt_border == 2)
  				fputs("| ", fout);
  			else if (opt_border == 1)
  				fputc(' ', fout);
  
+ 			/* for each column */
  			for (j = 0; j < col_count; j++)
  			{
! 				/* We have a valid array element, so index it */
! 				struct lineptr *this_line = &col_lineptrs[j][curr_nl_line[j]];
! 				int		bytes_to_output,  chars_to_output = width_wrap[j];
! 
! 				/* Past newline lines so pad for other columns */
! 				if (!this_line->ptr)
! 					fprintf(fout, "%*s", width_wrap[j], "");
  				else
  				{
! 					/* Get strlen() of the width_wrap character */
! 					bytes_to_output = strlen_max_width(this_line->ptr +
! 									bytes_output[j], &chars_to_output, encoding);
! 
! 					/*
! 					 *	If we exceeded width_wrap, it means the display width
! 					 *	of a single character was wider than our target width.
! 					 *	In that case, we have to pretend we are only printing
! 					 *	the target display width and make the best of it.
! 					 */
! 					if (chars_to_output > width_wrap[j])
! 						chars_to_output = width_wrap[j];
! 
! 					if (opt_align[j] == 'r')		/* Right aligned cell */
  					{
! 						/* spaces first */
! 						fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
! 						fprintf(fout, "%.*s", bytes_to_output,
! 								this_line->ptr + bytes_output[j]);
! 					}
! 					else	/* Left aligned cell */
! 					{
! 						/* spaces second */
! 						fprintf(fout, "%.*s", bytes_to_output,
! 								this_line->ptr + bytes_output[j]);
! 						fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
  					}
+ 
+ 					bytes_output[j] += bytes_to_output;
+ 
+ 					/* Do we have more text to wrap? */
+ 					if (*(this_line->ptr + bytes_output[j]) != 0)
+ 						more_lines = true;
  					else
  					{
! 						/* Advance to next newline line */
! 						curr_nl_line[j]++;
! 						if (col_lineptrs[j][curr_nl_line[j]].ptr != NULL)
! 							more_lines = true;
! 						bytes_output[j] = 0;
  					}
  				}
  
! 				/* print a divider, middle columns only */
  				if ((j + 1) % col_count)
  				{
  					if (opt_border == 0)
  						fputc(' ', fout);
! 					/* Next value is beyond past newlines? */
! 					else if (col_lineptrs[j+1][curr_nl_line[j+1]].ptr == NULL)
! 						fputs("   ", fout);
! 					/* In wrapping of value? */
! 					else if (bytes_output[j+1] != 0)
! 						fputs(" ; ", fout);
! 					/* After first newline value */
! 					else if (curr_nl_line[j+1] != 0)
! 						fputs(" : ", fout);
  					else
! 					/* Ordinary line */
! 						fputs(" | ", fout);
  				}
+ 
  			}
+ 
+ 			/* end of row border */
  			if (opt_border == 2)
  				fputs(" |", fout);
  			fputc('\n', fout);
! 
! 		} while (more_lines);
  	}
  
  	if (opt->stop_table)
  	{
  		if (opt_border == 2 && !cancel_pressed)
! 			_print_horizontal_line(col_count, width_wrap, opt_border, fout);
  
  		/* print footers */
  		if (footers && !opt_tuples_only && !cancel_pressed)
***************
*** 722,733 ****
  	}
  
  	/* clean up */
! 	free(widths);
! 	free(heights);
  	free(col_lineptrs);
! 	free(format_space);
! 	free(complete);
! 	free(lineptr_list);
  	for (i = 0; i < col_count; i++)
  		free(format_buf[i]);
  	free(format_buf);
--- 867,882 ----
  	}
  
  	/* clean up */
! 	free(width_header);
! 	free(width_average);
! 	free(max_width);
! 	free(width_wrap);
! 	free(max_nl_lines);
! 	free(curr_nl_line);
  	free(col_lineptrs);
! 	free(max_bytes);
! 	free(header_done);
! 	free(bytes_output);
  	for (i = 0; i < col_count; i++)
  		free(format_buf[i]);
  	free(format_buf);
***************
*** 754,760 ****
  				dheight = 1,
  				hformatsize = 0,
  				dformatsize = 0;
- 	int			tmp = 0;
  	char	   *divider;
  	unsigned int cell_count = 0;
  	struct lineptr *hlineptr,
--- 903,908 ----
***************
*** 779,790 ****
  	/* Find the maximum dimensions for the headers */
  	for (i = 0; i < col_count; i++)
  	{
! 		int			height,
  					fs;
  
! 		pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding,
&tmp, &height, &fs);
! 		if (tmp > hwidth)
! 			hwidth = tmp;
  		if (height > hheight)
  			hheight = height;
  		if (fs > hformatsize)
--- 927,939 ----
  	/* Find the maximum dimensions for the headers */
  	for (i = 0; i < col_count; i++)
  	{
! 		int			width,
! 					height,
  					fs;
  
! 		pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding,
&width, &height, &fs);
! 		if (width > hwidth)
! 			hwidth = width;
  		if (height > hheight)
  			hheight = height;
  		if (fs > hformatsize)
***************
*** 799,805 ****
  	for (i = 0, ptr = cells; *ptr; ptr++, i++)
  	{
  		int			numeric_locale_len;
! 		int			height,
  					fs;
  
  		if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
--- 948,955 ----
  	for (i = 0, ptr = cells; *ptr; ptr++, i++)
  	{
  		int			numeric_locale_len;
! 		int			width,
! 					height,
  					fs;
  
  		if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
***************
*** 807,816 ****
  		else
  			numeric_locale_len = 0;
  
! 		pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &tmp,
&height, &fs);
! 		tmp += numeric_locale_len;
! 		if (tmp > dwidth)
! 			dwidth = tmp;
  		if (height > dheight)
  			dheight = height;
  		if (fs > dformatsize)
--- 957,966 ----
  		else
  			numeric_locale_len = 0;
  
! 		pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &width,
&height, &fs);
! 		width += numeric_locale_len;
! 		if (width > dwidth)
! 			dwidth = width;
  		if (height > dheight)
  			dheight = height;
  		if (fs > dformatsize)
***************
*** 821,828 ****
  	 * We now have all the information we need to setup the formatting
  	 * structures
  	 */
! 	dlineptr = pg_local_malloc(sizeof(*dlineptr) * dheight);
! 	hlineptr = pg_local_malloc(sizeof(*hlineptr) * hheight);
  
  	dlineptr->ptr = pg_local_malloc(dformatsize);
  	hlineptr->ptr = pg_local_malloc(hformatsize);
--- 971,978 ----
  	 * We now have all the information we need to setup the formatting
  	 * structures
  	 */
! 	dlineptr = pg_local_malloc((sizeof(*dlineptr) + 1) * dheight);
! 	hlineptr = pg_local_malloc((sizeof(*hlineptr) + 1) * hheight);
  
  	dlineptr->ptr = pg_local_malloc(dformatsize);
  	hlineptr->ptr = pg_local_malloc(hformatsize);
***************
*** 910,916 ****
  				fprintf(fout, "%-s%*s", hlineptr[line_count].ptr,
  						hwidth - hlineptr[line_count].width, "");
  
! 				if (line_count == (hheight - 1) || !hlineptr[line_count + 1].ptr)
  					hcomplete = 1;
  			}
  			else
--- 1060,1066 ----
  				fprintf(fout, "%-s%*s", hlineptr[line_count].ptr,
  						hwidth - hlineptr[line_count].width, "");
  
! 				if (!hlineptr[line_count + 1].ptr)
  					hcomplete = 1;
  			}
  			else
***************
*** 943,949 ****
  								dwidth - dlineptr[line_count].width, "");
  				}
  
! 				if (line_count == dheight - 1 || !dlineptr[line_count + 1].ptr)
  					dcomplete = 1;
  			}
  			else
--- 1093,1099 ----
  								dwidth - dlineptr[line_count].width, "");
  				}
  
! 				if (!dlineptr[line_count + 1].ptr)
  					dcomplete = 1;
  			}
  			else
***************
*** 1879,1884 ****
--- 2029,2035 ----
  									 opt, output);
  			break;
  		case PRINT_ALIGNED:
+ 		case PRINT_WRAPPED:
  			if (opt->expanded)
  				print_aligned_vertical(title, headers, cells, footers, align,
  									   opt, output);
***************
*** 2066,2068 ****
--- 2217,2254 ----
  	else
  		thousands_sep = ".";
  }
+ 
+ /*
+  *	Returns the byte length to the end of the specified character
+  *  and number of display characters processed (useful if the string
+  *	is shorter then dpylen).
+  */
+ static int
+ strlen_max_width(unsigned char *str, int *target_width, int encoding)
+ {
+ 	unsigned char *start = str;
+ 	int curr_width = 0;
+ 
+ 	while (*str && curr_width < *target_width)
+ 	{
+ 		int char_width = PQdsplen((char *) str, encoding);
+ 
+ 		/*
+ 		 *	If the display width of the new character causes
+ 		 *	the string to exceed its target width, skip it
+ 		 *	and return.  However, if this is the first character
+ 		 *	of the string (*width == 0), we have to accept it.
+ 		 */
+ 		if (*target_width - curr_width < char_width && curr_width != 0)
+ 			break;
+ 			
+ 		str += PQmblen((char *)str, encoding);
+ 
+ 		curr_width += char_width;
+ 	}
+ 
+ 	*target_width = curr_width;
+ 	
+ 	/* last byte */
+ 	return str - start;
+ }
Index: src/bin/psql/print.h
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/print.h,v
retrieving revision 1.35
diff -c -c -r1.35 print.h
*** src/bin/psql/print.h	1 Jan 2008 19:45:56 -0000	1.35
--- src/bin/psql/print.h	29 Apr 2008 01:24:48 -0000
***************
*** 21,26 ****
--- 21,27 ----
  	PRINT_NOTHING = 0,			/* to make sure someone initializes this */
  	PRINT_UNALIGNED,
  	PRINT_ALIGNED,
+ 	PRINT_WRAPPED,
  	PRINT_HTML,
  	PRINT_LATEX,
  	PRINT_TROFF_MS
***************
*** 47,52 ****
--- 48,54 ----
  								 * decimal marker */
  	char	   *tableAttr;		/* attributes for HTML <table ...> */
  	int			encoding;		/* character encoding */
+ 	int			columns;		/* target width for wrapped format */
  } printTableOpt;
  
  

--ELM1209435076-22521-0_
Content-Type: text/plain
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
MIME-Version: 1.0


-- 
Sent via pgsql-patches mailing list (pgsql-patches@[EMAIL PROTECTED]
)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-patches

--ELM1209435076-22521-0_--
 




 7 Posts in Topic:
Re: [HACKERS] Proposed patch - psql wraps at window width
bruce@[EMAIL PROTECTED]   2008-04-28 22:11:16 
Re: [HACKERS] Proposed patch - psql wraps at window width
bryce2@[EMAIL PROTECTED]   2008-04-28 21:43:59 
Re: [HACKERS] Proposed patch - psql wraps at window width
bruce@[EMAIL PROTECTED]   2008-04-29 08:17:26 
Re: [HACKERS] Proposed patch - psql wraps at window width
alvherre@[EMAIL PROTECTED  2008-04-29 10:06:28 
Re: [HACKERS] Proposed patch - psql wraps at window width
stark@[EMAIL PROTECTED]   2008-04-29 21:17:42 
Re: [HACKERS] Proposed patch - psql wraps at window width
alvherre@[EMAIL PROTECTED  2008-04-30 18:09:05 
Re: [HACKERS] Proposed patch - psql wraps at window width
stark@[EMAIL PROTECTED]   2008-04-30 18:51:27 

Post A Reply:
  Go here to Signup

AddThis Feed Button


About - Advertising - Contact - Frequently Asked Questions - Privacy Policy - Terms of Use - Signup

Contact
tan13V112 Thu Jul 24 7:17:49 CDT 2008.