]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/varlena.c
New NameStr macro to convert Name to Str. No need for var.data anymore.
[postgresql] / src / backend / utils / adt / varlena.c
1 /*-------------------------------------------------------------------------
2  *
3  * varlena.c
4  *        Functions for the variable-length built-in types.
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.54 1999/11/07 23:08:24 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <ctype.h>
15
16 #include "postgres.h"
17
18 #include "mb/pg_wchar.h"
19 #include "utils/builtins.h"
20
21 static int      text_cmp(text *arg1, text *arg2);
22
23
24 /*****************************************************************************
25  *       USER I/O ROUTINES                                                                                                               *
26  *****************************************************************************/
27
28
29 #define VAL(CH)                 ((CH) - '0')
30 #define DIG(VAL)                ((VAL) + '0')
31
32 /*
33  *              byteain                 - converts from printable representation of byte array
34  *
35  *              Non-printable characters must be passed as '\nnn' (octal) and are
36  *              converted to internal form.  '\' must be passed as '\\'.
37  *              elog(ERROR, ...) if bad form.
38  *
39  *              BUGS:
40  *                              The input is scaned twice.
41  *                              The error checking of input is minimal.
42  */
43 text *
44 byteain(char *inputText)
45 {
46         char       *tp;
47         char       *rp;
48         int                     byte;
49         text       *result;
50
51         if (inputText == NULL)
52                 elog(ERROR, "Bad input string for type bytea");
53
54         for (byte = 0, tp = inputText; *tp != '\0'; byte++)
55                 if (*tp++ == '\\')
56                 {
57                         if (*tp == '\\')
58                                 tp++;
59                         else if (!isdigit(*tp++) ||
60                                          !isdigit(*tp++) ||
61                                          !isdigit(*tp++))
62                                 elog(ERROR, "Bad input string for type bytea");
63                 }
64         tp = inputText;
65         byte += VARHDRSZ;
66         result = (text *) palloc(byte);
67         result->vl_len = byte;          /* varlena? */
68         rp = result->vl_dat;
69         while (*tp != '\0')
70                 if (*tp != '\\' || *++tp == '\\')
71                         *rp++ = *tp++;
72                 else
73                 {
74                         byte = VAL(*tp++);
75                         byte <<= 3;
76                         byte += VAL(*tp++);
77                         byte <<= 3;
78                         *rp++ = byte + VAL(*tp++);
79                 }
80         return result;
81 }
82
83 /*
84  *              byteaout                - converts to printable representation of byte array
85  *
86  *              Non-printable characters are inserted as '\nnn' (octal) and '\' as
87  *              '\\'.
88  *
89  *              NULL vlena should be an error--returning string with NULL for now.
90  */
91 char *
92 byteaout(text *vlena)
93 {
94         char       *result;
95
96         char       *vp;
97         char       *rp;
98         int                     val;                    /* holds unprintable chars */
99         int                     i;
100         int                     len;
101
102         if (vlena == NULL)
103         {
104                 result = (char *) palloc(2);
105                 result[0] = '-';
106                 result[1] = '\0';
107                 return result;
108         }
109         vp = vlena->vl_dat;
110         len = 1;                                        /* empty string has 1 char */
111         for (i = vlena->vl_len - VARHDRSZ; i != 0; i--, vp++)
112                 if (*vp == '\\')
113                         len += 2;
114                 else if (isascii(*vp) && isprint(*vp))
115                         len++;
116                 else
117                         len += VARHDRSZ;
118         rp = result = (char *) palloc(len);
119         vp = vlena->vl_dat;
120         for (i = vlena->vl_len - VARHDRSZ; i != 0; i--)
121                 if (*vp == '\\')
122                 {
123                         vp++;
124                         *rp++ = '\\';
125                         *rp++ = '\\';
126                 }
127                 else if (isascii(*vp) && isprint(*vp))
128                         *rp++ = *vp++;
129                 else
130                 {
131                         val = *vp++;
132                         *rp = '\\';
133                         rp += 3;
134                         *rp-- = DIG(val & 07);
135                         val >>= 3;
136                         *rp-- = DIG(val & 07);
137                         val >>= 3;
138                         *rp = DIG(val & 03);
139                         rp += 3;
140                 }
141         *rp = '\0';
142         return result;
143 }
144
145
146 /*
147  *              textin                  - converts "..." to internal representation
148  */
149 text *
150 textin(char *inputText)
151 {
152         text       *result;
153         int                     len;
154
155         if (inputText == NULL)
156                 return NULL;
157
158         len = strlen(inputText) + VARHDRSZ;
159         result = (text *) palloc(len);
160         VARSIZE(result) = len;
161
162         memmove(VARDATA(result), inputText, len - VARHDRSZ);
163
164 #ifdef CYR_RECODE
165         convertstr(VARDATA(result), len - VARHDRSZ, 0);
166 #endif
167
168         return result;
169 }
170
171 /*
172  *              textout                 - converts internal representation to "..."
173  */
174 char *
175 textout(text *vlena)
176 {
177         int                     len;
178         char       *result;
179
180         if (vlena == NULL)
181         {
182                 result = (char *) palloc(2);
183                 result[0] = '-';
184                 result[1] = '\0';
185                 return result;
186         }
187         len = VARSIZE(vlena) - VARHDRSZ;
188         result = (char *) palloc(len + 1);
189         memmove(result, VARDATA(vlena), len);
190         result[len] = '\0';
191
192 #ifdef CYR_RECODE
193         convertstr(result, len, 1);
194 #endif
195
196         return result;
197 }
198
199
200 /* ========== PUBLIC ROUTINES ========== */
201
202 /*
203  * textlen -
204  *        returns the logical length of a text*
205  *         (which is less than the VARSIZE of the text*)
206  */
207 int32
208 textlen(text *t)
209 {
210 #ifdef MULTIBYTE
211         unsigned char *s;
212         int                     len,
213                                 l,
214                                 wl;
215
216 #endif
217
218         if (!PointerIsValid(t))
219                 elog(ERROR, "Null input to textlen");
220
221 #ifdef MULTIBYTE
222         len = 0;
223         s = VARDATA(t);
224         l = VARSIZE(t) - VARHDRSZ;
225         while (l > 0)
226         {
227                 wl = pg_mblen(s);
228                 l -= wl;
229                 s += wl;
230                 len++;
231         }
232         return (len);
233 #else
234         return VARSIZE(t) - VARHDRSZ;
235 #endif
236
237 }       /* textlen() */
238
239 /*
240  * textoctetlen -
241  *        returns the physical length of a text*
242  *         (which is less than the VARSIZE of the text*)
243  */
244 int32
245 textoctetlen(text *t)
246 {
247         if (!PointerIsValid(t))
248                 elog(ERROR, "Null input to textoctetlen");
249
250         return VARSIZE(t) - VARHDRSZ;
251
252 }       /* textoctetlen() */
253
254 /*
255  * textcat -
256  *        takes two text* and returns a text* that is the concatentation of
257  *        the two.
258  *
259  * Rewritten by Sapa, sapa@hq.icb.chel.su. 8-Jul-96.
260  * Updated by Thomas, Thomas.Lockhart@jpl.nasa.gov 1997-07-10.
261  * Allocate space for output in all cases.
262  * XXX - thomas 1997-07-10
263  */
264 text *
265 textcat(text *t1, text *t2)
266 {
267         int                     len1,
268                                 len2,
269                                 len;
270         char       *ptr;
271         text       *result;
272
273         if (!PointerIsValid(t1) || !PointerIsValid(t2))
274                 return NULL;
275
276         len1 = (VARSIZE(t1) - VARHDRSZ);
277         if (len1 < 0)
278                 len1 = 0;
279         while (len1 > 0 && VARDATA(t1)[len1 - 1] == '\0')
280                 len1--;
281
282         len2 = (VARSIZE(t2) - VARHDRSZ);
283         if (len2 < 0)
284                 len2 = 0;
285         while (len2 > 0 && VARDATA(t2)[len2 - 1] == '\0')
286                 len2--;
287
288         len = len1 + len2 + VARHDRSZ;
289         result = palloc(len);
290
291         /* Set size of result string... */
292         VARSIZE(result) = len;
293
294         /* Fill data field of result string... */
295         ptr = VARDATA(result);
296         if (len1 > 0)
297                 memcpy(ptr, VARDATA(t1), len1);
298         if (len2 > 0)
299                 memcpy(ptr + len1, VARDATA(t2), len2);
300
301         return result;
302 }       /* textcat() */
303
304 /*
305  * text_substr()
306  * Return a substring starting at the specified position.
307  * - thomas 1997-12-31
308  *
309  * Input:
310  *      - string
311  *      - starting position (is one-based)
312  *      - string length
313  *
314  * If the starting position is zero or less, then return from the start of the string
315  *      adjusting the length to be consistant with the "negative start" per SQL92.
316  * If the length is less than zero, return the remaining string.
317  *
318  * Note that the arguments operate on octet length,
319  *      so not aware of multi-byte character sets.
320  *
321  * Added multi-byte support.
322  * - Tatsuo Ishii 1998-4-21
323  * Changed behavior if starting position is less than one to conform to SQL92 behavior.
324  * Formerly returned the entire string; now returns a portion.
325  * - Thomas Lockhart 1998-12-10
326  */
327 text *
328 text_substr(text *string, int32 m, int32 n)
329 {
330         text       *ret;
331         int                     len;
332
333 #ifdef MULTIBYTE
334         int                     i;
335         char       *p;
336
337 #endif
338
339         if (string == (text *) NULL)
340                 return string;
341
342         len = VARSIZE(string) - VARHDRSZ;
343 #ifdef MULTIBYTE
344         len = pg_mbstrlen_with_len(VARDATA(string), len);
345 #endif
346
347         /* starting position after the end of the string? */
348         if (m > len)
349         {
350                 m = 1;
351                 n = 0;
352         }
353
354         /*
355          * starting position before the start of the string? then offset into
356          * the string per SQL92 spec...
357          */
358         else if (m < 1)
359         {
360                 n += (m - 1);
361                 m = 1;
362         }
363
364         /* m will now become a zero-based starting position */
365         m--;
366         if (((m + n) > len) || (n < 0))
367                 n = (len - m);
368
369 #ifdef MULTIBYTE
370         p = VARDATA(string);
371         for (i = 0; i < m; i++)
372                 p += pg_mblen(p);
373         m = p - VARDATA(string);
374         for (i = 0; i < n; i++)
375                 p += pg_mblen(p);
376         n = p - (VARDATA(string) + m);
377 #endif
378         ret = (text *) palloc(VARHDRSZ + n);
379         VARSIZE(ret) = VARHDRSZ + n;
380
381         memcpy(VARDATA(ret), VARDATA(string) + m, n);
382
383         return ret;
384 }       /* text_substr() */
385
386 /*
387  * textpos -
388  *        Return the position of the specified substring.
389  *        Implements the SQL92 POSITION() function.
390  *        Ref: A Guide To The SQL Standard, Date & Darwen, 1997
391  * - thomas 1997-07-27
392  *
393  * Added multi-byte support.
394  * - Tatsuo Ishii 1998-4-21
395  */
396 int32
397 textpos(text *t1, text *t2)
398 {
399         int                     pos;
400         int                     px,
401                                 p;
402         int                     len1,
403                                 len2;
404         pg_wchar   *p1,
405                            *p2;
406
407 #ifdef MULTIBYTE
408         pg_wchar   *ps1,
409                            *ps2;
410
411 #endif
412
413         if (!PointerIsValid(t1) || !PointerIsValid(t2))
414                 return 0;
415
416         if (VARSIZE(t2) <= 0)
417                 return 1;
418
419         len1 = (VARSIZE(t1) - VARHDRSZ);
420         len2 = (VARSIZE(t2) - VARHDRSZ);
421 #ifdef MULTIBYTE
422         ps1 = p1 = (pg_wchar *) palloc((len1 + 1) * sizeof(pg_wchar));
423         (void) pg_mb2wchar_with_len((unsigned char *) VARDATA(t1), p1, len1);
424         len1 = pg_wchar_strlen(p1);
425         ps2 = p2 = (pg_wchar *) palloc((len2 + 1) * sizeof(pg_wchar));
426         (void) pg_mb2wchar_with_len((unsigned char *) VARDATA(t2), p2, len2);
427         len2 = pg_wchar_strlen(p2);
428 #else
429         p1 = VARDATA(t1);
430         p2 = VARDATA(t2);
431 #endif
432         pos = 0;
433         px = (len1 - len2);
434         for (p = 0; p <= px; p++)
435         {
436 #ifdef MULTIBYTE
437                 if ((*p2 == *p1) && (pg_wchar_strncmp(p1, p2, len2) == 0))
438 #else
439                 if ((*p2 == *p1) && (strncmp(p1, p2, len2) == 0))
440 #endif
441                 {
442                         pos = p + 1;
443                         break;
444                 };
445                 p1++;
446         };
447 #ifdef MULTIBYTE
448         pfree(ps1);
449         pfree(ps2);
450 #endif
451         return pos;
452 }       /* textpos() */
453
454 /*
455  *              texteq                  - returns 1 iff arguments are equal
456  *              textne                  - returns 1 iff arguments are not equal
457  */
458 bool
459 texteq(text *arg1, text *arg2)
460 {
461         int                     len;
462         char       *a1p,
463                            *a2p;
464
465         if (arg1 == NULL || arg2 == NULL)
466                 return (bool) NULL;
467         if ((len = arg1->vl_len) != arg2->vl_len)
468                 return (bool) 0;
469         a1p = arg1->vl_dat;
470         a2p = arg2->vl_dat;
471
472         /*
473          * Varlenas are stored as the total size (data + size variable)
474          * followed by the data. Use VARHDRSZ instead of explicit sizeof() -
475          * thomas 1997-07-10
476          */
477         len -= VARHDRSZ;
478         while (len-- != 0)
479                 if (*a1p++ != *a2p++)
480                         return (bool) 0;
481         return (bool) 1;
482 }       /* texteq() */
483
484 bool
485 textne(text *arg1, text *arg2)
486 {
487         return (bool) !texteq(arg1, arg2);
488 }
489
490 /* varstr_cmp()
491  * Comparison function for text strings with given lengths.
492  * Includes locale support, but must copy strings to temporary memory
493  *      to allow null-termination for inputs to strcoll().
494  * Returns -1, 0 or 1
495  */
496 int
497 varstr_cmp(char *arg1, int len1, char *arg2, int len2)
498 {
499         int                     result;
500         char       *a1p,
501                            *a2p;
502
503 #ifdef USE_LOCALE
504         a1p = (unsigned char *) palloc(len1 + 1);
505         a2p = (unsigned char *) palloc(len2 + 1);
506
507         memcpy(a1p, arg1, len1);
508         *(a1p + len1) = '\0';
509         memcpy(a2p, arg2, len2);
510         *(a2p + len2) = '\0';
511
512         result = strcoll(a1p, a2p);
513
514         pfree(a1p);
515         pfree(a2p);
516
517 #else
518
519         a1p = arg1;
520         a2p = arg2;
521
522         result = strncmp(a1p, a2p, Min(len1, len2));
523         if ((result == 0) && (len1 != len2))
524                 result = (len1 < len2) ? -1 : 1;
525 #endif
526
527         return result;
528 }       /* varstr_cmp() */
529
530
531 /* text_cmp()
532  * Comparison function for text strings.
533  * Includes locale support, but must copy strings to temporary memory
534  *      to allow null-termination for inputs to strcoll().
535  * XXX HACK code for textlen() indicates that there can be embedded nulls
536  *      but it appears that most routines (incl. this one) assume not! - tgl 97/04/07
537  * Returns -1, 0 or 1
538  */
539 static int
540 text_cmp(text *arg1, text *arg2)
541 {
542         char       *a1p,
543                            *a2p;
544         int                     len1,
545                                 len2;
546
547         if (arg1 == NULL || arg2 == NULL)
548                 return (bool) FALSE;
549
550         a1p = VARDATA(arg1);
551         a2p = VARDATA(arg2);
552
553         len1 = VARSIZE(arg1) - VARHDRSZ;
554         len2 = VARSIZE(arg2) - VARHDRSZ;
555
556         return varstr_cmp(a1p, len1, a2p, len2);
557 }       /* text_cmp() */
558
559 /* text_lt()
560  * Comparison function for text strings.
561  */
562 bool
563 text_lt(text *arg1, text *arg2)
564 {
565         return (bool) (text_cmp(arg1, arg2) < 0);
566 }       /* text_lt() */
567
568 /* text_le()
569  * Comparison function for text strings.
570  */
571 bool
572 text_le(text *arg1, text *arg2)
573 {
574         return (bool) (text_cmp(arg1, arg2) <= 0);
575 }       /* text_le() */
576
577 bool
578 text_gt(text *arg1, text *arg2)
579 {
580         return (bool) !text_le(arg1, arg2);
581 }
582
583 bool
584 text_ge(text *arg1, text *arg2)
585 {
586         return (bool) !text_lt(arg1, arg2);
587 }
588
589 text *
590 text_larger(text *arg1, text *arg2)
591 {
592         text       *result;
593         text       *temp;
594
595         temp = ((text_cmp(arg1, arg2) <= 0) ? arg2 : arg1);
596
597         /* Make a copy */
598
599         result = (text *) palloc(VARSIZE(temp));
600         memmove((char *) result, (char *) temp, VARSIZE(temp));
601
602         return (result);
603 }
604
605 text *
606 text_smaller(text *arg1, text *arg2)
607 {
608         text       *result;
609         text       *temp;
610
611         temp = ((text_cmp(arg1, arg2) > 0) ? arg2 : arg1);
612
613         /* Make a copy */
614
615         result = (text *) palloc(VARSIZE(temp));
616         memmove((char *) result, (char *) temp, VARSIZE(temp));
617
618         return (result);
619 }
620
621 /*-------------------------------------------------------------
622  * byteaGetSize
623  *
624  * get the number of bytes contained in an instance of type 'bytea'
625  *-------------------------------------------------------------
626  */
627 int32
628 byteaGetSize(text *v)
629 {
630         int                     len;
631
632         len = v->vl_len - sizeof(v->vl_len);
633
634         return len;
635 }
636
637 /*-------------------------------------------------------------
638  * byteaGetByte
639  *
640  * this routine treats "bytea" as an array of bytes.
641  * It returns the Nth byte (a number between 0 and 255) or
642  * it dies if the length of this array is less than n.
643  *-------------------------------------------------------------
644  */
645 int32
646 byteaGetByte(text *v, int32 n)
647 {
648         int                     len;
649         int                     byte;
650
651         len = byteaGetSize(v);
652
653         if (n >= len)
654         {
655                 elog(ERROR, "byteaGetByte: index (=%d) out of range [0..%d]",
656                          n, len - 1);
657         }
658 #ifdef USE_LOCALE
659         byte = (unsigned char) (v->vl_dat[n]);
660 #else
661         byte = v->vl_dat[n];
662 #endif
663         return (int32) byte;
664 }
665
666 /*-------------------------------------------------------------
667  * byteaGetBit
668  *
669  * This routine treats a "bytea" type like an array of bits.
670  * It returns the value of the Nth bit (0 or 1).
671  * If 'n' is out of range, it dies!
672  *
673  *-------------------------------------------------------------
674  */
675 int32
676 byteaGetBit(text *v, int32 n)
677 {
678         int                     byteNo,
679                                 bitNo;
680         int                     byte;
681
682         byteNo = n / 8;
683         bitNo = n % 8;
684
685         byte = byteaGetByte(v, byteNo);
686
687         if (byte & (1 << bitNo))
688                 return (int32) 1;
689         else
690                 return (int32) 0;
691 }
692
693 /*-------------------------------------------------------------
694  * byteaSetByte
695  *
696  * Given an instance of type 'bytea' creates a new one with
697  * the Nth byte set to the given value.
698  *
699  *-------------------------------------------------------------
700  */
701 text *
702 byteaSetByte(text *v, int32 n, int32 newByte)
703 {
704         int                     len;
705         text       *res;
706
707         len = byteaGetSize(v);
708
709         if (n >= len)
710         {
711                 elog(ERROR,
712                          "byteaSetByte: index (=%d) out of range [0..%d]",
713                          n, len - 1);
714         }
715
716         /*
717          * Make a copy of the original varlena.
718          */
719         res = (text *) palloc(VARSIZE(v));
720         if (res == NULL)
721         {
722                 elog(ERROR, "byteaSetByte: Out of memory (%d bytes requested)",
723                          VARSIZE(v));
724         }
725         memmove((char *) res, (char *) v, VARSIZE(v));
726
727         /*
728          * Now set the byte.
729          */
730         res->vl_dat[n] = newByte;
731
732         return res;
733 }
734
735 /*-------------------------------------------------------------
736  * byteaSetBit
737  *
738  * Given an instance of type 'bytea' creates a new one with
739  * the Nth bit set to the given value.
740  *
741  *-------------------------------------------------------------
742  */
743 text *
744 byteaSetBit(text *v, int32 n, int32 newBit)
745 {
746         text       *res;
747         int                     oldByte,
748                                 newByte;
749         int                     byteNo,
750                                 bitNo;
751
752         /*
753          * sanity check!
754          */
755         if (newBit != 0 && newBit != 1)
756                 elog(ERROR, "byteaSetByte: new bit must be 0 or 1");
757
758         /*
759          * get the byte where the bit we want is stored.
760          */
761         byteNo = n / 8;
762         bitNo = n % 8;
763         oldByte = byteaGetByte(v, byteNo);
764
765         /*
766          * calculate the new value for that byte
767          */
768         if (newBit == 0)
769                 newByte = oldByte & (~(1 << bitNo));
770         else
771                 newByte = oldByte | (1 << bitNo);
772
773         /*
774          * NOTE: 'byteaSetByte' creates a copy of 'v' & sets the byte.
775          */
776         res = byteaSetByte(v, byteNo, newByte);
777
778         return res;
779 }
780
781
782 /* text_name()
783  * Converts a text() type to a NameData type.
784  */
785 NameData   *
786 text_name(text *s)
787 {
788         NameData   *result;
789         int                     len;
790
791         if (s == NULL)
792                 return NULL;
793
794         len = VARSIZE(s) - VARHDRSZ;
795         if (len > NAMEDATALEN)
796                 len = NAMEDATALEN;
797
798 #ifdef STRINGDEBUG
799         printf("text- convert string length %d (%d) ->%d\n",
800                    VARSIZE(s) - VARHDRSZ, VARSIZE(s), len);
801 #endif
802
803         result = palloc(NAMEDATALEN);
804         StrNCpy(NameStr(*result), VARDATA(s), NAMEDATALEN);
805
806         /* now null pad to full length... */
807         while (len < NAMEDATALEN)
808         {
809                 *(NameStr(*result) + len) = '\0';
810                 len++;
811         }
812
813         return result;
814 }       /* text_name() */
815
816 /* name_text()
817  * Converts a NameData type to a text type.
818  */
819 text *
820 name_text(NameData *s)
821 {
822         text       *result;
823         int                     len;
824
825         if (s == NULL)
826                 return NULL;
827
828         len = strlen(NameStr(*s));
829
830 #ifdef STRINGDEBUG
831         printf("text- convert string length %d (%d) ->%d\n",
832                    VARSIZE(s) - VARHDRSZ, VARSIZE(s), len);
833 #endif
834
835         result = palloc(VARHDRSZ + len);
836         strncpy(VARDATA(result), NameStr(*s), len);
837         VARSIZE(result) = len + VARHDRSZ;
838
839         return result;
840 }       /* name_text() */