I have applied the following patch to allow varchar() fields to store
just the needed bytes, and not the maximum size.

I have made a few more cleanup changes related to this, and it seems to
work perfectly.

I think this is one of those "Why didn't we do this earlier?" patches.

	test=> create table testvarchar (x varchar(2));
	CREATE
	test=> insert into testvarchar values ('1');
	INSERT 912201 1
	test=> insert into testvarchar values ('22');
	INSERT 912202 1
	test=> insert into testvarchar values ('333');
	INSERT 912203 1
	test=> select * from testvarchar;
	 x
	--
	 1
	22
	33
	(3 rows)

And if I create a varchar(2000), it does not take several 8k blocks to
store 10 rows, like it did before.

This makes varchar() behave much more like text, with a pre-defined
length limit.

Also, the fact that varchar() no longer has all those trailing zero's
should make it more portable with other types.

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

*** ./backend/utils/adt/varchar.c.orig	Wed Jan  7 12:43:00 1998
--- ./backend/utils/adt/varchar.c	Wed Jan  7 13:26:16 1998
***************
*** 70,85 ****
  		typlen = len + VARHDRSZ;
  	}
  	else
- 	{
  		len = typlen - VARHDRSZ;
- 	}
  
  	if (len > 4096)
  		elog(ERROR, "bpcharin: length of char() must be less than 4096");
  
  	result = (char *) palloc(typlen);
! 	*(int32 *) result = typlen;
! 	r = result + VARHDRSZ;
  	for (i = 0; i < len; i++, r++, s++)
  	{
  		*r = *s;
--- 70,83 ----
  		typlen = len + VARHDRSZ;
  	}
  	else
  		len = typlen - VARHDRSZ;
  
  	if (len > 4096)
  		elog(ERROR, "bpcharin: length of char() must be less than 4096");
  
  	result = (char *) palloc(typlen);
! 	VARSIZE(result) = typlen;
! 	r = VARDATA(result);
  	for (i = 0; i < len; i++, r++, s++)
  	{
  		*r = *s;
***************
*** 108,116 ****
  	}
  	else
  	{
! 		len = *(int32 *) s - VARHDRSZ;
  		result = (char *) palloc(len + 1);
! 		StrNCpy(result, s + VARHDRSZ, len+1);	/* these are blank-padded */
  	}
  	return (result);
  }
--- 106,114 ----
  	}
  	else
  	{
! 		len = VARSIZE(s) - VARHDRSZ;
  		result = (char *) palloc(len + 1);
! 		StrNCpy(result, VARDATA(s), len+1);	/* these are blank-padded */
  	}
  	return (result);
  }
***************
*** 129,155 ****
  varcharin(char *s, int dummy, int typlen)
  {
  	char	   *result;
! 	int			len = typlen - VARHDRSZ;
  
  	if (s == NULL)
  		return ((char *) NULL);
  
! 	if (typlen == -1)
! 	{
! 
! 		/*
! 		 * this is here because some functions can't supply the typlen
! 		 */
! 		len = strlen(s);
! 		typlen = len + VARHDRSZ;
! 	}
  
  	if (len > 4096)
  		elog(ERROR, "varcharin: length of char() must be less than 4096");
  
! 	result = (char *) palloc(typlen);
! 	*(int32 *) result = typlen;
! 	strncpy(result + VARHDRSZ, s, len+1);
  
  	return (result);
  }
--- 127,147 ----
  varcharin(char *s, int dummy, int typlen)
  {
  	char	   *result;
! 	int			len;
  
  	if (s == NULL)
  		return ((char *) NULL);
  
! 	len = strlen(s) + VARHDRSZ;
! 	if (typlen != -1 && len > typlen)
! 		len = typlen;	/* clip the string at max length */
  
  	if (len > 4096)
  		elog(ERROR, "varcharin: length of char() must be less than 4096");
  
! 	result = (char *) palloc(len);
! 	VARSIZE(result) = len;
! 	memmove(VARDATA(result), s, len - VARHDRSZ);
  
  	return (result);
  }
***************
*** 168,176 ****
  	}
  	else
  	{
! 		len = *(int32 *) s - VARHDRSZ;
  		result = (char *) palloc(len + 1);
! 		StrNCpy(result, s + VARHDRSZ, len+1);
  	}
  	return (result);
  }
--- 160,168 ----
  	}
  	else
  	{
! 		len = VARSIZE(s) - VARHDRSZ;
  		result = (char *) palloc(len + 1);
! 		StrNCpy(result, VARDATA(s), len+1);
  	}
  	return (result);
  }

-- 
Bruce Momjian
maillist@candle.pha.pa.us

Wed, 7 Jan 1998 14:41:21 -0500 (EST)
Bruce Momjian <maillist@candle.pha.pa.us>
varchar size