1/*-------------------------------------------------------------------------
2 *
3 * char.c
4 * Functions for the built-in type "char" (not to be confused with
5 * bpchar, which is the SQL CHAR(n) type).
6 *
7 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 *
11 * IDENTIFICATION
12 * src/backend/utils/adt/char.c
13 *
14 *-------------------------------------------------------------------------
15 */
16#include "postgres.h"
17
18#include <limits.h>
19
20#include "libpq/pqformat.h"
21#include "utils/builtins.h"
22
23/*****************************************************************************
24 * USER I/O ROUTINES *
25 *****************************************************************************/
26
27/*
28 * charin - converts "x" to 'x'
29 *
30 * Note that an empty input string will implicitly be converted to \0.
31 */
32Datum
33charin(PG_FUNCTION_ARGS)
34{
35 char *ch = PG_GETARG_CSTRING(0);
36
37 PG_RETURN_CHAR(ch[0]);
38}
39
40/*
41 * charout - converts 'x' to "x"
42 *
43 * Note that if the char value is \0, the resulting string will appear
44 * to be empty (null-terminated after zero characters). So this is the
45 * inverse of the charin() function for such data.
46 */
47Datum
48charout(PG_FUNCTION_ARGS)
49{
50 char ch = PG_GETARG_CHAR(0);
51 char *result = (char *) palloc(2);
52
53 result[0] = ch;
54 result[1] = '\0';
55 PG_RETURN_CSTRING(result);
56}
57
58/*
59 * charrecv - converts external binary format to char
60 *
61 * The external representation is one byte, with no character set
62 * conversion. This is somewhat dubious, perhaps, but in many
63 * cases people use char for a 1-byte binary type.
64 */
65Datum
66charrecv(PG_FUNCTION_ARGS)
67{
68 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
69
70 PG_RETURN_CHAR(pq_getmsgbyte(buf));
71}
72
73/*
74 * charsend - converts char to binary format
75 */
76Datum
77charsend(PG_FUNCTION_ARGS)
78{
79 char arg1 = PG_GETARG_CHAR(0);
80 StringInfoData buf;
81
82 pq_begintypsend(&buf);
83 pq_sendbyte(&buf, arg1);
84 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
85}
86
87/*****************************************************************************
88 * PUBLIC ROUTINES *
89 *****************************************************************************/
90
91/*
92 * NOTE: comparisons are done as though char is unsigned (uint8).
93 * Conversions to and from integer are done as though char is signed (int8).
94 *
95 * You wanted consistency?
96 */
97
98Datum
99chareq(PG_FUNCTION_ARGS)
100{
101 char arg1 = PG_GETARG_CHAR(0);
102 char arg2 = PG_GETARG_CHAR(1);
103
104 PG_RETURN_BOOL(arg1 == arg2);
105}
106
107Datum
108charne(PG_FUNCTION_ARGS)
109{
110 char arg1 = PG_GETARG_CHAR(0);
111 char arg2 = PG_GETARG_CHAR(1);
112
113 PG_RETURN_BOOL(arg1 != arg2);
114}
115
116Datum
117charlt(PG_FUNCTION_ARGS)
118{
119 char arg1 = PG_GETARG_CHAR(0);
120 char arg2 = PG_GETARG_CHAR(1);
121
122 PG_RETURN_BOOL((uint8) arg1 < (uint8) arg2);
123}
124
125Datum
126charle(PG_FUNCTION_ARGS)
127{
128 char arg1 = PG_GETARG_CHAR(0);
129 char arg2 = PG_GETARG_CHAR(1);
130
131 PG_RETURN_BOOL((uint8) arg1 <= (uint8) arg2);
132}
133
134Datum
135chargt(PG_FUNCTION_ARGS)
136{
137 char arg1 = PG_GETARG_CHAR(0);
138 char arg2 = PG_GETARG_CHAR(1);
139
140 PG_RETURN_BOOL((uint8) arg1 > (uint8) arg2);
141}
142
143Datum
144charge(PG_FUNCTION_ARGS)
145{
146 char arg1 = PG_GETARG_CHAR(0);
147 char arg2 = PG_GETARG_CHAR(1);
148
149 PG_RETURN_BOOL((uint8) arg1 >= (uint8) arg2);
150}
151
152
153Datum
154chartoi4(PG_FUNCTION_ARGS)
155{
156 char arg1 = PG_GETARG_CHAR(0);
157
158 PG_RETURN_INT32((int32) ((int8) arg1));
159}
160
161Datum
162i4tochar(PG_FUNCTION_ARGS)
163{
164 int32 arg1 = PG_GETARG_INT32(0);
165
166 if (arg1 < SCHAR_MIN || arg1 > SCHAR_MAX)
167 ereport(ERROR,
168 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
169 errmsg("\"char\" out of range")));
170
171 PG_RETURN_CHAR((int8) arg1);
172}
173
174
175Datum
176text_char(PG_FUNCTION_ARGS)
177{
178 text *arg1 = PG_GETARG_TEXT_PP(0);
179 char result;
180
181 /*
182 * An empty input string is converted to \0 (for consistency with charin).
183 * If the input is longer than one character, the excess data is silently
184 * discarded.
185 */
186 if (VARSIZE_ANY_EXHDR(arg1) > 0)
187 result = *(VARDATA_ANY(arg1));
188 else
189 result = '\0';
190
191 PG_RETURN_CHAR(result);
192}
193
194Datum
195char_text(PG_FUNCTION_ARGS)
196{
197 char arg1 = PG_GETARG_CHAR(0);
198 text *result = palloc(VARHDRSZ + 1);
199
200 /*
201 * Convert \0 to an empty string, for consistency with charout (and
202 * because the text stuff doesn't like embedded nulls all that well).
203 */
204 if (arg1 != '\0')
205 {
206 SET_VARSIZE(result, VARHDRSZ + 1);
207 *(VARDATA(result)) = arg1;
208 }
209 else
210 SET_VARSIZE(result, VARHDRSZ);
211
212 PG_RETURN_TEXT_P(result);
213}
214