diff options
Diffstat (limited to 'src/backend/utils/adt/varlena.c')
-rw-r--r-- | src/backend/utils/adt/varlena.c | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c new file mode 100644 index 00000000000..1ef6f19113e --- /dev/null +++ b/src/backend/utils/adt/varlena.c @@ -0,0 +1,488 @@ +/*------------------------------------------------------------------------- + * + * varlena.c-- + * Functions for the variable-length built-in types. + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.1.1.1 1996/07/09 06:22:06 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include <ctype.h> +#include <string.h> + +#include "postgres.h" +#include "utils/elog.h" +#include "utils/palloc.h" +#include "utils/builtins.h" /* where function declarations go */ + +/***************************************************************************** + * USER I/O ROUTINES * + *****************************************************************************/ + + +#define VAL(CH) ((CH) - '0') +#define DIG(VAL) ((VAL) + '0') + +/* + * byteain - converts from printable representation of byte array + * + * Non-printable characters must be passed as '\nnn' (octal) and are + * converted to internal form. '\' must be passed as '\\'. + * elog(WARN, ...) if bad form. + * + * BUGS: + * The input is scaned twice. + * The error checking of input is minimal. + */ +struct varlena * +byteain(char *inputText) +{ + register char *tp; + register char *rp; + register int byte; + struct varlena *result; + + if (inputText == NULL) + elog(WARN, "Bad input string for type bytea"); + + for (byte = 0, tp = inputText; *tp != '\0'; byte++) + if (*tp++ == '\\') + { + if (*tp == '\\') + tp++; + else if (!isdigit(*tp++) || + !isdigit(*tp++) || + !isdigit(*tp++)) + elog(WARN, "Bad input string for type bytea"); + } + tp = inputText; + byte += sizeof(int32); /* varlena? */ + result = (struct varlena *) palloc(byte); + result->vl_len = byte; /* varlena? */ + rp = result->vl_dat; + while (*tp != '\0') + if (*tp != '\\' || *++tp == '\\') + *rp++ = *tp++; + else { + byte = VAL(*tp++); + byte <<= 3; + byte += VAL(*tp++); + byte <<= 3; + *rp++ = byte + VAL(*tp++); + } + return(result); +} + +/* + * Shoves a bunch of memory pointed at by bytes into varlena. + * BUGS: Extremely unportable as things shoved can be string + * representations of structs, etc. + */ +struct varlena * +shove_bytes(unsigned char *stuff, int len) +{ + struct varlena *result; + + result = (struct varlena *) palloc(len + sizeof(int32)); + result->vl_len = len; + memmove(result->vl_dat, + stuff + sizeof(int32), + len - sizeof(int32)); + return(result); +} + + + +/* + * byteaout - converts to printable representation of byte array + * + * Non-printable characters are inserted as '\nnn' (octal) and '\' as + * '\\'. + * + * NULL vlena should be an error--returning string with NULL for now. + */ +char * +byteaout(struct varlena *vlena) +{ + register char *vp; + register char *rp; + register int val; /* holds unprintable chars */ + int i; + int len; + static char *result; + + if (vlena == NULL) { + result = (char *) palloc(2); + result[0] = '-'; + result[1] = '\0'; + return(result); + } + vp = vlena->vl_dat; + len = 1; /* empty string has 1 char */ + for (i = vlena->vl_len - sizeof(int32); i != 0; i--, vp++) /* varlena? */ + if (*vp == '\\') + len += 2; + else if (isascii(*vp) && isprint(*vp)) + len++; + else + len += 4; + rp = result = (char *) palloc(len); + vp = vlena->vl_dat; + for (i = vlena->vl_len - sizeof(int32); i != 0; i--) /* varlena? */ + if (*vp == '\\') { + *vp++; + *rp++ = '\\'; + *rp++ = '\\'; + } else if (isascii(*vp) && isprint(*vp)) + *rp++ = *vp++; + else { + val = *vp++; + *rp = '\\'; + rp += 3; + *rp-- = DIG(val & 07); + val >>= 3; + *rp-- = DIG(val & 07); + val >>= 3; + *rp = DIG(val & 03); + rp += 3; + } + *rp = '\0'; + return(result); +} + + +/* + * textin - converts "..." to internal representation + */ +struct varlena * +textin(char *inputText) +{ + struct varlena *result; + int len; + + if (inputText == NULL) + return(NULL); + len = strlen(inputText) + VARHDRSZ; + result = (struct varlena *) palloc(len); + VARSIZE(result) = len; + memmove(VARDATA(result), inputText, len - VARHDRSZ); + return(result); +} + +/* + * textout - converts internal representation to "..." + */ +char * +textout(struct varlena *vlena) +{ + int len; + char *result; + + if (vlena == NULL) { + result = (char *) palloc(2); + result[0] = '-'; + result[1] = '\0'; + return(result); + } + len = VARSIZE(vlena) - VARHDRSZ; + result = (char *) palloc(len + 1); + memmove(result, VARDATA(vlena), len); + result[len] = '\0'; + return(result); +} + + +/* ========== PUBLIC ROUTINES ========== */ + +/* + * textcat - + * takes two text* and returns a text* that is the concatentation of + * the two + */ +text* +textcat(text* t1, text* t2) +{ + int newlen; + char *str1, *str2; + text* result; + + if (t1 == NULL) return t2; + if (t2 == NULL) return t1; + + /* since t1, and t2 are non-null, str1 and str2 must also be non-null */ + str1 = textout(t1); + str2 = textout(t2); + /* we use strlen here to calculate the length because the size fields + of t1, t2 may be longer than necessary to hold the string */ + newlen = strlen(str1) + strlen(str2) + VARHDRSZ; + result = (text*)palloc(newlen); + strcpy(VARDATA(result), str1); + strncat(VARDATA(result), str2, newlen - VARHDRSZ); + /* [TRH] Was: + strcat(VARDATA(result), str2); + which may corrupt the malloc arena due to writing trailing \0. */ + + pfree(str1); + pfree(str2); + return result; +} + +/* + * texteq - returns 1 iff arguments are equal + * textne - returns 1 iff arguments are not equal + */ +int32 +texteq(struct varlena *arg1, struct varlena *arg2) +{ + register int len; + register char *a1p, *a2p; + + if (arg1 == NULL || arg2 == NULL) + return((int32) NULL); + if ((len = arg1->vl_len) != arg2->vl_len) + return((int32) 0); + a1p = arg1->vl_dat; + a2p = arg2->vl_dat; + /* + * Varlenas are stored as the total size (data + size variable) + * followed by the data. The size variable is an int32 so the + * length of the data is the total length less sizeof(int32) + */ + len -= sizeof(int32); + while (len-- != 0) + if (*a1p++ != *a2p++) + return((int32) 0); + return((int32) 1); +} + +int32 +textne(struct varlena *arg1, struct varlena *arg2) +{ + return((int32) !texteq(arg1, arg2)); +} + +int32 +text_lt(struct varlena *arg1, struct varlena *arg2) +{ + int len; + char *a1p, *a2p; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + + a1p = VARDATA(arg1); + a2p = VARDATA(arg2); + + if ((len = arg1->vl_len) > arg2->vl_len) + len = arg2->vl_len; + len -= sizeof(int32); + + while (len != 0 && *a1p == *a2p) + { + a1p++; + a2p++; + len--; + } + if (len) + return (int32) (*a1p < *a2p); + else + return (int32) (arg1->vl_len < arg2->vl_len); +} + +int32 +text_le(struct varlena *arg1, struct varlena *arg2) +{ + int len; + char *a1p, *a2p; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + + a1p = VARDATA(arg1); + a2p = VARDATA(arg2); + + if ((len = arg1->vl_len) > arg2->vl_len) + len = arg2->vl_len; + len -= sizeof(int32); /* varlena! */ + + while (len != 0 && *a1p == *a2p) + { + a1p++; + a2p++; + len--; + } + if (len) + return (int32) (*a1p < *a2p); + else + return ((int32) VARSIZE(arg1) <= VARSIZE(arg2)); +} + +int32 +text_gt(struct varlena *arg1, struct varlena *arg2) +{ + return ((int32) !text_le(arg1, arg2)); +} + +int32 +text_ge(struct varlena *arg1, struct varlena *arg2) +{ + return ((int32) !text_lt(arg1, arg2)); +} + +/*------------------------------------------------------------- + * byteaGetSize + * + * get the number of bytes contained in an instance of type 'bytea' + *------------------------------------------------------------- + */ +int32 +byteaGetSize(struct varlena *v) +{ + register int len; + + len = v->vl_len - sizeof(v->vl_len); + + return(len); +} + +/*------------------------------------------------------------- + * byteaGetByte + * + * this routine treats "bytea" as an array of bytes. + * It returns the Nth byte (a number between 0 and 255) or + * it dies if the length of this array is less than n. + *------------------------------------------------------------- + */ +int32 +byteaGetByte(struct varlena *v, int32 n) +{ + int len; + int byte; + + len = byteaGetSize(v); + + if (n>=len) { + elog(WARN, "byteaGetByte: index (=%d) out of range [0..%d]", + n,len-1); + } + + byte = (unsigned char) (v->vl_dat[n]); + + return((int32) byte); +} + +/*------------------------------------------------------------- + * byteaGetBit + * + * This routine treats a "bytea" type like an array of bits. + * It returns the value of the Nth bit (0 or 1). + * If 'n' is out of range, it dies! + * + *------------------------------------------------------------- + */ +int32 +byteaGetBit(struct varlena *v, int32 n) +{ + int byteNo, bitNo; + int byte; + + byteNo = n/8; + bitNo = n%8; + + byte = byteaGetByte(v, byteNo); + + if (byte & (1<<bitNo)) { + return((int32)1); + } else { + return((int32)0); + } +} +/*------------------------------------------------------------- + * byteaSetByte + * + * Given an instance of type 'bytea' creates a new one with + * the Nth byte set to the given value. + * + *------------------------------------------------------------- + */ +struct varlena * +byteaSetByte(struct varlena *v, int32 n, int32 newByte) +{ + int len; + struct varlena *res; + + len = byteaGetSize(v); + + if (n>=len) { + elog(WARN, + "byteaSetByte: index (=%d) out of range [0..%d]", + n, len-1); + } + + /* + * Make a copy of the original varlena. + */ + res = (struct varlena *) palloc(VARSIZE(v)); + if (res==NULL) { + elog(WARN, "byteaSetByte: Out of memory (%d bytes requested)", + VARSIZE(v)); + } + memmove((char *)res, (char *)v, VARSIZE(v)); + + /* + * Now set the byte. + */ + res->vl_dat[n] = newByte; + + return(res); +} + +/*------------------------------------------------------------- + * byteaSetBit + * + * Given an instance of type 'bytea' creates a new one with + * the Nth bit set to the given value. + * + *------------------------------------------------------------- + */ +struct varlena * +byteaSetBit(struct varlena *v, int32 n, int32 newBit) +{ + struct varlena *res; + int oldByte, newByte; + int byteNo, bitNo; + + /* + * sanity check! + */ + if (newBit != 0 && newBit != 1) { + elog(WARN, "byteaSetByte: new bit must be 0 or 1"); + } + + /* + * get the byte where the bit we want is stored. + */ + byteNo = n / 8; + bitNo = n % 8; + oldByte = byteaGetByte(v, byteNo); + + /* + * calculate the new value for that byte + */ + if (newBit == 0) { + newByte = oldByte & (~(1<<bitNo)); + } else { + newByte = oldByte | (1<<bitNo); + } + + /* + * NOTE: 'byteaSetByte' creates a copy of 'v' & sets the byte. + */ + res = byteaSetByte(v, byteNo, newByte); + + return(res); +} |