aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/varlena.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/varlena.c')
-rw-r--r--src/backend/utils/adt/varlena.c488
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);
+}