1 /*-------------------------------------------------------------------------
4 * Functions for the built-in type char() and varchar().
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.53 1999/07/17 16:25:25 momjian Exp $
12 *-------------------------------------------------------------------------
18 #include "access/htup.h"
19 #include "catalog/pg_type.h"
20 #include "utils/builtins.h"
23 #include "mb/pg_wchar.h"
27 char *convertstr(char *, int, int);
32 * CHAR() and VARCHAR() types are part of the ANSI SQL standard. CHAR()
33 * is for blank-padded string whose length is specified in CREATE TABLE.
34 * VARCHAR is for storing string whose length is at most the length specified
35 * at CREATE TABLE time.
37 * It's hard to implement these types because we cannot figure out what
38 * the length of the type from the type itself. I change (hopefully all) the
39 * fmgr calls that invoke input functions of a data type to supply the
40 * length also. (eg. in INSERTs, we have the tupleDescriptor which contains
41 * the length of the attributes and hence the exact length of the char() or
42 * varchar(). We pass this to bpcharin() or varcharin().) In the case where
43 * we cannot determine the length, we pass in -1 instead and the input string
44 * must be null-terminated.
46 * We actually implement this as a varlena so that we don't have to pass in
47 * the length for the comparison functions. (The difference between "text"
48 * is that we truncate and possibly blank-pad the string at insertion time.)
54 /*****************************************************************************
56 *****************************************************************************/
60 * converts a string of char() type to the internal representation.
61 * len is the length specified in () plus VARHDRSZ bytes. (XXX dummy is here
62 * because we pass typelem as the second argument for array_in.)
65 bpcharin(char *s, int dummy, int32 atttypmod)
79 * this is here because some functions can't supply the atttypmod
82 atttypmod = len + VARHDRSZ;
85 len = atttypmod - VARHDRSZ;
87 if (len > MaxAttrSize)
88 elog(ERROR, "bpcharin: length of char() must be less than %d",
91 result = (char *) palloc(atttypmod);
92 VARSIZE(result) = atttypmod;
94 for (i = 0; i < len; i++, r++, s++)
102 convertstr(result + VARHDRSZ, len, 0);
105 /* blank pad the string if necessary */
119 result = (char *) palloc(2);
125 len = VARSIZE(s) - VARHDRSZ;
126 result = (char *) palloc(len + 1);
127 StrNCpy(result, VARDATA(s), len + 1); /* these are blank-padded */
131 convertstr(result, len, 1);
138 * Converts a char() type to a specific internal length.
139 * len is the length specified in () plus VARHDRSZ bytes.
142 bpchar(char *s, int32 len)
151 return (char *) NULL;
153 if ((len == -1) || (len == VARSIZE(s)))
156 rlen = len - VARHDRSZ;
158 if (rlen > MaxAttrSize)
159 elog(ERROR, "bpchar: length of char() must be less than %d",
163 printf("bpchar- convert string length %d (%d) ->%d (%d)\n",
164 VARSIZE(s) - VARHDRSZ, VARSIZE(s), rlen, len);
167 result = (char *) palloc(len);
168 VARSIZE(result) = len;
173 * truncate multi-byte string in a way not to break multi-byte
176 if (VARSIZE(s) > len)
177 slen = pg_mbcliplen(VARDATA(s), VARSIZE(s) - VARHDRSZ, rlen);
179 slen = VARSIZE(s) - VARHDRSZ;
181 slen = VARSIZE(s) - VARHDRSZ;
186 printf("bpchar- string is '");
189 for (i = 0; (i < rlen) && (i < slen); i++)
205 /* blank pad the string if necessary */
206 for (; i < rlen; i++)
213 * Converts an array of char() type to a specific internal length.
214 * len is the length specified in () plus VARHDRSZ bytes.
217 _bpchar(ArrayType *v, int32 len)
219 return array_map(v, BPCHAROID, bpchar, BPCHAROID, 1, len);
224 * Convert bpchar(1) to char.
229 return (int32) *VARDATA(s);
230 } /* bpchar_char() */
233 * Convert char to bpchar(1).
240 result = palloc(VARHDRSZ + 1);
242 VARSIZE(result) = VARHDRSZ + 1;
243 *(VARDATA(result)) = (char) c;
246 } /* char_bpchar() */
250 * Converts a bpchar() type to a NameData type.
261 len = VARSIZE(s) - VARHDRSZ;
262 if (len > NAMEDATALEN)
267 if (*(VARDATA(s) + len - 1) != ' ')
273 printf("bpchar- convert string length %d (%d) ->%d\n",
274 VARSIZE(s) - VARHDRSZ, VARSIZE(s), len);
277 result = (NameData *) palloc(NAMEDATALEN);
278 StrNCpy(result->data, VARDATA(s), NAMEDATALEN);
280 /* now null pad to full length... */
281 while (len < NAMEDATALEN)
283 *(result->data + len) = '\0';
288 } /* bpchar_name() */
291 * Converts a NameData type to a bpchar type.
294 name_bpchar(NameData *s)
302 len = strlen(s->data);
305 printf("bpchar- convert string length %d (%d) ->%d\n",
306 VARSIZE(s) - VARHDRSZ, VARSIZE(s), len);
309 result = (char *) palloc(VARHDRSZ + len);
310 strncpy(VARDATA(result), s->data, len);
311 VARSIZE(result) = len + VARHDRSZ;
314 } /* name_bpchar() */
317 /*****************************************************************************
318 * varchar - varchar() *
319 *****************************************************************************/
323 * converts a string of varchar() type to the internal representation.
324 * len is the length specified in () plus VARHDRSZ bytes. (XXX dummy is here
325 * because we pass typelem as the second argument for array_in.)
328 varcharin(char *s, int dummy, int32 atttypmod)
334 return (char *) NULL;
336 len = strlen(s) + VARHDRSZ;
337 if (atttypmod != -1 && len > atttypmod)
338 len = atttypmod; /* clip the string at max length */
340 if (len > MaxAttrSize)
341 elog(ERROR, "varcharin: length of char() must be less than %d",
344 result = (char *) palloc(len);
345 VARSIZE(result) = len;
346 strncpy(VARDATA(result), s, len - VARHDRSZ);
349 convertstr(result + VARHDRSZ, len, 0);
363 result = (char *) palloc(2);
369 len = VARSIZE(s) - VARHDRSZ;
370 result = (char *) palloc(len + 1);
371 StrNCpy(result, VARDATA(s), len + 1);
375 convertstr(result, len, 1);
382 * Converts a varchar() type to the specified size.
383 * slen is the length specified in () plus VARHDRSZ bytes.
386 varchar(char *s, int32 slen)
392 return (char *) NULL;
395 if ((slen == -1) || (len <= slen))
398 /* only reach here if we need to truncate string... */
403 * truncate multi-byte string in a way not to break multi-byte
406 len = pg_mbcliplen(VARDATA(s), slen - VARHDRSZ, slen - VARHDRSZ);
407 slen = len + VARHDRSZ;
409 len = slen - VARHDRSZ;
412 if (len > MaxAttrSize)
413 elog(ERROR, "varchar: length of varchar() must be less than %d",
416 result = (char *) palloc(slen);
417 VARSIZE(result) = slen;
418 strncpy(VARDATA(result), VARDATA(s), len);
424 * Converts an array of varchar() type to the specified size.
425 * len is the length specified in () plus VARHDRSZ bytes.
428 _varchar(ArrayType *v, int32 len)
430 return array_map(v, VARCHAROID, varchar, VARCHAROID, 1, len);
434 /*****************************************************************************
435 * Comparison Functions used for bpchar
436 *****************************************************************************/
441 char *s = VARDATA(arg);
445 len = VARSIZE(arg) - VARHDRSZ;
446 for (i = len - 1; i >= 0; i--)
464 if (!PointerIsValid(arg))
465 elog(ERROR, "Bad (null) char() external representation", NULL);
479 return bcTruelen(arg);
484 bpcharoctetlen(char *arg)
486 if (!PointerIsValid(arg))
487 elog(ERROR, "Bad (null) char() external representation", NULL);
489 return bcTruelen(arg);
493 bpchareq(char *arg1, char *arg2)
498 if (arg1 == NULL || arg2 == NULL)
500 len1 = bcTruelen(arg1);
501 len2 = bcTruelen(arg2);
506 return strncmp(VARDATA(arg1), VARDATA(arg2), len1) == 0;
510 bpcharne(char *arg1, char *arg2)
515 if (arg1 == NULL || arg2 == NULL)
517 len1 = bcTruelen(arg1);
518 len2 = bcTruelen(arg2);
523 return strncmp(VARDATA(arg1), VARDATA(arg2), len1) != 0;
527 bpcharlt(char *arg1, char *arg2)
533 if (arg1 == NULL || arg2 == NULL)
535 len1 = bcTruelen(arg1);
536 len2 = bcTruelen(arg2);
538 cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
546 bpcharle(char *arg1, char *arg2)
552 if (arg1 == NULL || arg2 == NULL)
554 len1 = bcTruelen(arg1);
555 len2 = bcTruelen(arg2);
557 cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
559 return (bool) (len1 <= len2 ? 1 : 0);
561 return (bool) (cmp <= 0);
565 bpchargt(char *arg1, char *arg2)
571 if (arg1 == NULL || arg2 == NULL)
573 len1 = bcTruelen(arg1);
574 len2 = bcTruelen(arg2);
576 cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
584 bpcharge(char *arg1, char *arg2)
590 if (arg1 == NULL || arg2 == NULL)
592 len1 = bcTruelen(arg1);
593 len2 = bcTruelen(arg2);
595 cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
597 return (bool) (len1 >= len2 ? 1 : 0);
599 return (bool) (cmp >= 0);
603 bpcharcmp(char *arg1, char *arg2)
609 len1 = bcTruelen(arg1);
610 len2 = bcTruelen(arg2);
612 cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
613 if ((0 == cmp) && (len1 != len2))
614 return (int32) (len1 < len2 ? -1 : 1);
619 /*****************************************************************************
620 * Comparison Functions used for varchar
621 *****************************************************************************/
624 varcharlen(char *arg)
633 if (!PointerIsValid(arg))
634 elog(ERROR, "Bad (null) varchar() external representation", NULL);
639 l = VARSIZE(arg) - VARHDRSZ;
649 return VARSIZE(arg) - VARHDRSZ;
654 varcharoctetlen(char *arg)
656 if (!PointerIsValid(arg))
657 elog(ERROR, "Bad (null) varchar() external representation", NULL);
658 return VARSIZE(arg) - VARHDRSZ;
662 varchareq(char *arg1, char *arg2)
667 if (arg1 == NULL || arg2 == NULL)
670 len1 = VARSIZE(arg1) - VARHDRSZ;
671 len2 = VARSIZE(arg2) - VARHDRSZ;
676 return strncmp(VARDATA(arg1), VARDATA(arg2), len1) == 0;
680 varcharne(char *arg1, char *arg2)
685 if (arg1 == NULL || arg2 == NULL)
687 len1 = VARSIZE(arg1) - VARHDRSZ;
688 len2 = VARSIZE(arg2) - VARHDRSZ;
693 return strncmp(VARDATA(arg1), VARDATA(arg2), len1) != 0;
697 varcharlt(char *arg1, char *arg2)
703 if (arg1 == NULL || arg2 == NULL)
705 len1 = VARSIZE(arg1) - VARHDRSZ;
706 len2 = VARSIZE(arg2) - VARHDRSZ;
708 cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
716 varcharle(char *arg1, char *arg2)
722 if (arg1 == NULL || arg2 == NULL)
724 len1 = VARSIZE(arg1) - VARHDRSZ;
725 len2 = VARSIZE(arg2) - VARHDRSZ;
727 cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
729 return (bool) (len1 <= len2 ? 1 : 0);
731 return (bool) (cmp <= 0);
735 varchargt(char *arg1, char *arg2)
741 if (arg1 == NULL || arg2 == NULL)
743 len1 = VARSIZE(arg1) - VARHDRSZ;
744 len2 = VARSIZE(arg2) - VARHDRSZ;
746 cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
754 varcharge(char *arg1, char *arg2)
760 if (arg1 == NULL || arg2 == NULL)
762 len1 = VARSIZE(arg1) - VARHDRSZ;
763 len2 = VARSIZE(arg2) - VARHDRSZ;
765 cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
767 return (bool) (len1 >= len2 ? 1 : 0);
769 return (bool) (cmp >= 0);
774 varcharcmp(char *arg1, char *arg2)
780 len1 = VARSIZE(arg1) - VARHDRSZ;
781 len2 = VARSIZE(arg2) - VARHDRSZ;
782 cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
783 if ((0 == cmp) && (len1 != len2))
784 return (int32) (len1 < len2 ? -1 : 1);
786 return (int32) (cmp);
789 /*****************************************************************************
790 * Hash functions (modified from hashtext in access/hash/hashfunc.c)
791 *****************************************************************************/
794 hashbpchar(struct varlena * key)
801 keydata = VARDATA(key);
802 keylen = bcTruelen((char *) key);
804 #define HASHC n = *keydata++ + 65599 * n
809 loop = (keylen + 8 - 1) >> 3;
811 switch (keylen & (8 - 1))
815 { /* All fall throughs */
838 hashvarchar(struct varlena * key)
845 keydata = VARDATA(key);
846 keylen = VARSIZE(key) - VARHDRSZ;
848 #define HASHC n = *keydata++ + 65599 * n
853 loop = (keylen + 8 - 1) >> 3;
855 switch (keylen & (8 - 1))
859 { /* All fall throughs */