1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-12 05:01:15 +03:00
Files
postgres/src/backend/utils/adt/varchar.c
Tom Lane 5cabcfccce Modify array operations to include array's element type OID in the
array header, and to compute sizing and alignment of array elements
the same way normal tuple access operations do --- viz, using the
tupmacs.h macros att_addlength and att_align.  This makes the world
safe for arrays of cstrings or intervals, and should make it much
easier to write array-type-polymorphic functions; as examples see
the cleanups of array_out and contrib/array_iterator.  By Joe Conway
and Tom Lane.
2002-08-26 17:54:02 +00:00

976 lines
21 KiB
C

/*-------------------------------------------------------------------------
*
* varchar.c
* Functions for the built-in types char(n) and varchar(n).
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.91 2002/08/26 17:53:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/hash.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#ifdef MULTIBYTE
#include "mb/pg_wchar.h"
#endif
/*
* 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
* the length of the type from the type itself. I changed (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 these
* types and "text" is that we truncate and possibly blank-pad the string
* at insertion time.)
*
* - ay 6/95
*/
/*****************************************************************************
* bpchar - char() *
*****************************************************************************/
/*
* Convert a C string to CHARACTER internal representation. atttypmod
* is the declared length of the type plus VARHDRSZ.
*
* If the C string is too long, raise an error, unless the extra
* characters are spaces, in which case they're truncated. (per SQL)
*/
Datum
bpcharin(PG_FUNCTION_ARGS)
{
char *s = PG_GETARG_CSTRING(0);
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif
int32 atttypmod = PG_GETARG_INT32(2);
BpChar *result;
char *r;
size_t len,
maxlen;
int i;
#ifdef MULTIBYTE
int charlen; /* number of charcters in the input string */
char *ermsg;
#endif
len = strlen(s);
#ifdef MULTIBYTE
if ((ermsg = pg_verifymbstr(s, len)))
elog(ERROR, "%s", ermsg);
charlen = pg_mbstrlen(s);
#endif
/* If typmod is -1 (or invalid), use the actual string length */
if (atttypmod < (int32) VARHDRSZ)
#ifdef MULTIBYTE
maxlen = charlen;
#else
maxlen = len;
#endif
else
maxlen = atttypmod - VARHDRSZ;
#ifdef MULTIBYTE
if (charlen > maxlen)
#else
if (len > maxlen)
#endif
{
/* Verify that extra characters are spaces, and clip them off */
#ifdef MULTIBYTE
size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
/*
* at this point, len is the actual BYTE length of the input
* string, maxlen is the max number of CHARACTERS allowed for this
* bpchar type.
*/
if (strspn(s + mbmaxlen, " ") == len - mbmaxlen)
len = mbmaxlen;
else
elog(ERROR, "value too long for type character(%d)",
(int) maxlen);
/*
* XXX: at this point, maxlen is the necessary byte length, not
* the number of CHARACTERS!
*/
maxlen = len;
#else
if (strspn(s + maxlen, " ") == len - maxlen)
len = maxlen;
else
elog(ERROR, "value too long for type character(%d)",
(int) maxlen);
#endif
}
#ifdef MULTIBYTE
else
{
/*
* XXX: at this point, maxlen is the necessary byte length, not
* the number of CHARACTERS!
*/
maxlen = len + (maxlen - charlen);
}
#endif
result = palloc(maxlen + VARHDRSZ);
VARATT_SIZEP(result) = maxlen + VARHDRSZ;
r = VARDATA(result);
for (i = 0; i < len; i++)
*r++ = *s++;
/* blank pad the string if necessary */
for (; i < maxlen; i++)
*r++ = ' ';
#ifdef CYR_RECODE
convertstr(VARDATA(result), len, 0);
#endif
PG_RETURN_BPCHAR_P(result);
}
/*
* Convert a CHARACTER value to a C string.
*/
Datum
bpcharout(PG_FUNCTION_ARGS)
{
BpChar *s = PG_GETARG_BPCHAR_P(0);
char *result;
int len;
/* copy and add null term */
len = VARSIZE(s) - VARHDRSZ;
result = (char *) palloc(len + 1);
memcpy(result, VARDATA(s), len);
result[len] = '\0';
#ifdef CYR_RECODE
convertstr(result, len, 1);
#endif
PG_RETURN_CSTRING(result);
}
/*
* Converts a CHARACTER type to the specified size. maxlen is the new
* declared length plus VARHDRSZ bytes. Truncation
* rules see bpcharin() above.
*/
Datum
bpchar(PG_FUNCTION_ARGS)
{
BpChar *source = PG_GETARG_BPCHAR_P(0);
int32 maxlen = PG_GETARG_INT32(1);
BpChar *result;
int32 len;
char *r;
char *s;
int i;
#ifdef MULTIBYTE
int charlen; /* number of charcters in the input string
* + VARHDRSZ */
#endif
len = VARSIZE(source);
#ifdef MULTIBYTE
charlen = pg_mbstrlen_with_len(VARDATA(source), len - VARHDRSZ) + VARHDRSZ;
#endif
/* No work if typmod is invalid or supplied data matches it already */
if (maxlen < (int32) VARHDRSZ || len == maxlen)
PG_RETURN_BPCHAR_P(source);
#ifdef MULTIBYTE
if (charlen > maxlen)
#else
if (len > maxlen)
#endif
{
/* Verify that extra characters are spaces, and clip them off */
#ifdef MULTIBYTE
size_t maxmblen;
maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
maxlen - VARHDRSZ) + VARHDRSZ;
for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
if (*(VARDATA(source) + i) != ' ')
elog(ERROR, "value too long for type character(%d)",
maxlen - VARHDRSZ);
len = maxmblen;
/*
* XXX: at this point, maxlen is the necessary byte
* length+VARHDRSZ, not the number of CHARACTERS!
*/
maxlen = len;
#else
for (i = maxlen - VARHDRSZ; i < len - VARHDRSZ; i++)
if (*(VARDATA(source) + i) != ' ')
elog(ERROR, "value too long for type character(%d)",
maxlen - VARHDRSZ);
len = maxlen;
#endif
}
#ifdef MULTIBYTE
else
{
/*
* XXX: at this point, maxlen is the necessary byte
* length+VARHDRSZ, not the number of CHARACTERS!
*/
maxlen = len + (maxlen - charlen);
}
#endif
s = VARDATA(source);
result = palloc(maxlen);
VARATT_SIZEP(result) = maxlen;
r = VARDATA(result);
for (i = 0; i < len - VARHDRSZ; i++)
*r++ = *s++;
/* blank pad the string if necessary */
for (; i < maxlen - VARHDRSZ; i++)
*r++ = ' ';
PG_RETURN_BPCHAR_P(result);
}
/* _bpchar()
* Converts an array of char() elements to a specific internal length.
* len is the length specified in () plus VARHDRSZ bytes.
*/
Datum
_bpchar(PG_FUNCTION_ARGS)
{
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
int32 len = PG_GETARG_INT32(1);
FunctionCallInfoData locfcinfo;
/*
* Since bpchar() is a built-in function, we should only need to look
* it up once per run.
*/
static FmgrInfo bpchar_finfo;
if (bpchar_finfo.fn_oid == InvalidOid)
fmgr_info_cxt(F_BPCHAR, &bpchar_finfo, TopMemoryContext);
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
locfcinfo.flinfo = &bpchar_finfo;
locfcinfo.nargs = 2;
/* We assume we are "strict" and need not worry about null inputs */
locfcinfo.arg[0] = PointerGetDatum(v);
locfcinfo.arg[1] = Int32GetDatum(len);
return array_map(&locfcinfo, BPCHAROID, BPCHAROID);
}
/* char_bpchar()
* Convert char to bpchar(1).
*/
Datum
char_bpchar(PG_FUNCTION_ARGS)
{
char c = PG_GETARG_CHAR(0);
BpChar *result;
result = (BpChar *) palloc(VARHDRSZ + 1);
VARATT_SIZEP(result) = VARHDRSZ + 1;
*(VARDATA(result)) = c;
PG_RETURN_BPCHAR_P(result);
}
/* bpchar_name()
* Converts a bpchar() type to a NameData type.
*/
Datum
bpchar_name(PG_FUNCTION_ARGS)
{
BpChar *s = PG_GETARG_BPCHAR_P(0);
Name result;
int len;
len = VARSIZE(s) - VARHDRSZ;
/* Truncate to max length for a Name */
if (len >= NAMEDATALEN)
len = NAMEDATALEN - 1;
/* Remove trailing blanks */
while (len > 0)
{
if (*(VARDATA(s) + len - 1) != ' ')
break;
len--;
}
result = (NameData *) palloc(NAMEDATALEN);
memcpy(NameStr(*result), VARDATA(s), len);
/* Now null pad to full length... */
while (len < NAMEDATALEN)
{
*(NameStr(*result) + len) = '\0';
len++;
}
PG_RETURN_NAME(result);
}
/* name_bpchar()
* Converts a NameData type to a bpchar type.
*/
Datum
name_bpchar(PG_FUNCTION_ARGS)
{
Name s = PG_GETARG_NAME(0);
BpChar *result;
int len;
len = strlen(NameStr(*s));
result = (BpChar *) palloc(VARHDRSZ + len);
memcpy(VARDATA(result), NameStr(*s), len);
VARATT_SIZEP(result) = len + VARHDRSZ;
PG_RETURN_BPCHAR_P(result);
}
/*****************************************************************************
* varchar - varchar() *
*****************************************************************************/
/*
* Convert a C string to VARCHAR internal representation. atttypmod
* is the declared length of the type plus VARHDRSZ.
*
* Note that if MULTIBYTE is enabled, atttypmod is regarded as the
* number of characters, rather than number of bytes.
*
* If the C string is too long,
* raise an error, unless the extra characters are spaces, in which
* case they're truncated. (per SQL) */
Datum
varcharin(PG_FUNCTION_ARGS)
{
char *s = PG_GETARG_CSTRING(0);
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif
int32 atttypmod = PG_GETARG_INT32(2);
VarChar *result;
size_t len,
maxlen;
#ifdef MULTIBYTE
char *ermsg;
#endif
len = strlen(s);
#ifdef MULTIBYTE
if ((ermsg = pg_verifymbstr(s, len)))
elog(ERROR, "%s", ermsg);
#endif
maxlen = atttypmod - VARHDRSZ;
if (atttypmod >= (int32) VARHDRSZ && len > maxlen)
{
/* Verify that extra characters are spaces, and clip them off */
#ifdef MULTIBYTE
size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
if (strspn(s + mbmaxlen, " ") == len - mbmaxlen)
len = mbmaxlen;
#else
if (strspn(s + maxlen, " ") == len - maxlen)
len = maxlen;
#endif
else
elog(ERROR, "value too long for type character varying(%d)",
(int) maxlen);
}
result = palloc(len + VARHDRSZ);
VARATT_SIZEP(result) = len + VARHDRSZ;
memcpy(VARDATA(result), s, len);
#ifdef CYR_RECODE
convertstr(VARDATA(result), len, 0);
#endif
PG_RETURN_VARCHAR_P(result);
}
/*
* Convert a VARCHAR value to a C string.
*/
Datum
varcharout(PG_FUNCTION_ARGS)
{
VarChar *s = PG_GETARG_VARCHAR_P(0);
char *result;
int32 len;
/* copy and add null term */
len = VARSIZE(s) - VARHDRSZ;
result = palloc(len + 1);
memcpy(result, VARDATA(s), len);
result[len] = '\0';
#ifdef CYR_RECODE
convertstr(result, len, 1);
#endif
PG_RETURN_CSTRING(result);
}
/*
* Converts a VARCHAR type to the specified size. maxlen is the new
* declared length plus VARHDRSZ bytes. Truncation
* rules see varcharin() above.
*/
Datum
varchar(PG_FUNCTION_ARGS)
{
VarChar *source = PG_GETARG_VARCHAR_P(0);
int32 maxlen = PG_GETARG_INT32(1);
VarChar *result;
int32 len;
int i;
len = VARSIZE(source);
/* No work if typmod is invalid or supplied data fits it already */
if (maxlen < (int32) VARHDRSZ || len <= maxlen)
PG_RETURN_VARCHAR_P(source);
/* only reach here if string is too long... */
#ifdef MULTIBYTE
{
size_t maxmblen;
/* truncate multi-byte string preserving multi-byte boundary */
maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
maxlen - VARHDRSZ) + VARHDRSZ;
for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
if (*(VARDATA(source) + i) != ' ')
elog(ERROR, "value too long for type character varying(%d)",
maxlen - VARHDRSZ);
len = maxmblen;
}
#else
for (i = maxlen - VARHDRSZ; i < len - VARHDRSZ; i++)
if (*(VARDATA(source) + i) != ' ')
elog(ERROR, "value too long for type character varying(%d)",
maxlen - VARHDRSZ);
/* clip extra spaces */
len = maxlen;
#endif
result = palloc(len);
VARATT_SIZEP(result) = len;
memcpy(VARDATA(result), VARDATA(source), len - VARHDRSZ);
PG_RETURN_VARCHAR_P(result);
}
/* _varchar()
* Converts an array of varchar() elements to the specified size.
* len is the length specified in () plus VARHDRSZ bytes.
*/
Datum
_varchar(PG_FUNCTION_ARGS)
{
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
int32 len = PG_GETARG_INT32(1);
FunctionCallInfoData locfcinfo;
/*
* Since varchar() is a built-in function, we should only need to look
* it up once per run.
*/
static FmgrInfo varchar_finfo;
if (varchar_finfo.fn_oid == InvalidOid)
fmgr_info_cxt(F_VARCHAR, &varchar_finfo, TopMemoryContext);
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
locfcinfo.flinfo = &varchar_finfo;
locfcinfo.nargs = 2;
/* We assume we are "strict" and need not worry about null inputs */
locfcinfo.arg[0] = PointerGetDatum(v);
locfcinfo.arg[1] = Int32GetDatum(len);
return array_map(&locfcinfo, VARCHAROID, VARCHAROID);
}
/*****************************************************************************
* Exported functions
*****************************************************************************/
/* "True" length (not counting trailing blanks) of a BpChar */
static int
bcTruelen(BpChar *arg)
{
char *s = VARDATA(arg);
int i;
int len;
len = VARSIZE(arg) - VARHDRSZ;
for (i = len - 1; i >= 0; i--)
{
if (s[i] != ' ')
break;
}
return i + 1;
}
Datum
bpcharlen(PG_FUNCTION_ARGS)
{
BpChar *arg = PG_GETARG_BPCHAR_P(0);
#ifdef MULTIBYTE
/* optimization for single byte encoding */
if (pg_database_encoding_max_length() <= 1)
PG_RETURN_INT32(VARSIZE(arg) - VARHDRSZ);
PG_RETURN_INT32(
pg_mbstrlen_with_len(VARDATA(arg), VARSIZE(arg) - VARHDRSZ)
);
#else
PG_RETURN_INT32(VARSIZE(arg) - VARHDRSZ);
#endif
}
Datum
bpcharoctetlen(PG_FUNCTION_ARGS)
{
BpChar *arg = PG_GETARG_BPCHAR_P(0);
PG_RETURN_INT32(VARSIZE(arg) - VARHDRSZ);
}
/*****************************************************************************
* Comparison Functions used for bpchar
*
* Note: btree indexes need these routines not to leak memory; therefore,
* be careful to free working copies of toasted datums. Most places don't
* need to be so careful.
*****************************************************************************/
Datum
bpchareq(PG_FUNCTION_ARGS)
{
BpChar *arg1 = PG_GETARG_BPCHAR_P(0);
BpChar *arg2 = PG_GETARG_BPCHAR_P(1);
int len1,
len2;
bool result;
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
/* fast path for different-length inputs */
if (len1 != len2)
result = false;
else
result = (varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2) == 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(result);
}
Datum
bpcharne(PG_FUNCTION_ARGS)
{
BpChar *arg1 = PG_GETARG_BPCHAR_P(0);
BpChar *arg2 = PG_GETARG_BPCHAR_P(1);
int len1,
len2;
bool result;
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
/* fast path for different-length inputs */
if (len1 != len2)
result = true;
else
result = (varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2) != 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(result);
}
Datum
bpcharlt(PG_FUNCTION_ARGS)
{
BpChar *arg1 = PG_GETARG_BPCHAR_P(0);
BpChar *arg2 = PG_GETARG_BPCHAR_P(1);
int len1,
len2;
int cmp;
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(cmp < 0);
}
Datum
bpcharle(PG_FUNCTION_ARGS)
{
BpChar *arg1 = PG_GETARG_BPCHAR_P(0);
BpChar *arg2 = PG_GETARG_BPCHAR_P(1);
int len1,
len2;
int cmp;
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(cmp <= 0);
}
Datum
bpchargt(PG_FUNCTION_ARGS)
{
BpChar *arg1 = PG_GETARG_BPCHAR_P(0);
BpChar *arg2 = PG_GETARG_BPCHAR_P(1);
int len1,
len2;
int cmp;
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(cmp > 0);
}
Datum
bpcharge(PG_FUNCTION_ARGS)
{
BpChar *arg1 = PG_GETARG_BPCHAR_P(0);
BpChar *arg2 = PG_GETARG_BPCHAR_P(1);
int len1,
len2;
int cmp;
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(cmp >= 0);
}
Datum
bpcharcmp(PG_FUNCTION_ARGS)
{
BpChar *arg1 = PG_GETARG_BPCHAR_P(0);
BpChar *arg2 = PG_GETARG_BPCHAR_P(1);
int len1,
len2;
int cmp;
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_INT32(cmp);
}
/*
* bpchar needs a specialized hash function because we want to ignore
* trailing blanks in comparisons. (varchar can use plain hashvarlena.)
*/
Datum
hashbpchar(PG_FUNCTION_ARGS)
{
BpChar *key = PG_GETARG_BPCHAR_P(0);
char *keydata;
int keylen;
Datum result;
keydata = VARDATA(key);
keylen = bcTruelen(key);
result = hash_any((unsigned char *) keydata, keylen);
/* Avoid leaking memory for toasted inputs */
PG_FREE_IF_COPY(key, 0);
return result;
}
/*****************************************************************************
* Functions used for varchar
*****************************************************************************/
Datum
varcharlen(PG_FUNCTION_ARGS)
{
VarChar *arg = PG_GETARG_VARCHAR_P(0);
#ifdef MULTIBYTE
/* optimization for single byte encoding */
if (pg_database_encoding_max_length() <= 1)
PG_RETURN_INT32(VARSIZE(arg) - VARHDRSZ);
PG_RETURN_INT32(
pg_mbstrlen_with_len(VARDATA(arg), VARSIZE(arg) - VARHDRSZ)
);
#else
PG_RETURN_INT32(VARSIZE(arg) - VARHDRSZ);
#endif
}
Datum
varcharoctetlen(PG_FUNCTION_ARGS)
{
VarChar *arg = PG_GETARG_VARCHAR_P(0);
PG_RETURN_INT32(VARSIZE(arg) - VARHDRSZ);
}
/*****************************************************************************
* Comparison Functions used for varchar
*
* Note: btree indexes need these routines not to leak memory; therefore,
* be careful to free working copies of toasted datums. Most places don't
* need to be so careful.
*****************************************************************************/
Datum
varchareq(PG_FUNCTION_ARGS)
{
VarChar *arg1 = PG_GETARG_VARCHAR_P(0);
VarChar *arg2 = PG_GETARG_VARCHAR_P(1);
int len1,
len2;
bool result;
len1 = VARSIZE(arg1) - VARHDRSZ;
len2 = VARSIZE(arg2) - VARHDRSZ;
/* fast path for different-length inputs */
if (len1 != len2)
result = false;
else
result = (varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2) == 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(result);
}
Datum
varcharne(PG_FUNCTION_ARGS)
{
VarChar *arg1 = PG_GETARG_VARCHAR_P(0);
VarChar *arg2 = PG_GETARG_VARCHAR_P(1);
int len1,
len2;
bool result;
len1 = VARSIZE(arg1) - VARHDRSZ;
len2 = VARSIZE(arg2) - VARHDRSZ;
/* fast path for different-length inputs */
if (len1 != len2)
result = true;
else
result = (varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2) != 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(result);
}
Datum
varcharlt(PG_FUNCTION_ARGS)
{
VarChar *arg1 = PG_GETARG_VARCHAR_P(0);
VarChar *arg2 = PG_GETARG_VARCHAR_P(1);
int len1,
len2;
int cmp;
len1 = VARSIZE(arg1) - VARHDRSZ;
len2 = VARSIZE(arg2) - VARHDRSZ;
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(cmp < 0);
}
Datum
varcharle(PG_FUNCTION_ARGS)
{
VarChar *arg1 = PG_GETARG_VARCHAR_P(0);
VarChar *arg2 = PG_GETARG_VARCHAR_P(1);
int len1,
len2;
int cmp;
len1 = VARSIZE(arg1) - VARHDRSZ;
len2 = VARSIZE(arg2) - VARHDRSZ;
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(cmp <= 0);
}
Datum
varchargt(PG_FUNCTION_ARGS)
{
VarChar *arg1 = PG_GETARG_VARCHAR_P(0);
VarChar *arg2 = PG_GETARG_VARCHAR_P(1);
int len1,
len2;
int cmp;
len1 = VARSIZE(arg1) - VARHDRSZ;
len2 = VARSIZE(arg2) - VARHDRSZ;
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(cmp > 0);
}
Datum
varcharge(PG_FUNCTION_ARGS)
{
VarChar *arg1 = PG_GETARG_VARCHAR_P(0);
VarChar *arg2 = PG_GETARG_VARCHAR_P(1);
int len1,
len2;
int cmp;
len1 = VARSIZE(arg1) - VARHDRSZ;
len2 = VARSIZE(arg2) - VARHDRSZ;
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_BOOL(cmp >= 0);
}
Datum
varcharcmp(PG_FUNCTION_ARGS)
{
VarChar *arg1 = PG_GETARG_VARCHAR_P(0);
VarChar *arg2 = PG_GETARG_VARCHAR_P(1);
int len1,
len2;
int cmp;
len1 = VARSIZE(arg1) - VARHDRSZ;
len2 = VARSIZE(arg2) - VARHDRSZ;
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
PG_RETURN_INT32(cmp);
}