Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * bytea.c
4 : : * Functions for the bytea type.
5 : : *
6 : : * Portions Copyright (c) 2025, PostgreSQL Global Development Group
7 : : *
8 : : *
9 : : * IDENTIFICATION
10 : : * src/backend/utils/adt/bytea.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : :
15 : : #include "postgres.h"
16 : :
17 : : #include "access/detoast.h"
18 : : #include "catalog/pg_collation_d.h"
19 : : #include "catalog/pg_type_d.h"
20 : : #include "common/int.h"
21 : : #include "fmgr.h"
22 : : #include "libpq/pqformat.h"
23 : : #include "port/pg_bitutils.h"
24 : : #include "utils/builtins.h"
25 : : #include "utils/bytea.h"
26 : : #include "utils/fmgrprotos.h"
27 : : #include "utils/memutils.h"
28 : : #include "utils/sortsupport.h"
29 : : #include "utils/varlena.h"
30 : : #include "varatt.h"
31 : :
32 : : /* GUC variable */
33 : : int bytea_output = BYTEA_OUTPUT_HEX;
34 : :
35 : : static bytea *bytea_catenate(bytea *t1, bytea *t2);
36 : : static bytea *bytea_substring(Datum str, int S, int L,
37 : : bool length_not_specified);
38 : : static bytea *bytea_overlay(bytea *t1, bytea *t2, int sp, int sl);
39 : :
40 : : /*
41 : : * bytea_catenate
42 : : * Guts of byteacat(), broken out so it can be used by other functions
43 : : *
44 : : * Arguments can be in short-header form, but not compressed or out-of-line
45 : : */
46 : : static bytea *
66 michael@paquier.xyz 47 :GNC 779 : bytea_catenate(bytea *t1, bytea *t2)
48 : : {
49 : : bytea *result;
50 : : int len1,
51 : : len2,
52 : : len;
53 : : char *ptr;
54 : :
55 : 779 : len1 = VARSIZE_ANY_EXHDR(t1);
56 : 779 : len2 = VARSIZE_ANY_EXHDR(t2);
57 : :
58 : : /* paranoia ... probably should throw error instead? */
59 [ - + ]: 779 : if (len1 < 0)
66 michael@paquier.xyz 60 :UNC 0 : len1 = 0;
66 michael@paquier.xyz 61 [ - + ]:GNC 779 : if (len2 < 0)
66 michael@paquier.xyz 62 :UNC 0 : len2 = 0;
63 : :
66 michael@paquier.xyz 64 :GNC 779 : len = len1 + len2 + VARHDRSZ;
65 : 779 : result = (bytea *) palloc(len);
66 : :
67 : : /* Set size of result string... */
68 : 779 : SET_VARSIZE(result, len);
69 : :
70 : : /* Fill data field of result string... */
71 : 779 : ptr = VARDATA(result);
72 [ + - ]: 779 : if (len1 > 0)
73 : 779 : memcpy(ptr, VARDATA_ANY(t1), len1);
74 [ + + ]: 779 : if (len2 > 0)
75 : 770 : memcpy(ptr + len1, VARDATA_ANY(t2), len2);
76 : :
77 : 779 : return result;
78 : : }
79 : :
80 : : #define PG_STR_GET_BYTEA(str_) \
81 : : DatumGetByteaPP(DirectFunctionCall1(byteain, CStringGetDatum(str_)))
82 : :
83 : : static bytea *
84 : 2029 : bytea_substring(Datum str,
85 : : int S,
86 : : int L,
87 : : bool length_not_specified)
88 : : {
89 : : int32 S1; /* adjusted start position */
90 : : int32 L1; /* adjusted substring length */
91 : : int32 E; /* end position */
92 : :
93 : : /*
94 : : * The logic here should generally match text_substring().
95 : : */
96 : 2029 : S1 = Max(S, 1);
97 : :
98 [ + + ]: 2029 : if (length_not_specified)
99 : : {
100 : : /*
101 : : * Not passed a length - DatumGetByteaPSlice() grabs everything to the
102 : : * end of the string if we pass it a negative value for length.
103 : : */
104 : 1977 : L1 = -1;
105 : : }
106 [ + + ]: 52 : else if (L < 0)
107 : : {
108 : : /* SQL99 says to throw an error for E < S, i.e., negative length */
109 [ + - ]: 6 : ereport(ERROR,
110 : : (errcode(ERRCODE_SUBSTRING_ERROR),
111 : : errmsg("negative substring length not allowed")));
112 : : L1 = -1; /* silence stupider compilers */
113 : : }
114 [ + + ]: 46 : else if (pg_add_s32_overflow(S, L, &E))
115 : : {
116 : : /*
117 : : * L could be large enough for S + L to overflow, in which case the
118 : : * substring must run to end of string.
119 : : */
120 : 3 : L1 = -1;
121 : : }
122 : : else
123 : : {
124 : : /*
125 : : * A zero or negative value for the end position can happen if the
126 : : * start was negative or one. SQL99 says to return a zero-length
127 : : * string.
128 : : */
129 [ - + ]: 43 : if (E < 1)
66 michael@paquier.xyz 130 :UNC 0 : return PG_STR_GET_BYTEA("");
131 : :
66 michael@paquier.xyz 132 :GNC 43 : L1 = E - S1;
133 : : }
134 : :
135 : : /*
136 : : * If the start position is past the end of the string, SQL99 says to
137 : : * return a zero-length string -- DatumGetByteaPSlice() will do that for
138 : : * us. We need only convert S1 to zero-based starting position.
139 : : */
140 : 2023 : return DatumGetByteaPSlice(str, S1 - 1, L1);
141 : : }
142 : :
143 : : static bytea *
144 : 9 : bytea_overlay(bytea *t1, bytea *t2, int sp, int sl)
145 : : {
146 : : bytea *result;
147 : : bytea *s1;
148 : : bytea *s2;
149 : : int sp_pl_sl;
150 : :
151 : : /*
152 : : * Check for possible integer-overflow cases. For negative sp, throw a
153 : : * "substring length" error because that's what should be expected
154 : : * according to the spec's definition of OVERLAY().
155 : : */
156 [ - + ]: 9 : if (sp <= 0)
66 michael@paquier.xyz 157 [ # # ]:UNC 0 : ereport(ERROR,
158 : : (errcode(ERRCODE_SUBSTRING_ERROR),
159 : : errmsg("negative substring length not allowed")));
66 michael@paquier.xyz 160 [ - + ]:GNC 9 : if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
66 michael@paquier.xyz 161 [ # # ]:UNC 0 : ereport(ERROR,
162 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
163 : : errmsg("integer out of range")));
164 : :
66 michael@paquier.xyz 165 :GNC 9 : s1 = bytea_substring(PointerGetDatum(t1), 1, sp - 1, false);
166 : 9 : s2 = bytea_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
167 : 9 : result = bytea_catenate(s1, t2);
168 : 9 : result = bytea_catenate(result, s2);
169 : :
170 : 9 : return result;
171 : : }
172 : :
173 : : /*****************************************************************************
174 : : * USER I/O ROUTINES *
175 : : *****************************************************************************/
176 : :
177 : : #define VAL(CH) ((CH) - '0')
178 : : #define DIG(VAL) ((VAL) + '0')
179 : :
180 : : /*
181 : : * byteain - converts from printable representation of byte array
182 : : *
183 : : * Non-printable characters must be passed as '\nnn' (octal) and are
184 : : * converted to internal form. '\' must be passed as '\\'.
185 : : */
186 : : Datum
187 : 692927 : byteain(PG_FUNCTION_ARGS)
188 : : {
189 : 692927 : char *inputText = PG_GETARG_CSTRING(0);
190 : 692927 : Node *escontext = fcinfo->context;
50 tgl@sss.pgh.pa.us 191 : 692927 : size_t len = strlen(inputText);
192 : : size_t bc;
193 : : char *tp;
194 : : char *rp;
195 : : bytea *result;
196 : :
197 : : /* Recognize hex input */
66 michael@paquier.xyz 198 [ + + + + ]: 692927 : if (inputText[0] == '\\' && inputText[1] == 'x')
199 : : {
200 : 55828 : bc = (len - 2) / 2 + VARHDRSZ; /* maximum possible length */
201 : 55828 : result = palloc(bc);
202 : 55828 : bc = hex_decode_safe(inputText + 2, len - 2, VARDATA(result),
203 : : escontext);
204 : 55822 : SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */
205 : :
206 : 55822 : PG_RETURN_BYTEA_P(result);
207 : : }
208 : :
209 : : /* Else, it's the traditional escaped style */
50 tgl@sss.pgh.pa.us 210 : 637099 : result = (bytea *) palloc(len + VARHDRSZ); /* maximum possible length */
211 : :
66 michael@paquier.xyz 212 : 637099 : tp = inputText;
213 : 637099 : rp = VARDATA(result);
214 [ + + ]: 4783820 : while (*tp != '\0')
215 : : {
216 [ + + ]: 4146727 : if (tp[0] != '\\')
217 : 4146282 : *rp++ = *tp++;
50 tgl@sss.pgh.pa.us 218 [ + - + + ]: 445 : else if ((tp[1] >= '0' && tp[1] <= '3') &&
66 michael@paquier.xyz 219 [ + - + - ]: 433 : (tp[2] >= '0' && tp[2] <= '7') &&
220 [ + - + - ]: 433 : (tp[3] >= '0' && tp[3] <= '7'))
221 : 433 : {
222 : : int v;
223 : :
50 tgl@sss.pgh.pa.us 224 : 433 : v = VAL(tp[1]);
225 : 433 : v <<= 3;
226 : 433 : v += VAL(tp[2]);
227 : 433 : v <<= 3;
228 : 433 : *rp++ = v + VAL(tp[3]);
229 : :
66 michael@paquier.xyz 230 : 433 : tp += 4;
231 : : }
50 tgl@sss.pgh.pa.us 232 [ + + ]: 12 : else if (tp[1] == '\\')
233 : : {
66 michael@paquier.xyz 234 : 6 : *rp++ = '\\';
235 : 6 : tp += 2;
236 : : }
237 : : else
238 : : {
239 : : /*
240 : : * one backslash, not followed by another or ### valid octal
241 : : */
242 [ + - ]: 6 : ereturn(escontext, (Datum) 0,
243 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
244 : : errmsg("invalid input syntax for type %s", "bytea")));
245 : : }
246 : : }
247 : :
50 tgl@sss.pgh.pa.us 248 : 637093 : bc = rp - VARDATA(result); /* actual length */
249 : 637093 : SET_VARSIZE(result, bc + VARHDRSZ);
250 : :
66 michael@paquier.xyz 251 : 637093 : PG_RETURN_BYTEA_P(result);
252 : : }
253 : :
254 : : /*
255 : : * byteaout - converts to printable representation of byte array
256 : : *
257 : : * In the traditional escaped format, non-printable characters are
258 : : * printed as '\nnn' (octal) and '\' as '\\'.
259 : : */
260 : : Datum
261 : 280201 : byteaout(PG_FUNCTION_ARGS)
262 : : {
263 : 280201 : bytea *vlena = PG_GETARG_BYTEA_PP(0);
264 : : char *result;
265 : : char *rp;
266 : :
267 [ + + ]: 280201 : if (bytea_output == BYTEA_OUTPUT_HEX)
268 : : {
269 : : /* Print hex format */
270 : 280007 : rp = result = palloc(VARSIZE_ANY_EXHDR(vlena) * 2 + 2 + 1);
271 : 280007 : *rp++ = '\\';
272 : 280007 : *rp++ = 'x';
273 : 280007 : rp += hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp);
274 : : }
275 [ + - ]: 194 : else if (bytea_output == BYTEA_OUTPUT_ESCAPE)
276 : : {
277 : : /* Print traditional escaped format */
278 : : char *vp;
279 : : uint64 len;
280 : : int i;
281 : :
282 : 194 : len = 1; /* empty string has 1 char */
283 : 194 : vp = VARDATA_ANY(vlena);
284 [ + + ]: 108855 : for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++)
285 : : {
286 [ + + ]: 108661 : if (*vp == '\\')
287 : 3 : len += 2;
288 [ + + + + ]: 108658 : else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e)
289 : 246 : len += 4;
290 : : else
291 : 108412 : len++;
292 : : }
293 : :
294 : : /*
295 : : * In principle len can't overflow uint32 if the input fit in 1GB, but
296 : : * for safety let's check rather than relying on palloc's internal
297 : : * check.
298 : : */
299 [ - + ]: 194 : if (len > MaxAllocSize)
66 michael@paquier.xyz 300 [ # # ]:UNC 0 : ereport(ERROR,
301 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
302 : : errmsg_internal("result of bytea output conversion is too large")));
66 michael@paquier.xyz 303 :GNC 194 : rp = result = (char *) palloc(len);
304 : :
305 : 194 : vp = VARDATA_ANY(vlena);
306 [ + + ]: 108855 : for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++)
307 : : {
308 [ + + ]: 108661 : if (*vp == '\\')
309 : : {
310 : 3 : *rp++ = '\\';
311 : 3 : *rp++ = '\\';
312 : : }
313 [ + + + + ]: 108658 : else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e)
314 : 246 : {
315 : : int val; /* holds unprintable chars */
316 : :
317 : 246 : val = *vp;
318 : 246 : rp[0] = '\\';
319 : 246 : rp[3] = DIG(val & 07);
320 : 246 : val >>= 3;
321 : 246 : rp[2] = DIG(val & 07);
322 : 246 : val >>= 3;
323 : 246 : rp[1] = DIG(val & 03);
324 : 246 : rp += 4;
325 : : }
326 : : else
327 : 108412 : *rp++ = *vp;
328 : : }
329 : : }
330 : : else
331 : : {
66 michael@paquier.xyz 332 [ # # ]:UNC 0 : elog(ERROR, "unrecognized \"bytea_output\" setting: %d",
333 : : bytea_output);
334 : : rp = result = NULL; /* keep compiler quiet */
335 : : }
66 michael@paquier.xyz 336 :GNC 280201 : *rp = '\0';
337 : 280201 : PG_RETURN_CSTRING(result);
338 : : }
339 : :
340 : : /*
341 : : * bytearecv - converts external binary format to bytea
342 : : */
343 : : Datum
344 : 53842 : bytearecv(PG_FUNCTION_ARGS)
345 : : {
346 : 53842 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
347 : : bytea *result;
348 : : int nbytes;
349 : :
350 : 53842 : nbytes = buf->len - buf->cursor;
351 : 53842 : result = (bytea *) palloc(nbytes + VARHDRSZ);
352 : 53842 : SET_VARSIZE(result, nbytes + VARHDRSZ);
353 : 53842 : pq_copymsgbytes(buf, VARDATA(result), nbytes);
354 : 53842 : PG_RETURN_BYTEA_P(result);
355 : : }
356 : :
357 : : /*
358 : : * byteasend - converts bytea to binary format
359 : : *
360 : : * This is a special case: just copy the input...
361 : : */
362 : : Datum
363 : 34496 : byteasend(PG_FUNCTION_ARGS)
364 : : {
365 : 34496 : bytea *vlena = PG_GETARG_BYTEA_P_COPY(0);
366 : :
367 : 34496 : PG_RETURN_BYTEA_P(vlena);
368 : : }
369 : :
370 : : Datum
371 : 129387 : bytea_string_agg_transfn(PG_FUNCTION_ARGS)
372 : : {
373 : : StringInfo state;
374 : :
375 [ + + ]: 129387 : state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
376 : :
377 : : /* Append the value unless null, preceding it with the delimiter. */
378 [ + + ]: 129387 : if (!PG_ARGISNULL(1))
379 : : {
380 : 121887 : bytea *value = PG_GETARG_BYTEA_PP(1);
381 : 121887 : bool isfirst = false;
382 : :
383 : : /*
384 : : * You might think we can just throw away the first delimiter, however
385 : : * we must keep it as we may be a parallel worker doing partial
386 : : * aggregation building a state to send to the main process. We need
387 : : * to keep the delimiter of every aggregation so that the combine
388 : : * function can properly join up the strings of two separately
389 : : * partially aggregated results. The first delimiter is only stripped
390 : : * off in the final function. To know how much to strip off the front
391 : : * of the string, we store the length of the first delimiter in the
392 : : * StringInfo's cursor field, which we don't otherwise need here.
393 : : */
394 [ + + ]: 121887 : if (state == NULL)
395 : : {
396 : : MemoryContext aggcontext;
397 : : MemoryContext oldcontext;
398 : :
399 [ - + ]: 104 : if (!AggCheckCallContext(fcinfo, &aggcontext))
400 : : {
401 : : /* cannot be called directly because of internal-type argument */
66 michael@paquier.xyz 402 [ # # ]:UNC 0 : elog(ERROR, "bytea_string_agg_transfn called in non-aggregate context");
403 : : }
404 : :
405 : : /*
406 : : * Create state in aggregate context. It'll stay there across
407 : : * subsequent calls.
408 : : */
66 michael@paquier.xyz 409 :GNC 104 : oldcontext = MemoryContextSwitchTo(aggcontext);
410 : 104 : state = makeStringInfo();
411 : 104 : MemoryContextSwitchTo(oldcontext);
412 : :
413 : 104 : isfirst = true;
414 : : }
415 : :
416 [ + + ]: 121887 : if (!PG_ARGISNULL(2))
417 : : {
418 : 121881 : bytea *delim = PG_GETARG_BYTEA_PP(2);
419 : :
420 : 121881 : appendBinaryStringInfo(state, VARDATA_ANY(delim),
421 : 121881 : VARSIZE_ANY_EXHDR(delim));
422 [ + + ]: 121881 : if (isfirst)
423 : 101 : state->cursor = VARSIZE_ANY_EXHDR(delim);
424 : : }
425 : :
426 : 121887 : appendBinaryStringInfo(state, VARDATA_ANY(value),
427 : 121887 : VARSIZE_ANY_EXHDR(value));
428 : : }
429 : :
430 : : /*
431 : : * The transition type for string_agg() is declared to be "internal",
432 : : * which is a pass-by-value type the same size as a pointer.
433 : : */
434 [ + + ]: 129387 : if (state)
435 : 129362 : PG_RETURN_POINTER(state);
436 : 25 : PG_RETURN_NULL();
437 : : }
438 : :
439 : : Datum
440 : 77 : bytea_string_agg_finalfn(PG_FUNCTION_ARGS)
441 : : {
442 : : StringInfo state;
443 : :
444 : : /* cannot be called directly because of internal-type argument */
445 [ - + ]: 77 : Assert(AggCheckCallContext(fcinfo, NULL));
446 : :
447 [ + + ]: 77 : state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
448 : :
449 [ + + ]: 77 : if (state != NULL)
450 : : {
451 : : /* As per comment in transfn, strip data before the cursor position */
452 : : bytea *result;
453 : 74 : int strippedlen = state->len - state->cursor;
454 : :
455 : 74 : result = (bytea *) palloc(strippedlen + VARHDRSZ);
456 : 74 : SET_VARSIZE(result, strippedlen + VARHDRSZ);
457 : 74 : memcpy(VARDATA(result), &state->data[state->cursor], strippedlen);
458 : 74 : PG_RETURN_BYTEA_P(result);
459 : : }
460 : : else
461 : 3 : PG_RETURN_NULL();
462 : : }
463 : :
464 : : /*-------------------------------------------------------------
465 : : * byteaoctetlen
466 : : *
467 : : * get the number of bytes contained in an instance of type 'bytea'
468 : : *-------------------------------------------------------------
469 : : */
470 : : Datum
471 : 325 : byteaoctetlen(PG_FUNCTION_ARGS)
472 : : {
473 : 325 : Datum str = PG_GETARG_DATUM(0);
474 : :
475 : : /* We need not detoast the input at all */
476 : 325 : PG_RETURN_INT32(toast_raw_datum_size(str) - VARHDRSZ);
477 : : }
478 : :
479 : : /*
480 : : * byteacat -
481 : : * takes two bytea* and returns a bytea* that is the concatenation of
482 : : * the two.
483 : : *
484 : : * Cloned from textcat and modified as required.
485 : : */
486 : : Datum
487 : 761 : byteacat(PG_FUNCTION_ARGS)
488 : : {
489 : 761 : bytea *t1 = PG_GETARG_BYTEA_PP(0);
490 : 761 : bytea *t2 = PG_GETARG_BYTEA_PP(1);
491 : :
492 : 761 : PG_RETURN_BYTEA_P(bytea_catenate(t1, t2));
493 : : }
494 : :
495 : : /*
496 : : * byteaoverlay
497 : : * Replace specified substring of first string with second
498 : : *
499 : : * The SQL standard defines OVERLAY() in terms of substring and concatenation.
500 : : * This code is a direct implementation of what the standard says.
501 : : */
502 : : Datum
503 : 3 : byteaoverlay(PG_FUNCTION_ARGS)
504 : : {
505 : 3 : bytea *t1 = PG_GETARG_BYTEA_PP(0);
506 : 3 : bytea *t2 = PG_GETARG_BYTEA_PP(1);
507 : 3 : int sp = PG_GETARG_INT32(2); /* substring start position */
508 : 3 : int sl = PG_GETARG_INT32(3); /* substring length */
509 : :
510 : 3 : PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
511 : : }
512 : :
513 : : Datum
514 : 6 : byteaoverlay_no_len(PG_FUNCTION_ARGS)
515 : : {
516 : 6 : bytea *t1 = PG_GETARG_BYTEA_PP(0);
517 : 6 : bytea *t2 = PG_GETARG_BYTEA_PP(1);
518 : 6 : int sp = PG_GETARG_INT32(2); /* substring start position */
519 : : int sl;
520 : :
521 : 6 : sl = VARSIZE_ANY_EXHDR(t2); /* defaults to length(t2) */
522 : 6 : PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
523 : : }
524 : :
525 : : /*
526 : : * bytea_substr()
527 : : * Return a substring starting at the specified position.
528 : : * Cloned from text_substr and modified as required.
529 : : *
530 : : * Input:
531 : : * - string
532 : : * - starting position (is one-based)
533 : : * - string length (optional)
534 : : *
535 : : * If the starting position is zero or less, then return from the start of the string
536 : : * adjusting the length to be consistent with the "negative start" per SQL.
537 : : * If the length is less than zero, an ERROR is thrown. If no third argument
538 : : * (length) is provided, the length to the end of the string is assumed.
539 : : */
540 : : Datum
541 : 43 : bytea_substr(PG_FUNCTION_ARGS)
542 : : {
543 : 43 : PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
544 : : PG_GETARG_INT32(1),
545 : : PG_GETARG_INT32(2),
546 : : false));
547 : : }
548 : :
549 : : /*
550 : : * bytea_substr_no_len -
551 : : * Wrapper to avoid opr_sanity failure due to
552 : : * one function accepting a different number of args.
553 : : */
554 : : Datum
555 : 1968 : bytea_substr_no_len(PG_FUNCTION_ARGS)
556 : : {
557 : 1968 : PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
558 : : PG_GETARG_INT32(1),
559 : : -1,
560 : : true));
561 : : }
562 : :
563 : : /*
564 : : * bit_count
565 : : */
566 : : Datum
567 : 3 : bytea_bit_count(PG_FUNCTION_ARGS)
568 : : {
569 : 3 : bytea *t1 = PG_GETARG_BYTEA_PP(0);
570 : :
571 : 3 : PG_RETURN_INT64(pg_popcount(VARDATA_ANY(t1), VARSIZE_ANY_EXHDR(t1)));
572 : : }
573 : :
574 : : /*
575 : : * byteapos -
576 : : * Return the position of the specified substring.
577 : : * Implements the SQL POSITION() function.
578 : : * Cloned from textpos and modified as required.
579 : : */
580 : : Datum
581 : 15 : byteapos(PG_FUNCTION_ARGS)
582 : : {
583 : 15 : bytea *t1 = PG_GETARG_BYTEA_PP(0);
584 : 15 : bytea *t2 = PG_GETARG_BYTEA_PP(1);
585 : : int pos;
586 : : int px,
587 : : p;
588 : : int len1,
589 : : len2;
590 : : char *p1,
591 : : *p2;
592 : :
593 : 15 : len1 = VARSIZE_ANY_EXHDR(t1);
594 : 15 : len2 = VARSIZE_ANY_EXHDR(t2);
595 : :
596 [ + + ]: 15 : if (len2 <= 0)
597 : 3 : PG_RETURN_INT32(1); /* result for empty pattern */
598 : :
599 : 12 : p1 = VARDATA_ANY(t1);
600 : 12 : p2 = VARDATA_ANY(t2);
601 : :
602 : 12 : pos = 0;
603 : 12 : px = (len1 - len2);
604 [ + + ]: 27 : for (p = 0; p <= px; p++)
605 : : {
606 [ + + + - ]: 21 : if ((*p2 == *p1) && (memcmp(p1, p2, len2) == 0))
607 : : {
608 : 6 : pos = p + 1;
609 : 6 : break;
610 : : };
611 : 15 : p1++;
612 : : };
613 : :
614 : 12 : PG_RETURN_INT32(pos);
615 : : }
616 : :
617 : : /*-------------------------------------------------------------
618 : : * byteaGetByte
619 : : *
620 : : * this routine treats "bytea" as an array of bytes.
621 : : * It returns the Nth byte (a number between 0 and 255).
622 : : *-------------------------------------------------------------
623 : : */
624 : : Datum
625 : 38 : byteaGetByte(PG_FUNCTION_ARGS)
626 : : {
627 : 38 : bytea *v = PG_GETARG_BYTEA_PP(0);
628 : 38 : int32 n = PG_GETARG_INT32(1);
629 : : int len;
630 : : int byte;
631 : :
632 : 38 : len = VARSIZE_ANY_EXHDR(v);
633 : :
634 [ + - + + ]: 38 : if (n < 0 || n >= len)
635 [ + - ]: 3 : ereport(ERROR,
636 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
637 : : errmsg("index %d out of valid range, 0..%d",
638 : : n, len - 1)));
639 : :
640 : 35 : byte = ((unsigned char *) VARDATA_ANY(v))[n];
641 : :
642 : 35 : PG_RETURN_INT32(byte);
643 : : }
644 : :
645 : : /*-------------------------------------------------------------
646 : : * byteaGetBit
647 : : *
648 : : * This routine treats a "bytea" type like an array of bits.
649 : : * It returns the value of the Nth bit (0 or 1).
650 : : *
651 : : *-------------------------------------------------------------
652 : : */
653 : : Datum
654 : 6 : byteaGetBit(PG_FUNCTION_ARGS)
655 : : {
656 : 6 : bytea *v = PG_GETARG_BYTEA_PP(0);
657 : 6 : int64 n = PG_GETARG_INT64(1);
658 : : int byteNo,
659 : : bitNo;
660 : : int len;
661 : : int byte;
662 : :
663 : 6 : len = VARSIZE_ANY_EXHDR(v);
664 : :
665 [ + - + + ]: 6 : if (n < 0 || n >= (int64) len * 8)
666 [ + - ]: 3 : ereport(ERROR,
667 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
668 : : errmsg("index %" PRId64 " out of valid range, 0..%" PRId64,
669 : : n, (int64) len * 8 - 1)));
670 : :
671 : : /* n/8 is now known < len, so safe to cast to int */
672 : 3 : byteNo = (int) (n / 8);
673 : 3 : bitNo = (int) (n % 8);
674 : :
675 : 3 : byte = ((unsigned char *) VARDATA_ANY(v))[byteNo];
676 : :
677 [ + - ]: 3 : if (byte & (1 << bitNo))
678 : 3 : PG_RETURN_INT32(1);
679 : : else
66 michael@paquier.xyz 680 :UNC 0 : PG_RETURN_INT32(0);
681 : : }
682 : :
683 : : /*-------------------------------------------------------------
684 : : * byteaSetByte
685 : : *
686 : : * Given an instance of type 'bytea' creates a new one with
687 : : * the Nth byte set to the given value.
688 : : *
689 : : *-------------------------------------------------------------
690 : : */
691 : : Datum
66 michael@paquier.xyz 692 :GNC 6 : byteaSetByte(PG_FUNCTION_ARGS)
693 : : {
694 : 6 : bytea *res = PG_GETARG_BYTEA_P_COPY(0);
695 : 6 : int32 n = PG_GETARG_INT32(1);
696 : 6 : int32 newByte = PG_GETARG_INT32(2);
697 : : int len;
698 : :
699 : 6 : len = VARSIZE(res) - VARHDRSZ;
700 : :
701 [ + - + + ]: 6 : if (n < 0 || n >= len)
702 [ + - ]: 3 : ereport(ERROR,
703 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
704 : : errmsg("index %d out of valid range, 0..%d",
705 : : n, len - 1)));
706 : :
707 : : /*
708 : : * Now set the byte.
709 : : */
710 : 3 : ((unsigned char *) VARDATA(res))[n] = newByte;
711 : :
712 : 3 : PG_RETURN_BYTEA_P(res);
713 : : }
714 : :
715 : : /*-------------------------------------------------------------
716 : : * byteaSetBit
717 : : *
718 : : * Given an instance of type 'bytea' creates a new one with
719 : : * the Nth bit set to the given value.
720 : : *
721 : : *-------------------------------------------------------------
722 : : */
723 : : Datum
724 : 6 : byteaSetBit(PG_FUNCTION_ARGS)
725 : : {
726 : 6 : bytea *res = PG_GETARG_BYTEA_P_COPY(0);
727 : 6 : int64 n = PG_GETARG_INT64(1);
728 : 6 : int32 newBit = PG_GETARG_INT32(2);
729 : : int len;
730 : : int oldByte,
731 : : newByte;
732 : : int byteNo,
733 : : bitNo;
734 : :
735 : 6 : len = VARSIZE(res) - VARHDRSZ;
736 : :
737 [ + - + + ]: 6 : if (n < 0 || n >= (int64) len * 8)
738 [ + - ]: 3 : ereport(ERROR,
739 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
740 : : errmsg("index %" PRId64 " out of valid range, 0..%" PRId64,
741 : : n, (int64) len * 8 - 1)));
742 : :
743 : : /* n/8 is now known < len, so safe to cast to int */
744 : 3 : byteNo = (int) (n / 8);
745 : 3 : bitNo = (int) (n % 8);
746 : :
747 : : /*
748 : : * sanity check!
749 : : */
750 [ - + - - ]: 3 : if (newBit != 0 && newBit != 1)
66 michael@paquier.xyz 751 [ # # ]:UNC 0 : ereport(ERROR,
752 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
753 : : errmsg("new bit must be 0 or 1")));
754 : :
755 : : /*
756 : : * Update the byte.
757 : : */
66 michael@paquier.xyz 758 :GNC 3 : oldByte = ((unsigned char *) VARDATA(res))[byteNo];
759 : :
760 [ + - ]: 3 : if (newBit == 0)
761 : 3 : newByte = oldByte & (~(1 << bitNo));
762 : : else
66 michael@paquier.xyz 763 :UNC 0 : newByte = oldByte | (1 << bitNo);
764 : :
66 michael@paquier.xyz 765 :GNC 3 : ((unsigned char *) VARDATA(res))[byteNo] = newByte;
766 : :
767 : 3 : PG_RETURN_BYTEA_P(res);
768 : : }
769 : :
770 : : /*
771 : : * Return reversed bytea
772 : : */
773 : : Datum
774 : 9 : bytea_reverse(PG_FUNCTION_ARGS)
775 : : {
776 : 9 : bytea *v = PG_GETARG_BYTEA_PP(0);
777 : 9 : const char *p = VARDATA_ANY(v);
778 : 9 : int len = VARSIZE_ANY_EXHDR(v);
779 : 9 : const char *endp = p + len;
780 : 9 : bytea *result = palloc(len + VARHDRSZ);
781 : 9 : char *dst = (char *) VARDATA(result) + len;
782 : :
783 : 9 : SET_VARSIZE(result, len + VARHDRSZ);
784 : :
785 [ + + ]: 18 : while (p < endp)
786 : 9 : *(--dst) = *p++;
787 : :
788 : 9 : PG_RETURN_BYTEA_P(result);
789 : : }
790 : :
791 : :
792 : : /*****************************************************************************
793 : : * Comparison Functions used for bytea
794 : : *
795 : : * Note: btree indexes need these routines not to leak memory; therefore,
796 : : * be careful to free working copies of toasted datums. Most places don't
797 : : * need to be so careful.
798 : : *****************************************************************************/
799 : :
800 : : Datum
801 : 5238 : byteaeq(PG_FUNCTION_ARGS)
802 : : {
803 : 5238 : Datum arg1 = PG_GETARG_DATUM(0);
804 : 5238 : Datum arg2 = PG_GETARG_DATUM(1);
805 : : bool result;
806 : : Size len1,
807 : : len2;
808 : :
809 : : /*
810 : : * We can use a fast path for unequal lengths, which might save us from
811 : : * having to detoast one or both values.
812 : : */
813 : 5238 : len1 = toast_raw_datum_size(arg1);
814 : 5238 : len2 = toast_raw_datum_size(arg2);
815 [ + + ]: 5238 : if (len1 != len2)
816 : 2200 : result = false;
817 : : else
818 : : {
819 : 3038 : bytea *barg1 = DatumGetByteaPP(arg1);
820 : 3038 : bytea *barg2 = DatumGetByteaPP(arg2);
821 : :
822 : 3038 : result = (memcmp(VARDATA_ANY(barg1), VARDATA_ANY(barg2),
823 : : len1 - VARHDRSZ) == 0);
824 : :
825 [ + + ]: 3038 : PG_FREE_IF_COPY(barg1, 0);
826 [ + + ]: 3038 : PG_FREE_IF_COPY(barg2, 1);
827 : : }
828 : :
829 : 5238 : PG_RETURN_BOOL(result);
830 : : }
831 : :
832 : : Datum
833 : 384 : byteane(PG_FUNCTION_ARGS)
834 : : {
835 : 384 : Datum arg1 = PG_GETARG_DATUM(0);
836 : 384 : Datum arg2 = PG_GETARG_DATUM(1);
837 : : bool result;
838 : : Size len1,
839 : : len2;
840 : :
841 : : /*
842 : : * We can use a fast path for unequal lengths, which might save us from
843 : : * having to detoast one or both values.
844 : : */
845 : 384 : len1 = toast_raw_datum_size(arg1);
846 : 384 : len2 = toast_raw_datum_size(arg2);
847 [ - + ]: 384 : if (len1 != len2)
66 michael@paquier.xyz 848 :UNC 0 : result = true;
849 : : else
850 : : {
66 michael@paquier.xyz 851 :GNC 384 : bytea *barg1 = DatumGetByteaPP(arg1);
852 : 384 : bytea *barg2 = DatumGetByteaPP(arg2);
853 : :
854 : 384 : result = (memcmp(VARDATA_ANY(barg1), VARDATA_ANY(barg2),
855 : : len1 - VARHDRSZ) != 0);
856 : :
857 [ - + ]: 384 : PG_FREE_IF_COPY(barg1, 0);
858 [ - + ]: 384 : PG_FREE_IF_COPY(barg2, 1);
859 : : }
860 : :
861 : 384 : PG_RETURN_BOOL(result);
862 : : }
863 : :
864 : : Datum
865 : 4126 : bytealt(PG_FUNCTION_ARGS)
866 : : {
867 : 4126 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
868 : 4126 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
869 : : int len1,
870 : : len2;
871 : : int cmp;
872 : :
873 : 4126 : len1 = VARSIZE_ANY_EXHDR(arg1);
874 : 4126 : len2 = VARSIZE_ANY_EXHDR(arg2);
875 : :
876 : 4126 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
877 : :
878 [ + + ]: 4126 : PG_FREE_IF_COPY(arg1, 0);
879 [ - + ]: 4126 : PG_FREE_IF_COPY(arg2, 1);
880 : :
881 [ + + + + : 4126 : PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 < len2)));
+ + ]
882 : : }
883 : :
884 : : Datum
885 : 3178 : byteale(PG_FUNCTION_ARGS)
886 : : {
887 : 3178 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
888 : 3178 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
889 : : int len1,
890 : : len2;
891 : : int cmp;
892 : :
893 : 3178 : len1 = VARSIZE_ANY_EXHDR(arg1);
894 : 3178 : len2 = VARSIZE_ANY_EXHDR(arg2);
895 : :
896 : 3178 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
897 : :
898 [ + + ]: 3178 : PG_FREE_IF_COPY(arg1, 0);
899 [ - + ]: 3178 : PG_FREE_IF_COPY(arg2, 1);
900 : :
901 [ + + + + : 3178 : PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 <= len2)));
+ + ]
902 : : }
903 : :
904 : : Datum
905 : 3136 : byteagt(PG_FUNCTION_ARGS)
906 : : {
907 : 3136 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
908 : 3136 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
909 : : int len1,
910 : : len2;
911 : : int cmp;
912 : :
913 : 3136 : len1 = VARSIZE_ANY_EXHDR(arg1);
914 : 3136 : len2 = VARSIZE_ANY_EXHDR(arg2);
915 : :
916 : 3136 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
917 : :
918 [ + + ]: 3136 : PG_FREE_IF_COPY(arg1, 0);
919 [ - + ]: 3136 : PG_FREE_IF_COPY(arg2, 1);
920 : :
921 [ + + + + : 3136 : PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 > len2)));
+ + ]
922 : : }
923 : :
924 : : Datum
925 : 2527 : byteage(PG_FUNCTION_ARGS)
926 : : {
927 : 2527 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
928 : 2527 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
929 : : int len1,
930 : : len2;
931 : : int cmp;
932 : :
933 : 2527 : len1 = VARSIZE_ANY_EXHDR(arg1);
934 : 2527 : len2 = VARSIZE_ANY_EXHDR(arg2);
935 : :
936 : 2527 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
937 : :
938 [ + + ]: 2527 : PG_FREE_IF_COPY(arg1, 0);
939 [ - + ]: 2527 : PG_FREE_IF_COPY(arg2, 1);
940 : :
941 [ + + + + : 2527 : PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 >= len2)));
+ + ]
942 : : }
943 : :
944 : : Datum
945 : 47296 : byteacmp(PG_FUNCTION_ARGS)
946 : : {
947 : 47296 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
948 : 47296 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
949 : : int len1,
950 : : len2;
951 : : int cmp;
952 : :
953 : 47296 : len1 = VARSIZE_ANY_EXHDR(arg1);
954 : 47296 : len2 = VARSIZE_ANY_EXHDR(arg2);
955 : :
956 : 47296 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
957 [ + + + + ]: 47296 : if ((cmp == 0) && (len1 != len2))
958 [ + + ]: 1700 : cmp = (len1 < len2) ? -1 : 1;
959 : :
960 [ - + ]: 47296 : PG_FREE_IF_COPY(arg1, 0);
961 [ - + ]: 47296 : PG_FREE_IF_COPY(arg2, 1);
962 : :
963 : 47296 : PG_RETURN_INT32(cmp);
964 : : }
965 : :
966 : : Datum
967 : 12 : bytea_larger(PG_FUNCTION_ARGS)
968 : : {
969 : 12 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
970 : 12 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
971 : : bytea *result;
972 : : int len1,
973 : : len2;
974 : : int cmp;
975 : :
976 : 12 : len1 = VARSIZE_ANY_EXHDR(arg1);
977 : 12 : len2 = VARSIZE_ANY_EXHDR(arg2);
978 : :
979 : 12 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
980 [ + + + - : 12 : result = ((cmp > 0) || ((cmp == 0) && (len1 > len2)) ? arg1 : arg2);
- + ]
981 : :
982 : 12 : PG_RETURN_BYTEA_P(result);
983 : : }
984 : :
985 : : Datum
986 : 12 : bytea_smaller(PG_FUNCTION_ARGS)
987 : : {
988 : 12 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
989 : 12 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
990 : : bytea *result;
991 : : int len1,
992 : : len2;
993 : : int cmp;
994 : :
995 : 12 : len1 = VARSIZE_ANY_EXHDR(arg1);
996 : 12 : len2 = VARSIZE_ANY_EXHDR(arg2);
997 : :
998 : 12 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
999 [ + + + + : 12 : result = ((cmp < 0) || ((cmp == 0) && (len1 < len2)) ? arg1 : arg2);
+ - ]
1000 : :
1001 : 12 : PG_RETURN_BYTEA_P(result);
1002 : : }
1003 : :
1004 : : Datum
1005 : 28 : bytea_sortsupport(PG_FUNCTION_ARGS)
1006 : : {
1007 : 28 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
1008 : : MemoryContext oldcontext;
1009 : :
1010 : 28 : oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
1011 : :
1012 : : /* Use generic string SortSupport, forcing "C" collation */
1013 : 28 : varstr_sortsupport(ssup, BYTEAOID, C_COLLATION_OID);
1014 : :
1015 : 28 : MemoryContextSwitchTo(oldcontext);
1016 : :
1017 : 28 : PG_RETURN_VOID();
1018 : : }
1019 : :
1020 : : /* Cast bytea -> int2 */
1021 : : Datum
1022 : 18 : bytea_int2(PG_FUNCTION_ARGS)
1023 : : {
1024 : 18 : bytea *v = PG_GETARG_BYTEA_PP(0);
1025 : 18 : int len = VARSIZE_ANY_EXHDR(v);
1026 : : uint16 result;
1027 : :
1028 : : /* Check that the byte array is not too long */
1029 [ + + ]: 18 : if (len > sizeof(result))
1030 [ + - ]: 3 : ereport(ERROR,
1031 : : errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1032 : : errmsg("smallint out of range"));
1033 : :
1034 : : /* Convert it to an integer; most significant bytes come first */
1035 : 15 : result = 0;
1036 [ + + ]: 36 : for (int i = 0; i < len; i++)
1037 : : {
1038 : 21 : result <<= BITS_PER_BYTE;
1039 : 21 : result |= ((unsigned char *) VARDATA_ANY(v))[i];
1040 : : }
1041 : :
1042 : 15 : PG_RETURN_INT16(result);
1043 : : }
1044 : :
1045 : : /* Cast bytea -> int4 */
1046 : : Datum
1047 : 18 : bytea_int4(PG_FUNCTION_ARGS)
1048 : : {
1049 : 18 : bytea *v = PG_GETARG_BYTEA_PP(0);
1050 : 18 : int len = VARSIZE_ANY_EXHDR(v);
1051 : : uint32 result;
1052 : :
1053 : : /* Check that the byte array is not too long */
1054 [ + + ]: 18 : if (len > sizeof(result))
1055 [ + - ]: 3 : ereport(ERROR,
1056 : : errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1057 : : errmsg("integer out of range"));
1058 : :
1059 : : /* Convert it to an integer; most significant bytes come first */
1060 : 15 : result = 0;
1061 [ + + ]: 54 : for (int i = 0; i < len; i++)
1062 : : {
1063 : 39 : result <<= BITS_PER_BYTE;
1064 : 39 : result |= ((unsigned char *) VARDATA_ANY(v))[i];
1065 : : }
1066 : :
1067 : 15 : PG_RETURN_INT32(result);
1068 : : }
1069 : :
1070 : : /* Cast bytea -> int8 */
1071 : : Datum
1072 : 18 : bytea_int8(PG_FUNCTION_ARGS)
1073 : : {
1074 : 18 : bytea *v = PG_GETARG_BYTEA_PP(0);
1075 : 18 : int len = VARSIZE_ANY_EXHDR(v);
1076 : : uint64 result;
1077 : :
1078 : : /* Check that the byte array is not too long */
1079 [ + + ]: 18 : if (len > sizeof(result))
1080 [ + - ]: 3 : ereport(ERROR,
1081 : : errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1082 : : errmsg("bigint out of range"));
1083 : :
1084 : : /* Convert it to an integer; most significant bytes come first */
1085 : 15 : result = 0;
1086 [ + + ]: 90 : for (int i = 0; i < len; i++)
1087 : : {
1088 : 75 : result <<= BITS_PER_BYTE;
1089 : 75 : result |= ((unsigned char *) VARDATA_ANY(v))[i];
1090 : : }
1091 : :
1092 : 15 : PG_RETURN_INT64(result);
1093 : : }
1094 : :
1095 : : /* Cast int2 -> bytea; can just use int2send() */
1096 : : Datum
1097 : 6 : int2_bytea(PG_FUNCTION_ARGS)
1098 : : {
1099 : 6 : return int2send(fcinfo);
1100 : : }
1101 : :
1102 : : /* Cast int4 -> bytea; can just use int4send() */
1103 : : Datum
1104 : 20486 : int4_bytea(PG_FUNCTION_ARGS)
1105 : : {
1106 : 20486 : return int4send(fcinfo);
1107 : : }
1108 : :
1109 : : /* Cast int8 -> bytea; can just use int8send() */
1110 : : Datum
1111 : 6 : int8_bytea(PG_FUNCTION_ARGS)
1112 : : {
1113 : 6 : return int8send(fcinfo);
1114 : : }
|