varchar size

Started by Bruce Momjianabout 28 years ago2 messages
#1Bruce Momjian
maillist@candle.pha.pa.us

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

#2Noname
darrenk@insightdist.com
In reply to: Bruce Momjian (#1)
Re: [HACKERS] varchar size

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

...

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

Fixes the following "problem" too...

Currently, you can create a table with attributes that _can_ total more
than the max_tup_size if they maximum size, but not be able to insert
valid data into all of them.

For instance, ...

create table foo (bar varchar(4000),
bah varchar(3000),
baz varchar(2000));

... is fine as long as one of the attributes is null. Now you can have
non-null values for all three as long as they don't go over max_tup_size
in _total_.

darrenk