1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00
Files
postgres/src/backend/utils/adt/varchar.c
Marc G. Fournier 491b9b89c4 The patch that is applied at the end of the email makes sure that these
conditions are always met. The patch can be applied to any version
of Postgres95 from 1.02 to 1.05. After applying the patch, queries
using indices on bpchar and varchar fields should (hopefully ;-) )
always return the same tuple set regardless to the fact whether
indices are used or not.

Submitted by: Gerhard Reithofer <tbr_laa@AON.AT>
1996-08-26 20:38:52 +00:00

537 lines
11 KiB
C

/*-------------------------------------------------------------------------
*
* 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.3 1996/08/26 20:38:52 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;
}
#ifndef OPENLINK_PATCHES
if (len < 1 || len > 4096)
elog(WARN, "bpcharin: length of char() must be between 1 and 4096");
#else
if (len > 4096)
elog(WARN, "bpcharin: length of char() must be less than 4096");
#endif
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;
}
#ifndef OPENLINK_PATCHES
if (len < 1 || len > 4096)
elog(WARN, "bpcharin: length of char() must be between 1 and 4096");
#else
if (len > 4096)
elog(WARN, "varcharin: length of char() must be less than 4096");
#endif
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;
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 (0 == cmp)
return (int32)(len1 <= len2 ? 1 : 0);
else
return (int32)(cmp <= 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;
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 (0 == cmp)
return (int32)(len1 >= len2 ? 1 : 0);
else
return (int32)(cmp >= 0);
}
int32
bpcharcmp(char *arg1, char *arg2)
{
int len1, len2;
int cmp;
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
if ((0 == cmp) && (len1 != len2))
return (int32)(len1 < len2 ? -1 : 1);
else
return cmp;
}
/*****************************************************************************
* 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;
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 (0 == cmp)
return (int32)( len1 <= len2 ? 1 : 0);
else
return (int32)(cmp <= 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;
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 (0 == cmp)
return (int32)(len1 >= len2 ? 1 : 0);
else
return (int32)(cmp >= 0);
}
int32
varcharcmp(char *arg1, char *arg2)
{
int len1, len2;
int cmp;
len1 = vcTruelen(arg1);
len2 = vcTruelen(arg2);
cmp = (strncmp(arg1+4, arg2+4, Min(len1,len2)));
if ((0 == cmp) && (len1 != len2))
return (int32)(len1 < len2 ? -1 : 1);
else
return (int32)(cmp);
}
/*****************************************************************************
* 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);
}