]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/char.c
Add support for EUI-64 MAC addresses as macaddr8
[postgresql] / src / backend / utils / adt / char.c
index 2984555af022155b6cbd1e0aecc342594075c9dc..1b849e870354d9ca6c54f9175cd1b33b20ab6857 100644 (file)
@@ -1,22 +1,24 @@
 /*-------------------------------------------------------------------------
  *
  * 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);
 }