1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

Make char(n) and varchar(n) types raise an error if the inserted string is

too long.  While I was adjusting the regression tests I moved the array
things all into array.sql, to make things more manageable.
This commit is contained in:
Peter Eisentraut
2001-05-21 16:54:46 +00:00
parent d27f363e3f
commit 5546ec289b
14 changed files with 351 additions and 236 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.77 2001/05/03 19:00:36 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.78 2001/05/21 16:54:46 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -55,9 +55,11 @@
*****************************************************************************/
/*
* bpcharin -
* converts a string of char() type to the internal representation.
* len is the length specified in () plus VARHDRSZ bytes.
* Convert a C string to CHARACTER internal representation. atttypmod
* is the declared length of the type plus VARHDRSZ.
*
* If the C string is too long, raise an error, unless the extra
* characters are spaces, in which case they're truncated. (per SQL)
*/
Datum
bpcharin(PG_FUNCTION_ARGS)
@ -71,30 +73,33 @@ bpcharin(PG_FUNCTION_ARGS)
int32 atttypmod = PG_GETARG_INT32(2);
BpChar *result;
char *r;
int len;
size_t len, maxlen;
int i;
if (atttypmod < (int32) VARHDRSZ)
len = strlen(s);
maxlen = atttypmod - VARHDRSZ;
if (atttypmod >= (int32) VARHDRSZ && len > maxlen)
{
/* If typmod is -1 (or invalid), use the actual string length */
len = strlen(s);
atttypmod = len + VARHDRSZ;
#ifdef MULTIBYTE
size_t mbmaxlen = pg_mbcliplen(s, len, maxlen);
if (strspn(s + mbmaxlen, " ") == len - mbmaxlen)
len = mbmaxlen;
#else
if (strspn(s + maxlen, " ") == len - maxlen)
/* clip extra spaces */
len = maxlen;
#endif
else
elog(ERROR, "value too long for type character(%d)", maxlen);
}
else
#ifdef MULTIBYTE
{
/* If typmod is -1 (or invalid), use the actual string length */
maxlen = len;
/*
* truncate multi-byte string preserving multi-byte boundary
*/
len = pg_mbcliplen(s, atttypmod - VARHDRSZ, atttypmod - VARHDRSZ);
}
#else
len = atttypmod - VARHDRSZ;
#endif
result = (BpChar *) palloc(atttypmod);
VARATT_SIZEP(result) = atttypmod;
result = palloc(maxlen + VARHDRSZ);
VARATT_SIZEP(result) = maxlen + VARHDRSZ;
r = VARDATA(result);
for (i = 0; i < len; i++, r++, s++)
{
@ -108,16 +113,16 @@ bpcharin(PG_FUNCTION_ARGS)
#endif
/* blank pad the string if necessary */
#ifdef MULTIBYTE
for (; i < atttypmod - VARHDRSZ; i++)
#else
for (; i < len; i++)
#endif
for (; i < maxlen; i++)
*r++ = ' ';
PG_RETURN_BPCHAR_P(result);
}
/*
* Convert a CHARACTER value to a C string.
*/
Datum
bpcharout(PG_FUNCTION_ARGS)
{
@ -138,75 +143,70 @@ bpcharout(PG_FUNCTION_ARGS)
PG_RETURN_CSTRING(result);
}
/* bpchar()
* Converts a char() type to a specific internal length.
* len is the length specified in () plus VARHDRSZ bytes.
/*
* Converts a CHARACTER type to the specified size. maxlen is the new
* declared length plus VARHDRSZ bytes. Truncation
* rules see bpcharin() above.
*/
Datum
bpchar(PG_FUNCTION_ARGS)
{
BpChar *str = PG_GETARG_BPCHAR_P(0);
int32 len = PG_GETARG_INT32(1);
BpChar *source = PG_GETARG_BPCHAR_P(0);
int32 maxlen = PG_GETARG_INT32(1);
BpChar *result;
char *r,
*s;
int rlen,
slen;
int32 len;
char *r;
char *s;
int i;
len = VARSIZE(source);
/* No work if typmod is invalid or supplied data matches it already */
if (len < (int32) VARHDRSZ || len == VARSIZE(str))
PG_RETURN_BPCHAR_P(str);
if (len < (int32) VARHDRSZ || len == maxlen)
PG_RETURN_BPCHAR_P(source);
rlen = len - VARHDRSZ;
#ifdef STRINGDEBUG
printf("bpchar- convert string length %d (%d) ->%d (%d)\n",
VARSIZE(str) - VARHDRSZ, VARSIZE(str), rlen, len);
#endif
result = (BpChar *) palloc(len);
VARATT_SIZEP(result) = len;
r = VARDATA(result);
#ifdef MULTIBYTE
/*
* truncate multi-byte string in a way not to break multi-byte
* boundary
*/
if (VARSIZE(str) > len)
slen = pg_mbcliplen(VARDATA(str), VARSIZE(str) - VARHDRSZ, rlen);
else
slen = VARSIZE(str) - VARHDRSZ;
#else
slen = VARSIZE(str) - VARHDRSZ;
#endif
s = VARDATA(str);
#ifdef STRINGDEBUG
printf("bpchar- string is '");
#endif
for (i = 0; (i < rlen) && (i < slen); i++)
if (len > maxlen)
{
#ifdef STRINGDEBUG
printf("%c", *s);
#ifdef MULTIBYTE
size_t maxmblen;
maxmblen = pg_mbcliplen(VARDATA(source), len - VARHDRSZ,
maxlen - VARHDRSZ) + VARHDRSZ;
for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
if (*(VARDATA(source) + i) != ' ')
elog(ERROR, "value too long for type character(%d)",
maxlen - VARHDRSZ);
len = maxmblen;
#else
for (i = maxlen - VARHDRSZ; i < len - VARHDRSZ; i++)
if (*(VARDATA(source) + i) != ' ')
elog(ERROR, "value too long for type character(%d)",
maxlen - VARHDRSZ);
/* clip extra spaces */
len = maxlen;
#endif
*r++ = *s++;
}
#ifdef STRINGDEBUG
printf("'\n");
#endif
s = VARDATA(source);
result = palloc(maxlen);
VARATT_SIZEP(result) = maxlen;
r = VARDATA(result);
for (i = 0; (i < maxlen - VARHDRSZ) && (i < len - VARHDRSZ); i++)
*r++ = *s++;
/* blank pad the string if necessary */
for (; i < rlen; i++)
for (; i < maxlen - VARHDRSZ; i++)
*r++ = ' ';
PG_RETURN_BPCHAR_P(result);
}
/* _bpchar()
* Converts an array of char() elements to a specific internal length.
* len is the length specified in () plus VARHDRSZ bytes.
@ -330,9 +330,11 @@ name_bpchar(PG_FUNCTION_ARGS)
*****************************************************************************/
/*
* varcharin -
* converts a string of varchar() type to the internal representation.
* len is the length specified in () plus VARHDRSZ bytes.
* Convert a C string to VARCHAR internal representation. atttypmod
* is the declared length of the type plus VARHDRSZ.
*
* If the C string is too long, raise an error, unless the extra
* characters are spaces, in which case they're truncated. (per SQL)
*/
Datum
varcharin(PG_FUNCTION_ARGS)
@ -345,37 +347,52 @@ varcharin(PG_FUNCTION_ARGS)
#endif
int32 atttypmod = PG_GETARG_INT32(2);
VarChar *result;
int len;
size_t len, maxlen;
len = strlen(s) + VARHDRSZ;
if (atttypmod >= (int32) VARHDRSZ && len > atttypmod)
len = strlen(s);
maxlen = atttypmod - VARHDRSZ;
if (atttypmod >= (int32) VARHDRSZ && len > maxlen)
{
#ifdef MULTIBYTE
len = pg_mbcliplen(s, len - VARHDRSZ, atttypmod - VARHDRSZ) + VARHDRSZ;
#else
len = atttypmod; /* clip the string at max length */
#endif
size_t mbmaxlen = pg_mbcliplen(s, len, maxlen);
result = (VarChar *) palloc(len);
VARATT_SIZEP(result) = len;
memcpy(VARDATA(result), s, len - VARHDRSZ);
if (strspn(s + mbmaxlen, " ") == len - mbmaxlen)
len = mbmaxlen;
#else
if (strspn(s + maxlen, " ") == len - maxlen)
/* clip extra spaces */
len = maxlen;
#endif
else
elog(ERROR, "value too long for type character varying(%d)", maxlen);
}
result = palloc(len + VARHDRSZ);
VARATT_SIZEP(result) = len + VARHDRSZ;
memcpy(VARDATA(result), s, len);
#ifdef CYR_RECODE
convertstr(VARDATA(result), len - VARHDRSZ, 0);
convertstr(VARDATA(result), len, 0);
#endif
PG_RETURN_VARCHAR_P(result);
}
/*
* Convert a VARCHAR value to a C string.
*/
Datum
varcharout(PG_FUNCTION_ARGS)
{
VarChar *s = PG_GETARG_VARCHAR_P(0);
char *result;
int len;
int32 len;
/* copy and add null term */
len = VARSIZE(s) - VARHDRSZ;
result = (char *) palloc(len + 1);
result = palloc(len + 1);
memcpy(result, VARDATA(s), len);
result[len] = '\0';
@ -386,42 +403,60 @@ varcharout(PG_FUNCTION_ARGS)
PG_RETURN_CSTRING(result);
}
/* varchar()
* Converts a varchar() type to the specified size.
* slen is the length specified in () plus VARHDRSZ bytes.
/*
* Converts a VARCHAR type to the specified size. maxlen is the new
* declared length plus VARHDRSZ bytes. Truncation
* rules see varcharin() above.
*/
Datum
varchar(PG_FUNCTION_ARGS)
{
VarChar *s = PG_GETARG_VARCHAR_P(0);
int32 slen = PG_GETARG_INT32(1);
VarChar *source = PG_GETARG_VARCHAR_P(0);
int32 maxlen = PG_GETARG_INT32(1);
VarChar *result;
int len;
int32 len;
int i;
len = VARSIZE(s);
if (slen < (int32) VARHDRSZ || len <= slen)
PG_RETURN_VARCHAR_P(s);
len = VARSIZE(source);
if (maxlen < (int32) VARHDRSZ || len <= maxlen)
PG_RETURN_VARCHAR_P(source);
/* only reach here if we need to truncate string... */
/* only reach here if string is too long... */
#ifdef MULTIBYTE
{
size_t maxmblen;
/*
* truncate multi-byte string preserving multi-byte boundary
*/
len = pg_mbcliplen(VARDATA(s), slen - VARHDRSZ, slen - VARHDRSZ);
slen = len + VARHDRSZ;
/* truncate multi-byte string preserving multi-byte boundary */
maxmblen = pg_mbcliplen(VARDATA(source), len - VARHDRSZ,
maxlen - VARHDRSZ) + VARHDRSZ;
for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
if (*(VARDATA(source) + i) != ' ')
elog(ERROR, "value too long for type character varying(%d)",
maxlen - VARHDRSZ);
len = maxmblen;
}
#else
len = slen - VARHDRSZ;
for (i = maxlen - VARHDRSZ; i < len - VARHDRSZ; i++)
if (*(VARDATA(source) + i) != ' ')
elog(ERROR, "value too long for type character varying(%d)",
maxlen - VARHDRSZ);
/* clip extra spaces */
len = maxlen;
#endif
result = (VarChar *) palloc(slen);
VARATT_SIZEP(result) = slen;
memcpy(VARDATA(result), VARDATA(s), len);
result = palloc(len);
VARATT_SIZEP(result) = len;
memcpy(VARDATA(result), VARDATA(source), len - VARHDRSZ);
PG_RETURN_VARCHAR_P(result);
}
/* _varchar()
* Converts an array of varchar() elements to the specified size.
* len is the length specified in () plus VARHDRSZ bytes.
@ -452,6 +487,12 @@ _varchar(PG_FUNCTION_ARGS)
return array_map(&locfcinfo, VARCHAROID, VARCHAROID);
}
/*****************************************************************************
* Exported functions
*****************************************************************************/
/* "True" length (not counting trailing blanks) of a BpChar */
static int
bcTruelen(BpChar *arg)

View File

@ -1,6 +1,32 @@
--
-- ARRAYS
--
CREATE TABLE arrtest (
a int2[],
b int4[][][],
c name[],
d text[][],
e float8[],
f char(5)[],
g varchar(5)[]
);
--
-- only this array as a 0-based 'e', the others are 1-based.
-- 'e' is also a large object.
--
INSERT INTO arrtest (a[5], b[2][1][2], c, d, f, g)
VALUES ('{1,2,3,4,5}', '{{{},{1,2}}}', '{}', '{}', '{}', '{}');
UPDATE arrtest SET e[0] = '1.1';
UPDATE arrtest SET e[1] = '2.2';
INSERT INTO arrtest (f)
VALUES ('{"too long"}');
ERROR: value too long for type character(5)
INSERT INTO arrtest (a, b[2][2][1], c, d, e, f, g)
VALUES ('{11,12,23}', '{{3,4},{4,5}}', '{"foobar"}',
'{{"elt1", "elt2"}}', '{"3.4", "6.7"}',
'{"abc","abcde"}', '{"abc","abcde"}');
INSERT INTO arrtest (a, b[1][2][2], c, d[2][1])
VALUES ('{}', '{3,4}', '{foo,bar}', '{bar,foo}');
SELECT * FROM arrtest;
a | b | c | d | e | f | g
-------------+-----------------+---------------+-------------------+---------------+-------------------+-----------------
@ -75,8 +101,8 @@ SELECT a,b,c FROM arrtest;
a | b | c
---------------+-----------------------+-----------------------
{16,25,3,4,5} | {{{113,142},{1,147}}} | {}
{16,25,23} | {{3,4},{4,5}} | {"foobar","new_word"}
{} | {3,4} | {"foo","new_word"}
{16,25,23} | {{3,4},{4,5}} | {"foobar","new_word"}
(3 rows)
SELECT a[1:3],
@ -87,7 +113,7 @@ SELECT a[1:3],
a | b | c | d
------------+-----------------------+-----------------------+------------
{16,25,3} | {{{113,142},{1,147}}} | |
{16,25,23} | | {"foobar","new_word"} | {{"elt2"}}
| | {"foo","new_word"} |
{16,25,23} | | {"foobar","new_word"} | {{"elt2"}}
(3 rows)

View File

@ -1,6 +1,5 @@
--
-- CHAR
-- all inputs are SILENTLY truncated at 1 character
--
-- fixed-length by value
-- internally passed by value if <= 4 bytes in storage
@ -24,6 +23,8 @@ INSERT INTO CHAR_TBL (f1) VALUES ('3');
INSERT INTO CHAR_TBL (f1) VALUES ('');
-- try char's of greater than 1 length
INSERT INTO CHAR_TBL (f1) VALUES ('cd');
ERROR: value too long for type character(1)
INSERT INTO CHAR_TBL (f1) VALUES ('c ');
SELECT '' AS seven, CHAR_TBL.*;
seven | f1
-------+----
@ -108,6 +109,8 @@ INSERT INTO CHAR_TBL (f1) VALUES ('a');
INSERT INTO CHAR_TBL (f1) VALUES ('ab');
INSERT INTO CHAR_TBL (f1) VALUES ('abcd');
INSERT INTO CHAR_TBL (f1) VALUES ('abcde');
ERROR: value too long for type character(4)
INSERT INTO CHAR_TBL (f1) VALUES ('abcd ');
SELECT '' AS four, CHAR_TBL.*;
four | f1
------+------

View File

@ -121,23 +121,6 @@ INSERT INTO f_star (class, f)
VALUES ('f', '(11111111,33333333),(22222222,44444444)'::polygon);
INSERT INTO f_star (class) VALUES ('f');
--
-- ARRAYS
--
--
-- only this array as a 0-based 'e', the others are 1-based.
-- 'e' is also a large object.
--
INSERT INTO arrtest (a[5], b[2][1][2], c, d, f, g)
VALUES ('{1,2,3,4,5}', '{{{},{1,2}}}', '{}', '{}', '{}', '{}');
UPDATE arrtest SET e[0] = '1.1';
UPDATE arrtest SET e[1] = '2.2';
INSERT INTO arrtest (a, b[2][2][1], c, d, e, f, g)
VALUES ('{11,12,23}', '{{3,4},{4,5}}', '{"foobar"}',
'{{"elt1", "elt2"}}', '{"3.4", "6.7"}',
'{"abc","abcdefgh"}', '{"abc","abcdefgh"}');
INSERT INTO arrtest (a, b[1][2][2], c, d[2][1])
VALUES ('{}', '{3,4}', '{foo,bar}', '{bar,foo}');
--
-- for internal portal (cursor) tests
--
CREATE TABLE iportaltest (

View File

@ -147,15 +147,6 @@ CREATE TABLE aggtest (
a int2,
b float4
);
CREATE TABLE arrtest (
a int2[],
b int4[][][],
c name[],
d text[][],
e float8[],
f char(5)[],
g varchar(5)[]
);
CREATE TABLE hash_i4_heap (
seqno int4,
random int4

View File

@ -45,11 +45,13 @@ SELECT CAST(name 'namefield' AS text) AS "text(name)";
namefield
(1 row)
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL;
char(text)
------------
doh!
hi de ho n
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL; -- fail
ERROR: value too long for type character(10)
SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;
char(text)
----------------------
doh!
hi de ho neighbor
(2 rows)
SELECT CAST(f1 AS char(10)) AS "char(varchar)" FROM VARCHAR_TBL;
@ -479,10 +481,10 @@ SELECT text 'text' || ' and unknown' AS "Concat text to unknown type";
text and unknown
(1 row)
SELECT text 'text' || char(10) ' and characters' AS "Concat text to char";
SELECT text 'text' || char(20) ' and characters' AS "Concat text to char";
Concat text to char
---------------------
text and chara
text and characters
(1 row)
SELECT text 'text' || varchar ' and varchar' AS "Concat text to varchar";

View File

@ -12,6 +12,8 @@ INSERT INTO VARCHAR_TBL (f1) VALUES ('3');
INSERT INTO VARCHAR_TBL (f1) VALUES ('');
-- try varchar's of greater than 1 length
INSERT INTO VARCHAR_TBL (f1) VALUES ('cd');
ERROR: value too long for type character varying(1)
INSERT INTO VARCHAR_TBL (f1) VALUES ('c ');
SELECT '' AS seven, VARCHAR_TBL.*;
seven | f1
-------+----
@ -96,6 +98,8 @@ INSERT INTO VARCHAR_TBL (f1) VALUES ('a');
INSERT INTO VARCHAR_TBL (f1) VALUES ('ab');
INSERT INTO VARCHAR_TBL (f1) VALUES ('abcd');
INSERT INTO VARCHAR_TBL (f1) VALUES ('abcde');
ERROR: value too long for type character varying(4)
INSERT INTO VARCHAR_TBL (f1) VALUES ('abcd ');
SELECT '' AS four, VARCHAR_TBL.*;
four | f1
------+------

View File

@ -2,6 +2,40 @@
-- ARRAYS
--
CREATE TABLE arrtest (
a int2[],
b int4[][][],
c name[],
d text[][],
e float8[],
f char(5)[],
g varchar(5)[]
);
--
-- only this array as a 0-based 'e', the others are 1-based.
-- 'e' is also a large object.
--
INSERT INTO arrtest (a[5], b[2][1][2], c, d, f, g)
VALUES ('{1,2,3,4,5}', '{{{},{1,2}}}', '{}', '{}', '{}', '{}');
UPDATE arrtest SET e[0] = '1.1';
UPDATE arrtest SET e[1] = '2.2';
INSERT INTO arrtest (f)
VALUES ('{"too long"}');
INSERT INTO arrtest (a, b[2][2][1], c, d, e, f, g)
VALUES ('{11,12,23}', '{{3,4},{4,5}}', '{"foobar"}',
'{{"elt1", "elt2"}}', '{"3.4", "6.7"}',
'{"abc","abcde"}', '{"abc","abcde"}');
INSERT INTO arrtest (a, b[1][2][2], c, d[2][1])
VALUES ('{}', '{3,4}', '{foo,bar}', '{bar,foo}');
SELECT * FROM arrtest;
SELECT arrtest.a[1],

View File

@ -1,6 +1,5 @@
--
-- CHAR
-- all inputs are SILENTLY truncated at 1 character
--
-- fixed-length by value
@ -30,6 +29,7 @@ INSERT INTO CHAR_TBL (f1) VALUES ('');
-- try char's of greater than 1 length
INSERT INTO CHAR_TBL (f1) VALUES ('cd');
INSERT INTO CHAR_TBL (f1) VALUES ('c ');
SELECT '' AS seven, CHAR_TBL.*;
@ -70,6 +70,6 @@ INSERT INTO CHAR_TBL (f1) VALUES ('a');
INSERT INTO CHAR_TBL (f1) VALUES ('ab');
INSERT INTO CHAR_TBL (f1) VALUES ('abcd');
INSERT INTO CHAR_TBL (f1) VALUES ('abcde');
INSERT INTO CHAR_TBL (f1) VALUES ('abcd ');
SELECT '' AS four, CHAR_TBL.*;

View File

@ -188,30 +188,6 @@ INSERT INTO f_star (class, f)
INSERT INTO f_star (class) VALUES ('f');
--
-- ARRAYS
--
--
-- only this array as a 0-based 'e', the others are 1-based.
-- 'e' is also a large object.
--
INSERT INTO arrtest (a[5], b[2][1][2], c, d, f, g)
VALUES ('{1,2,3,4,5}', '{{{},{1,2}}}', '{}', '{}', '{}', '{}');
UPDATE arrtest SET e[0] = '1.1';
UPDATE arrtest SET e[1] = '2.2';
INSERT INTO arrtest (a, b[2][2][1], c, d, e, f, g)
VALUES ('{11,12,23}', '{{3,4},{4,5}}', '{"foobar"}',
'{{"elt1", "elt2"}}', '{"3.4", "6.7"}',
'{"abc","abcdefgh"}', '{"abc","abcdefgh"}');
INSERT INTO arrtest (a, b[1][2][2], c, d[2][1])
VALUES ('{}', '{3,4}', '{foo,bar}', '{bar,foo}');
--
-- for internal portal (cursor) tests

View File

@ -172,16 +172,6 @@ CREATE TABLE aggtest (
b float4
);
CREATE TABLE arrtest (
a int2[],
b int4[][][],
c name[],
d text[][],
e float8[],
f char(5)[],
g varchar(5)[]
);
CREATE TABLE hash_i4_heap (
seqno int4,
random int4

View File

@ -25,7 +25,9 @@ SELECT CAST(f1 AS text) AS "text(varchar)" FROM VARCHAR_TBL;
SELECT CAST(name 'namefield' AS text) AS "text(name)";
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL;
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL; -- fail
SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;
SELECT CAST(f1 AS char(10)) AS "char(varchar)" FROM VARCHAR_TBL;
@ -158,7 +160,7 @@ SELECT 'unknown' || ' and unknown' AS "Concat unknown types";
SELECT text 'text' || ' and unknown' AS "Concat text to unknown type";
SELECT text 'text' || char(10) ' and characters' AS "Concat text to char";
SELECT text 'text' || char(20) ' and characters' AS "Concat text to char";
SELECT text 'text' || varchar ' and varchar' AS "Concat text to varchar";

View File

@ -20,6 +20,7 @@ INSERT INTO VARCHAR_TBL (f1) VALUES ('');
-- try varchar's of greater than 1 length
INSERT INTO VARCHAR_TBL (f1) VALUES ('cd');
INSERT INTO VARCHAR_TBL (f1) VALUES ('c ');
SELECT '' AS seven, VARCHAR_TBL.*;
@ -60,6 +61,6 @@ INSERT INTO VARCHAR_TBL (f1) VALUES ('a');
INSERT INTO VARCHAR_TBL (f1) VALUES ('ab');
INSERT INTO VARCHAR_TBL (f1) VALUES ('abcd');
INSERT INTO VARCHAR_TBL (f1) VALUES ('abcde');
INSERT INTO VARCHAR_TBL (f1) VALUES ('abcd ');
SELECT '' AS four, VARCHAR_TBL.*;