diff options
Diffstat (limited to 'src/backend/utils/adt/varchar.c')
-rw-r--r-- | src/backend/utils/adt/varchar.c | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c new file mode 100644 index 00000000000..341ad94f009 --- /dev/null +++ b/src/backend/utils/adt/varchar.c @@ -0,0 +1,496 @@ +/*------------------------------------------------------------------------- + * + * char.c-- + * Functions for the built-in type char() and varchar(). + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include <stdio.h> /* for sprintf() */ +#include <string.h> +#include "postgres.h" +#include "utils/palloc.h" +#include "utils/elog.h" + +/* + * CHAR() and VARCHAR() types are part of the ANSI SQL standard. CHAR() + * is for blank-padded string whose length is specified in CREATE TABLE. + * VARCHAR is for storing string whose length is at most the length specified + * at CREATE TABLE time. + * + * It's hard to implement these types because we cannot figure out what + * the length of the type from the type itself. I change (hopefully all) the + * fmgr calls that invoke input functions of a data type to supply the + * length also. (eg. in INSERTs, we have the tupleDescriptor which contains + * the length of the attributes and hence the exact length of the char() or + * varchar(). We pass this to bpcharin() or varcharin().) In the case where + * we cannot determine the length, we pass in -1 instead and the input string + * must be null-terminated. + * + * We actually implement this as a varlena so that we don't have to pass in + * the length for the comparison functions. (The difference between "text" + * is that we truncate and possibly blank-pad the string at insertion time.) + * + * - ay 6/95 + */ + + +/***************************************************************************** + * bpchar - char() * + *****************************************************************************/ + +/* + * bpcharin - + * converts a string of char() type to the internal representation. + * len is the length specified in () plus 4 bytes. (XXX dummy is here + * because we pass typelem as the second argument for array_in.) + */ +char * +bpcharin(char *s, int dummy, int typlen) +{ + char *result, *r; + int len = typlen - 4; + int i; + + if (s == NULL) + return((char *) NULL); + + if (typlen == -1) { + /* + * this is here because some functions can't supply the typlen + */ + len = strlen(s); + typlen = len + 4; + } + + if (len < 1 || len > 4096) + elog(WARN, "bpcharin: length of char() must be between 1 and 4096"); + + result = (char *) palloc(typlen); + *(int32*)result = typlen; + r = result + 4; + for(i=0; i < len; i++, r++, s++) { + *r = *s; + if (*r == '\0') + break; + } + /* blank pad the string if necessary */ + for(; i < len; i++) { + *r++ = ' '; + } + return(result); +} + +char * +bpcharout(char *s) +{ + char *result; + int len; + + if (s == NULL) { + result = (char *) palloc(2); + result[0] = '-'; + result[1] = '\0'; + } else { + len = *(int32*)s - 4; + result = (char *) palloc(len+1); + strncpy(result, s+4, len); /* these are blank-padded */ + result[len] = '\0'; + } + return(result); +} + +/***************************************************************************** + * varchar - varchar() * + *****************************************************************************/ + +/* + * vcharin - + * converts a string of varchar() type to the internal representation. + * len is the length specified in () plus 4 bytes. (XXX dummy is here + * because we pass typelem as the second argument for array_in.) + */ +char * +varcharin(char *s, int dummy, int typlen) +{ + char *result; + int len = typlen - 4; + + if (s == NULL) + return((char *) NULL); + + if (typlen == -1) { + /* + * this is here because some functions can't supply the typlen + */ + len = strlen(s); + typlen = len + 4; + } + + if (len < 1 || len > 4096) + elog(WARN, "bpcharin: length of char() must be between 1 and 4096"); + + result = (char *) palloc(typlen); + *(int32*)result = typlen; + memset(result+4, 0, len); + (void) strncpy(result+4, s, len); + + return(result); +} + +char * +varcharout(char *s) +{ + char *result; + int len; + + if (s == NULL) { + result = (char *) palloc(2); + result[0] = '-'; + result[1] = '\0'; + } else { + len = *(int32*)s - 4; + result = (char *) palloc(len+1); + memset(result, 0, len+1); + strncpy(result, s+4, len); + } + return(result); +} + +/***************************************************************************** + * Comparison Functions used for bpchar + *****************************************************************************/ + +static int +bcTruelen(char *arg) +{ + char *s = arg + 4; + int i; + int len; + + len = *(int32*)arg - 4; + for(i=len-1; i >= 0; i--) { + if (s[i] != ' ') + break; + } + return (i+1); +} + +int32 +bpchareq(char *arg1, char *arg2) +{ + int len1, len2; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = bcTruelen(arg1); + len2 = bcTruelen(arg2); + + if (len1!=len2) + return 0; + + return(strncmp(arg1+4, arg2+4, len1) == 0); +} + +int32 +bpcharne(char *arg1, char *arg2) +{ + int len1, len2; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = bcTruelen(arg1); + len2 = bcTruelen(arg2); + + if (len1!=len2) + return 1; + + return(strncmp(arg1+4, arg2+4, len1) != 0); +} + +int32 +bpcharlt(char *arg1, char *arg2) +{ + int len1, len2; + int cmp; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = bcTruelen(arg1); + len2 = bcTruelen(arg2); + + cmp = strncmp(arg1+4, arg2+4, Min(len1,len2)); + if (cmp == 0) + return (len1<len2); + else + return (cmp < 0); +} + +int32 +bpcharle(char *arg1, char *arg2) +{ + int len1, len2; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = bcTruelen(arg1); + len2 = bcTruelen(arg2); + + return(strncmp(arg1+4, arg2+4, Min(len1,len2)) <= 0); +} + +int32 +bpchargt(char *arg1, char *arg2) +{ + int len1, len2; + int cmp; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = bcTruelen(arg1); + len2 = bcTruelen(arg2); + + cmp = strncmp(arg1+4, arg2+4, Min(len1,len2)); + if (cmp == 0) + return (len1 > len2); + else + return (cmp > 0); +} + +int32 +bpcharge(char *arg1, char *arg2) +{ + int len1, len2; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = bcTruelen(arg1); + len2 = bcTruelen(arg2); + + return(strncmp(arg1+4, arg2+4, Min(len1,len2)) >= 0); +} + +int32 +bpcharcmp(char *arg1, char *arg2) +{ + int len1, len2; + + len1 = bcTruelen(arg1); + len2 = bcTruelen(arg2); + + return(strncmp(arg1+4, arg2+4, Min(len1,len2))); +} + +/***************************************************************************** + * Comparison Functions used for varchar + *****************************************************************************/ + +static int +vcTruelen(char *arg) +{ + char *s = arg + 4; + int i; + int len; + + len = *(int32*)arg - 4; + for(i=0; i < len; i++) { + if (*s++ == '\0') + break; + } + return i; +} + +int32 +varchareq(char *arg1, char *arg2) +{ + int len1, len2; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = vcTruelen(arg1); + len2 = vcTruelen(arg2); + + if (len1!=len2) + return 0; + + return(strncmp(arg1+4, arg2+4, len1) == 0); +} + +int32 +varcharne(char *arg1, char *arg2) +{ + int len1, len2; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = vcTruelen(arg1); + len2 = vcTruelen(arg2); + + if (len1!=len2) + return 1; + + return(strncmp(arg1+4, arg2+4, len1) != 0); +} + +int32 +varcharlt(char *arg1, char *arg2) +{ + int len1, len2; + int cmp; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = vcTruelen(arg1); + len2 = vcTruelen(arg2); + + cmp = strncmp(arg1+4, arg2+4, Min(len1,len2)); + if (cmp == 0) + return (len1<len2); + else + return (cmp < 0); +} + +int32 +varcharle(char *arg1, char *arg2) +{ + int len1, len2; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = vcTruelen(arg1); + len2 = vcTruelen(arg2); + + return(strncmp(arg1+4, arg2+4, Min(len1,len2)) <= 0); +} + +int32 +varchargt(char *arg1, char *arg2) +{ + int len1, len2; + int cmp; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = vcTruelen(arg1); + len2 = vcTruelen(arg2); + + cmp = strncmp(arg1+4, arg2+4, Min(len1,len2)); + if (cmp == 0) + return (len1 > len2); + else + return (cmp > 0); +} + +int32 +varcharge(char *arg1, char *arg2) +{ + int len1, len2; + + if (arg1 == NULL || arg2 == NULL) + return((int32) 0); + len1 = vcTruelen(arg1); + len2 = vcTruelen(arg2); + + return(strncmp(arg1+4, arg2+4, Min(len1,len2)) >= 0); +} + +int32 +varcharcmp(char *arg1, char *arg2) +{ + int len1, len2; + + len1 = vcTruelen(arg1); + len2 = vcTruelen(arg2); + + return(strncmp(arg1+4, arg2+4, Min(len1,len2))); +} + +/***************************************************************************** + * Hash functions (modified from hashtext in access/hash/hashfunc.c) + *****************************************************************************/ + +uint32 hashbpchar(struct varlena *key) +{ + int keylen; + char *keydata; + uint32 n; + int loop; + + keydata = VARDATA(key); + keylen = bcTruelen((char*)key); + +#define HASHC n = *keydata++ + 65599 * n + + n = 0; + if (keylen > 0) { + loop = (keylen + 8 - 1) >> 3; + + switch (keylen & (8 - 1)) { + case 0: + do { /* All fall throughs */ + HASHC; + case 7: + HASHC; + case 6: + HASHC; + case 5: + HASHC; + case 4: + HASHC; + case 3: + HASHC; + case 2: + HASHC; + case 1: + HASHC; + } while (--loop); + } + } + return (n); +} + +uint32 hashvarchar(struct varlena *key) +{ + int keylen; + char *keydata; + uint32 n; + int loop; + + keydata = VARDATA(key); + keylen = vcTruelen((char*)key); + +#define HASHC n = *keydata++ + 65599 * n + + n = 0; + if (keylen > 0) { + loop = (keylen + 8 - 1) >> 3; + + switch (keylen & (8 - 1)) { + case 0: + do { /* All fall throughs */ + HASHC; + case 7: + HASHC; + case 6: + HASHC; + case 5: + HASHC; + case 4: + HASHC; + case 3: + HASHC; + case 2: + HASHC; + case 1: + HASHC; + } while (--loop); + } + } + return (n); +} + |