/*-------------------------------------------------------------------------
*
- * char.c--
- * Functions for the built-in type "char".
- * Functions for the built-in type "cid".
- * Functions for the built-in type "char2".
- * Functions for the built-in type "char4".
- * Functions for the built-in type "char8".
- * Functions for the built-in type "char16".
+ * char.c
+ * Functions for the built-in type "char" (not to be confused with
+ * bpchar, which is the SQL CHAR(n) type).
*
- * Copyright (c) 1994, Regents of the University of California
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/char.c,v 1.14 1997/11/02 15:25:57 vadim Exp $
+ * src/backend/utils/adt/char.c
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
-#include <string.h>
#include "postgres.h"
-#include "utils/palloc.h"
-#include "utils/builtins.h" /* where the declarations go */
+
+#include <limits.h>
+
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
/*****************************************************************************
* USER I/O ROUTINES *
/*
* charin - converts "x" to 'x'
- */
-int32
-charin(char *ch)
-{
- if (ch == NULL)
- return ((int32) NULL);
- return ((int32) *ch);
-}
-
-/*
- * charout - converts 'x' to "x"
- */
-char *
-charout(int32 ch)
-{
- char *result = (char *) palloc(2);
-
- result[0] = (char) ch;
- result[1] = '\0';
- return (result);
-}
-
-/*
- * cidin - converts "..." to internal representation.
*
- * NOTE: we must not use 'charin' because cid might be a non
- * printable character...
+ * Note that an empty input string will implicitly be converted to \0.
*/
-int32
-cidin(char *s)
+Datum
+charin(PG_FUNCTION_ARGS)
{
- CommandId c;
+ char *ch = PG_GETARG_CSTRING(0);
- if (s == NULL)
- c = 0;
- else
- c = atoi(s);
-
- return ((int32) c);
+ PG_RETURN_CHAR(ch[0]);
}
/*
- * cidout - converts a cid to "..."
+ * charout - converts 'x' to "x"
*
- * NOTE: we must no use 'charout' because cid might be a non
- * printable character...
+ * Note that if the char value is \0, the resulting string will appear
+ * to be empty (null-terminated after zero characters). So this is the
+ * inverse of the charin() function for such data.
*/
-char *
-cidout(int32 c)
+Datum
+charout(PG_FUNCTION_ARGS)
{
- char *result;
- CommandId c2;
+ char ch = PG_GETARG_CHAR(0);
+ char *result = (char *) palloc(2);
- result = palloc(12);
- c2 = (CommandId) c;
- sprintf(result, "%u", (unsigned) (c2));
- return (result);
+ result[0] = ch;
+ result[1] = '\0';
+ PG_RETURN_CSTRING(result);
}
/*
- * char16in - converts "..." to internal reprsentation
+ * charrecv - converts external binary format to char
*
- * Note:
- * Currently if strlen(s) < 14, the extra chars are nulls
+ * The external representation is one byte, with no character set
+ * conversion. This is somewhat dubious, perhaps, but in many
+ * cases people use char for a 1-byte binary type.
*/
-char *
-char16in(char *s)
+Datum
+charrecv(PG_FUNCTION_ARGS)
{
- char *result;
+ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
- if (s == NULL)
- return (NULL);
- result = (char *) palloc(16);
- strncpy(result, s, 16);
- return (result);
+ PG_RETURN_CHAR(pq_getmsgbyte(buf));
}
/*
- * char16out - converts internal reprsentation to "..."
+ * charsend - converts char to binary format
*/
-char *
-char16out(char *s)
+Datum
+charsend(PG_FUNCTION_ARGS)
{
- char *result = (char *) palloc(17);
+ char arg1 = PG_GETARG_CHAR(0);
+ StringInfoData buf;
- if (s == NULL)
- {
- result[0] = '-';
- result[1] = '\0';
- }
- else
- StrNCpy(result, s, 17);
- return (result);
+ pq_begintypsend(&buf);
+ pq_sendbyte(&buf, arg1);
+ PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
-
/*****************************************************************************
* PUBLIC ROUTINES *
*****************************************************************************/
-bool
-chareq(int8 arg1, int8 arg2)
-{
- return (arg1 == arg2);
-}
-
-bool
-charne(int8 arg1, int8 arg2)
-{
- return (arg1 != arg2);
-}
-
-bool
-charlt(int8 arg1, int8 arg2)
-{
- return ((uint8) arg1 < (uint8) arg2);
-}
-
-bool
-charle(int8 arg1, int8 arg2)
-{
- return ((uint8) arg1 <= (uint8) arg2);
-}
-
-bool
-chargt(int8 arg1, int8 arg2)
-{
- return ((uint8) arg1 > (uint8) arg2);
-}
-
-bool
-charge(int8 arg1, int8 arg2)
-{
- return ((uint8) arg1 >= (uint8) arg2);
-}
-
-int8
-charpl(int8 arg1, int8 arg2)
-{
- return (arg1 + arg2);
-}
-
-int8
-charmi(int8 arg1, int8 arg2)
-{
- return (arg1 - arg2);
-}
-
-int8
-charmul(int8 arg1, int8 arg2)
-{
- return (arg1 * arg2);
-}
-
-int8
-chardiv(int8 arg1, int8 arg2)
-{
- return (arg1 / arg2);
-}
-
-bool
-cideq(int8 arg1, int8 arg2)
-{
- return (arg1 == arg2);
-}
-
/*
- * char16eq - returns 1 iff arguments are equal
- * char16ne - returns 1 iff arguments are not equal
- *
- * BUGS:
- * Assumes that "xy\0\0a" should be equal to "xy\0b".
- * If not, can do the comparison backwards for efficiency.
- *
- * char16lt - returns 1 iff a < b
- * char16le - returns 1 iff a <= b
- * char16gt - returns 1 iff a < b
- * char16ge - returns 1 iff a <= b
+ * NOTE: comparisons are done as though char is unsigned (uint8).
+ * Conversions to and from integer are done as though char is signed (int8).
*
+ * You wanted consistency?
*/
-bool
-char16eq(char *arg1, char *arg2)
-{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
- return (strncmp(arg1, arg2, 16) == 0);
-}
-bool
-char16ne(char *arg1, char *arg2)
+Datum
+chareq(PG_FUNCTION_ARGS)
{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
- return (strncmp(arg1, arg2, 16) != 0);
-}
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
-bool
-char16lt(char *arg1, char *arg2)
-{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
- return (strncmp(arg1, arg2, 16) < 0);
+ PG_RETURN_BOOL(arg1 == arg2);
}
-bool
-char16le(char *arg1, char *arg2)
+Datum
+charne(PG_FUNCTION_ARGS)
{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
- return (strncmp(arg1, arg2, 16) <= 0);
-}
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
-bool
-char16gt(char *arg1, char *arg2)
-{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
-
- return (strncmp(arg1, arg2, 16) > 0);
-}
-
-bool
-char16ge(char *arg1, char *arg2)
-{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
-
- return (strncmp(arg1, arg2, 16) >= 0);
-}
-
-
-/* ============================== char2 ============================== */
-uint16
-char2in(char *s)
-{
- uint16 res;
-
- if (s == NULL)
- return (0);
-
- strncpy((char *) &res, s, 2);
- return (res);
-}
-
-char *
-char2out(uint16 s)
-{
- char *result = (char *) palloc(3);
-
- StrNCpy(result, (char *) &s, 3);
-
- return (result);
-}
-
-bool
-char2eq(uint16 a, uint16 b)
-{
- return (strncmp((char *) &a, (char *) &b, 2) == 0);
-}
-
-bool
-char2ne(uint16 a, uint16 b)
-{
- return (strncmp((char *) &a, (char *) &b, 2) != 0);
-}
-
-bool
-char2lt(uint16 a, uint16 b)
-{
- return (strncmp((char *) &a, (char *) &b, 2) < 0);
+ PG_RETURN_BOOL(arg1 != arg2);
}
-bool
-char2le(uint16 a, uint16 b)
+Datum
+charlt(PG_FUNCTION_ARGS)
{
- return (strncmp((char *) &a, (char *) &b, 2) <= 0);
-}
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
-bool
-char2gt(uint16 a, uint16 b)
-{
- return (strncmp((char *) &a, (char *) &b, 2) > 0);
+ PG_RETURN_BOOL((uint8) arg1 < (uint8) arg2);
}
-bool
-char2ge(uint16 a, uint16 b)
+Datum
+charle(PG_FUNCTION_ARGS)
{
- return (strncmp((char *) &a, (char *) &b, 2) >= 0);
-}
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
-int32
-char2cmp(uint16 a, uint16 b)
-{
- return (strncmp((char *) &a, (char *) &b, 2));
+ PG_RETURN_BOOL((uint8) arg1 <= (uint8) arg2);
}
-/* ============================== char4 ============================== */
-uint32
-char4in(char *s)
+Datum
+chargt(PG_FUNCTION_ARGS)
{
- uint32 res;
-
- if (s == NULL)
- return (0);
-
- strncpy((char *) &res, s, 4);
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
- return (res);
+ PG_RETURN_BOOL((uint8) arg1 > (uint8) arg2);
}
-char *
-char4out(s)
-uint32 s;
+Datum
+charge(PG_FUNCTION_ARGS)
{
- char *result = (char *) palloc(5);
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
- StrNCpy(result, (char *) &s, 5);
-
- return (result);
+ PG_RETURN_BOOL((uint8) arg1 >= (uint8) arg2);
}
-bool
-char4eq(uint32 a, uint32 b)
-{
- return (strncmp((char *) &a, (char *) &b, 4) == 0);
-}
-bool
-char4ne(uint32 a, uint32 b)
+Datum
+chartoi4(PG_FUNCTION_ARGS)
{
- return (strncmp((char *) &a, (char *) &b, 4) != 0);
-}
+ char arg1 = PG_GETARG_CHAR(0);
-bool
-char4lt(uint32 a, uint32 b)
-{
- return (strncmp((char *) &a, (char *) &b, 4) < 0);
+ PG_RETURN_INT32((int32) ((int8) arg1));
}
-bool
-char4le(uint32 a, uint32 b)
+Datum
+i4tochar(PG_FUNCTION_ARGS)
{
- return (strncmp((char *) &a, (char *) &b, 4) <= 0);
-}
+ int32 arg1 = PG_GETARG_INT32(0);
-bool
-char4gt(uint32 a, uint32 b)
-{
- return (strncmp((char *) &a, (char *) &b, 4) > 0);
-}
+ if (arg1 < SCHAR_MIN || arg1 > SCHAR_MAX)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("\"char\" out of range")));
-bool
-char4ge(uint32 a, uint32 b)
-{
- return (strncmp((char *) &a, (char *) &b, 4) >= 0);
+ PG_RETURN_CHAR((int8) arg1);
}
-int32
-char4cmp(uint32 a, uint32 b)
-{
- return (strncmp((char *) &a, (char *) &b, 4));
-}
-/* ============================== char8 ============================== */
-char *
-char8in(char *s)
+Datum
+text_char(PG_FUNCTION_ARGS)
{
- char *result;
+ text *arg1 = PG_GETARG_TEXT_PP(0);
+ char result;
- if (s == NULL)
- return ((char *) NULL);
+ /*
+ * An empty input string is converted to \0 (for consistency with charin).
+ * If the input is longer than one character, the excess data is silently
+ * discarded.
+ */
+ if (VARSIZE_ANY_EXHDR(arg1) > 0)
+ result = *(VARDATA_ANY(arg1));
+ else
+ result = '\0';
- result = (char *) palloc(8);
- strncpy(result, s, 8);
- return (result);
+ PG_RETURN_CHAR(result);
}
-char *
-char8out(char *s)
+Datum
+char_text(PG_FUNCTION_ARGS)
{
- char *result = (char *) palloc(9);
+ char arg1 = PG_GETARG_CHAR(0);
+ text *result = palloc(VARHDRSZ + 1);
- if (s == NULL)
+ /*
+ * Convert \0 to an empty string, for consistency with charout (and
+ * because the text stuff doesn't like embedded nulls all that well).
+ */
+ if (arg1 != '\0')
{
- result[0] = '-';
- result[1] = '\0';
+ SET_VARSIZE(result, VARHDRSZ + 1);
+ *(VARDATA(result)) = arg1;
}
else
- StrNCpy(result, s, 9);
- return (result);
-}
-
-bool
-char8eq(char *arg1, char *arg2)
-{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
- return (strncmp(arg1, arg2, 8) == 0);
-}
+ SET_VARSIZE(result, VARHDRSZ);
-bool
-char8ne(char *arg1, char *arg2)
-{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
- return (strncmp(arg1, arg2, 8) != 0);
-}
-
-bool
-char8lt(char *arg1, char *arg2)
-{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
- return (strncmp(arg1, arg2, 8) < 0);
-}
-
-bool
-char8le(char *arg1, char *arg2)
-{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
- return (strncmp(arg1, arg2, 8) <= 0);
-}
-
-bool
-char8gt(char *arg1, char *arg2)
-{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
- return (strncmp(arg1, arg2, 8) > 0);
-}
-
-bool
-char8ge(char *arg1, char *arg2)
-{
- if (arg1 == NULL || arg2 == NULL)
- return ((bool) 0);
- return (strncmp(arg1, arg2, 8) >= 0);
-}
-
-int32
-char8cmp(char *arg1, char *arg2)
-{
- return (strncmp(arg1, arg2, 8));
+ PG_RETURN_TEXT_P(result);
}