]> 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 04508129cfdab893af0e7ca1649ef07b842744fe..1b849e870354d9ca6c54f9175cd1b33b20ab6857 100644 (file)
 /*-------------------------------------------------------------------------
  *
- * 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.2 1996/09/10 06:41:34 scrappy 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 */
 
-/***************************************************************************** 
- *   USER I/O ROUTINES                                                       *
- *****************************************************************************/
+#include <limits.h>
 
-/*
- *     charin          - converts "x" to 'x'
- */
-int32 charin(char *ch)
-{
-    if (ch == NULL)
-       return((int32) NULL);
-    return((int32) *ch);
-}
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
 
-/*
- *     charout         - converts 'x' to "x"
- */
-char *charout(int32 ch)
-{
-    char       *result = (char *) palloc(2);
-    
-    result[0] = (char) ch;
-    result[1] = '\0';
-    return(result);
-}
+/*****************************************************************************
+ *      USER I/O ROUTINES                                                                                                               *
+ *****************************************************************************/
 
 /*
- *     cidin   - converts "..." to internal representation.
+ *             charin                  - converts "x" to 'x'
  *
- *     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;
-    
-    if (s==NULL)
-       c = 0;
-    else
-       c = atoi(s);
-    
-    return((int32)c);
+       char       *ch = PG_GETARG_CSTRING(0);
+
+       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;
-    
-    /*
-     * cid is a number between 0 .. 2^16-1, therefore we need at most
-     * 6 chars for the string (5 digits + '\0')
-     * NOTE: print it as an UNSIGNED int!
-     */
-    result = palloc(6);
-    c2 = (CommandId)c;
-    sprintf(result, "%u", (unsigned)(c2));
-    return(result);
+       char            ch = PG_GETARG_CHAR(0);
+       char       *result = (char *) palloc(2);
+
+       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;
-
-    if (s == NULL)
-       return(NULL);
-    result = (char *) palloc(16);
-    memset(result, 0, 16);
-    (void) strncpy(result, s, 16);
-    return(result);
+       StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
+
+       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);
-    
-    memset(result, 0, 17);
-    if (s == NULL) {
-       result[0] = '-';
-    } else {
-       strncpy(result, s, 16);
-    }
-    return(result);
-}
+       char            arg1 = PG_GETARG_CHAR(0);
+       StringInfoData buf;
 
+       pq_begintypsend(&buf);
+       pq_sendbyte(&buf, arg1);
+       PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
 
-/***************************************************************************** 
- *   PUBLIC ROUTINES                                                         *
+/*****************************************************************************
+ *      PUBLIC ROUTINES                                                                                                                 *
  *****************************************************************************/
 
-int32 chareq(int8 arg1, int8 arg2)     { return(arg1 == arg2); }
-int32 charne(int8 arg1, int8 arg2)     { return(arg1 != arg2); }
-#ifdef UNSIGNED_CHAR_TEXT
-int32 charlt(int8 arg1, int8 arg2)    { return((uint8)arg1 <  (uint8)arg2); }
-int32 charle(int8 arg1, int8 arg2)    { return((uint8)arg1 <= (uint8)arg2); }
-int32 chargt(int8 arg1, int8 arg2)    { return((uint8)arg1 >  (uint8)arg2); }
-int32 charge(int8 arg1, int8 arg2)    { return((uint8)arg1 >= (uint8)arg2); }
-#else
-int32 charlt(int8 arg1, int8 arg2)     { return(arg1 < arg2); }
-int32 charle(int8 arg1, int8 arg2)     { return(arg1 <= arg2); }
-int32 chargt(int8 arg1, int8 arg2)     { return(arg1 > arg2); }
-int32 charge(int8 arg1, int8 arg2)     { return(arg1 >= arg2); }
-#endif
-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); }
-
-int32 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?
  */
-int32 char16eq(char *arg1, char *arg2)
-{
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    return(strncmp(arg1, arg2, 16) == 0);
-}
-
-int32 char16ne(char *arg1, char *arg2)
-{
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    return(strncmp(arg1, arg2, 16) != 0);
-}
-
-int32 char16lt(char *arg1, char *arg2)
-{
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    return((int32) (strncmp(arg1, arg2, 16) < 0));
-}
-
-int32 char16le(char *arg1, char *arg2)
-{
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    return((int32) (strncmp(arg1, arg2, 16) <= 0));
-}
-
-int32 char16gt(char *arg1, char *arg2)
-{
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    
-    return((int32) (strncmp(arg1, arg2, 16) > 0));
-}
-
-int32 char16ge(char *arg1, char *arg2)
-{
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    
-    return((int32) (strncmp(arg1, arg2, 16) >= 0));
-}
-
 
-/* ============================== char2 ============================== */
-uint16 char2in(char *s)
+Datum
+chareq(PG_FUNCTION_ARGS)
 {
-    uint16     res;
-    
-    if (s == NULL)
-       return(0);
-    
-    memset((char *) &res, 0, sizeof(res));
-    (void) strncpy((char *) &res, s, 2);
-    return(res);
-}
+       char            arg1 = PG_GETARG_CHAR(0);
+       char            arg2 = PG_GETARG_CHAR(1);
 
-char *char2out(uint16 s)
-{
-    char       *result = (char *) palloc(3);
-    
-    memset(result, 0, 3);
-    (void) strncpy(result, (char *) &s, 2);
-    
-    return(result);
-}
-
-int32 char2eq(uint16 a, uint16 b)
-{
-    return(strncmp((char *) &a, (char *) &b, 2) == 0);
+       PG_RETURN_BOOL(arg1 == arg2);
 }
 
-int32 char2ne(uint16 a, uint16 b)
+Datum
+charne(PG_FUNCTION_ARGS)
 {
-    return(strncmp((char *) &a, (char *) &b, 2) != 0);
-}
-
-int32 char2lt(uint16 a, uint16 b)
-{
-    return(strncmp((char *) &a, (char *) &b, 2) < 0);
-}
+       char            arg1 = PG_GETARG_CHAR(0);
+       char            arg2 = PG_GETARG_CHAR(1);
 
-int32 char2le(uint16 a, uint16 b)
-{
-    return(strncmp((char *) &a, (char *) &b, 2) <= 0);
+       PG_RETURN_BOOL(arg1 != arg2);
 }
 
-int32 char2gt(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);
 
-int32 char2ge(uint16 a, uint16 b)
-{
-    return(strncmp((char *) &a, (char *) &b, 2) >= 0);
+       PG_RETURN_BOOL((uint8) arg1 < (uint8) arg2);
 }
 
-int32 char2cmp(uint16 a, uint16 b)
+Datum
+charle(PG_FUNCTION_ARGS)
 {
-    return (strncmp((char *) &a, (char *) &b, 2));
-}
+       char            arg1 = PG_GETARG_CHAR(0);
+       char            arg2 = PG_GETARG_CHAR(1);
 
-/* ============================== char4 ============================== */
-uint32 char4in(char *s)
-{
-    uint32     res;
-    
-    if (s == NULL)
-       return(0);
-    
-    memset((char *) &res, 0, sizeof(res));
-    (void) strncpy((char *) &res, s, 4);
-    
-    return(res);
+       PG_RETURN_BOOL((uint8) arg1 <= (uint8) arg2);
 }
 
-char *char4out(s)
-     uint32 s;
+Datum
+chargt(PG_FUNCTION_ARGS)
 {
-    char       *result = (char *) palloc(5);
-    
-    memset(result, 0, 5);
-    (void) strncpy(result, (char *) &s, 4);
-    
-    return(result);
-}
+       char            arg1 = PG_GETARG_CHAR(0);
+       char            arg2 = PG_GETARG_CHAR(1);
 
-int32 char4eq(uint32 a, uint32 b)
-{
-    return(strncmp((char *) &a, (char *) &b, 4) == 0);
+       PG_RETURN_BOOL((uint8) arg1 > (uint8) arg2);
 }
 
-int32 char4ne(uint32 a, uint32 b)
+Datum
+charge(PG_FUNCTION_ARGS)
 {
-    return(strncmp((char *) &a, (char *) &b, 4) != 0);
-}
+       char            arg1 = PG_GETARG_CHAR(0);
+       char            arg2 = PG_GETARG_CHAR(1);
 
-int32 char4lt(uint32 a, uint32 b)
-{
-    return(strncmp((char *) &a, (char *) &b, 4) < 0);
+       PG_RETURN_BOOL((uint8) arg1 >= (uint8) arg2);
 }
 
-int32 char4le(uint32 a, uint32 b)
-{
-    return(strncmp((char *) &a, (char *) &b, 4) <= 0);
-}
 
-int32 char4gt(uint32 a, uint32 b)
+Datum
+chartoi4(PG_FUNCTION_ARGS)
 {
-    return(strncmp((char *) &a, (char *) &b, 4) > 0);
-}
+       char            arg1 = PG_GETARG_CHAR(0);
 
-int32 char4ge(uint32 a, uint32 b)
-{
-    return(strncmp((char *) &a, (char *) &b, 4) >= 0);
+       PG_RETURN_INT32((int32) ((int8) arg1));
 }
 
-int32 char4cmp(uint32 a, uint32 b)
+Datum
+i4tochar(PG_FUNCTION_ARGS)
 {
-    return(strncmp((char *) &a, (char *) &b, 4));
-}
+       int32           arg1 = PG_GETARG_INT32(0);
 
-/* ============================== char8 ============================== */
-char *char8in(char *s)
-{
-    char       *result;
-    
-    if (s == NULL)
-       return((char *) NULL);
-    
-    result = (char *) palloc(8);
-    memset(result, 0, 8);
-    (void) strncpy(result, s, 8);
-    return(result);
-}
+       if (arg1 < SCHAR_MIN || arg1 > SCHAR_MAX)
+               ereport(ERROR,
+                               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                errmsg("\"char\" out of range")));
 
-char *char8out(char *s)
-{
-    char       *result = (char *) palloc(9);
-    
-    memset(result, 0, 9);
-    if (s == NULL) {
-       result[0] = '-';
-    } else {
-       strncpy(result, s, 8);
-    }
-    return(result);
+       PG_RETURN_CHAR((int8) arg1);
 }
 
-int32 char8eq(char *arg1, char *arg2)
-{
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    return(strncmp(arg1, arg2, 8) == 0);
-}
 
-int32 char8ne(char *arg1, char *arg2)
+Datum
+text_char(PG_FUNCTION_ARGS)
 {
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    return(strncmp(arg1, arg2, 8) != 0);
-}
+       text       *arg1 = PG_GETARG_TEXT_PP(0);
+       char            result;
 
-int32 char8lt(char *arg1, char *arg2)
-{
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    return(strncmp(arg1, arg2, 8) < 0);
-}
+       /*
+        * 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';
 
-int32 char8le(char *arg1, char *arg2)
-{
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    return(strncmp(arg1, arg2, 8) <= 0);
+       PG_RETURN_CHAR(result);
 }
 
-int32 char8gt(char *arg1, char *arg2)
+Datum
+char_text(PG_FUNCTION_ARGS)
 {
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    return(strncmp(arg1, arg2, 8) > 0);
-}
+       char            arg1 = PG_GETARG_CHAR(0);
+       text       *result = palloc(VARHDRSZ + 1);
 
-int32 char8ge(char *arg1, char *arg2)
-{
-    if (arg1 == NULL || arg2 == NULL)
-       return((int32) 0);
-    return(strncmp(arg1, arg2, 8) >= 0);
-}
+       /*
+        * 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);
 
-int32 char8cmp(char *arg1, char *arg2)
-{
-    return(strncmp(arg1, arg2, 8));
+       PG_RETURN_TEXT_P(result);
 }