/*-------------------------------------------------------------------------
*
* char.c
- * Functions for the built-in type "char".
- * Functions for the built-in type "cid".
+ * 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.21 1999/02/13 23:19:05 momjian 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'
+ *
+ * Note that an empty input string will implicitly be converted to \0.
*/
-int32
-charin(char *ch)
+Datum
+charin(PG_FUNCTION_ARGS)
{
- if (ch == NULL)
- return (int32) '\0';
- return (int32) *ch;
+ char *ch = PG_GETARG_CSTRING(0);
+
+ PG_RETURN_CHAR(ch[0]);
}
/*
* charout - converts 'x' to "x"
+ *
+ * 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 *
-charout(int32 ch)
+Datum
+charout(PG_FUNCTION_ARGS)
{
+ char ch = PG_GETARG_CHAR(0);
char *result = (char *) palloc(2);
- result[0] = (char) ch;
+ result[0] = ch;
result[1] = '\0';
- return result;
+ PG_RETURN_CSTRING(result);
}
/*
- * cidin - converts "..." to internal representation.
+ * charrecv - converts external binary format to char
*
- * NOTE: we must not use 'charin' because cid might be a non
- * printable character...
+ * 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.
*/
-int32
-cidin(char *s)
+Datum
+charrecv(PG_FUNCTION_ARGS)
{
- CommandId c;
-
- if (s == NULL)
- c = 0;
- else
- c = atoi(s);
+ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
- return (int32) c;
+ PG_RETURN_CHAR(pq_getmsgbyte(buf));
}
/*
- * cidout - converts a cid to "..."
- *
- * NOTE: we must no use 'charout' because cid might be a non
- * printable character...
+ * charsend - converts char to binary format
*/
-char *
-cidout(int32 c)
+Datum
+charsend(PG_FUNCTION_ARGS)
{
- char *result;
- CommandId c2;
+ char arg1 = PG_GETARG_CHAR(0);
+ StringInfoData buf;
- result = palloc(12);
- c2 = (CommandId) c;
- sprintf(result, "%u", (unsigned) (c2));
- 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;
-}
+/*
+ * 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
-charne(int8 arg1, int8 arg2)
+Datum
+chareq(PG_FUNCTION_ARGS)
{
- return arg1 != arg2;
-}
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
-bool
-charlt(int8 arg1, int8 arg2)
-{
- return (uint8) arg1 < (uint8) arg2;
+ PG_RETURN_BOOL(arg1 == arg2);
}
-bool
-charle(int8 arg1, int8 arg2)
+Datum
+charne(PG_FUNCTION_ARGS)
{
- return (uint8) arg1 <= (uint8) arg2;
-}
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
-bool
-chargt(int8 arg1, int8 arg2)
-{
- return (uint8) arg1 > (uint8) arg2;
+ PG_RETURN_BOOL(arg1 != arg2);
}
-bool
-charge(int8 arg1, int8 arg2)
+Datum
+charlt(PG_FUNCTION_ARGS)
{
- return (uint8) arg1 >= (uint8) arg2;
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
+
+ PG_RETURN_BOOL((uint8) arg1 < (uint8) arg2);
}
-int8
-charpl(int8 arg1, int8 arg2)
+Datum
+charle(PG_FUNCTION_ARGS)
{
- return arg1 + arg2;
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
+
+ PG_RETURN_BOOL((uint8) arg1 <= (uint8) arg2);
}
-int8
-charmi(int8 arg1, int8 arg2)
+Datum
+chargt(PG_FUNCTION_ARGS)
{
- return arg1 - arg2;
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
+
+ PG_RETURN_BOOL((uint8) arg1 > (uint8) arg2);
}
-int8
-charmul(int8 arg1, int8 arg2)
+Datum
+charge(PG_FUNCTION_ARGS)
{
- return arg1 * arg2;
+ char arg1 = PG_GETARG_CHAR(0);
+ char arg2 = PG_GETARG_CHAR(1);
+
+ PG_RETURN_BOOL((uint8) arg1 >= (uint8) arg2);
}
-int8
-chardiv(int8 arg1, int8 arg2)
+
+Datum
+chartoi4(PG_FUNCTION_ARGS)
{
- return arg1 / arg2;
+ char arg1 = PG_GETARG_CHAR(0);
+
+ PG_RETURN_INT32((int32) ((int8) arg1));
}
-bool
-cideq(int8 arg1, int8 arg2)
+Datum
+i4tochar(PG_FUNCTION_ARGS)
{
- return arg1 == arg2;
+ int32 arg1 = PG_GETARG_INT32(0);
+
+ if (arg1 < SCHAR_MIN || arg1 > SCHAR_MAX)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("\"char\" out of range")));
+
+ PG_RETURN_CHAR((int8) arg1);
}
-int8
-text_char(text *arg1)
+
+Datum
+text_char(PG_FUNCTION_ARGS)
{
- return ((int8) *(VARDATA(arg1)));
+ text *arg1 = PG_GETARG_TEXT_PP(0);
+ char result;
+
+ /*
+ * 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';
+
+ PG_RETURN_CHAR(result);
}
-text *
-char_text(int8 arg1)
+Datum
+char_text(PG_FUNCTION_ARGS)
{
- text *result;
+ char arg1 = PG_GETARG_CHAR(0);
+ text *result = palloc(VARHDRSZ + 1);
- result = palloc(VARHDRSZ+1);
- VARSIZE(result) = VARHDRSZ+1;
- *(VARDATA(result)) = arg1;
+ /*
+ * 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')
+ {
+ SET_VARSIZE(result, VARHDRSZ + 1);
+ *(VARDATA(result)) = arg1;
+ }
+ else
+ SET_VARSIZE(result, VARHDRSZ);
- return result;
+ PG_RETURN_TEXT_P(result);
}