Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * bytea.c
4 : : * Functions for the bytea type.
5 : : *
6 : : * Portions Copyright (c) 2025-2026, 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 "common/hashfn.h"
19 : : #include "common/int.h"
20 : : #include "fmgr.h"
21 : : #include "lib/hyperloglog.h"
22 : : #include "libpq/pqformat.h"
23 : : #include "port/pg_bitutils.h"
24 : : #include "port/pg_bswap.h"
25 : : #include "utils/builtins.h"
26 : : #include "utils/bytea.h"
27 : : #include "utils/fmgrprotos.h"
28 : : #include "utils/guc.h"
29 : : #include "utils/memutils.h"
30 : : #include "utils/sortsupport.h"
31 : : #include "varatt.h"
32 : :
33 : : /* GUC variable */
34 : : int bytea_output = BYTEA_OUTPUT_HEX;
35 : :
36 : : static bytea *bytea_catenate(bytea *t1, bytea *t2);
37 : : static bytea *bytea_substring(Datum str, int S, int L,
38 : : bool length_not_specified);
39 : : static bytea *bytea_overlay(bytea *t1, bytea *t2, int sp, int sl);
40 : :
41 : : typedef struct
42 : : {
43 : : bool abbreviate; /* Should we abbreviate keys? */
44 : : hyperLogLogState abbr_card; /* Abbreviated key cardinality state */
45 : : hyperLogLogState full_card; /* Full key cardinality state */
46 : : double prop_card; /* Required cardinality proportion */
47 : : } ByteaSortSupport;
48 : :
49 : : /* Static function declarations for sort support */
50 : : static int byteafastcmp(Datum x, Datum y, SortSupport ssup);
51 : : static Datum bytea_abbrev_convert(Datum original, SortSupport ssup);
52 : : static bool bytea_abbrev_abort(int memtupcount, SortSupport ssup);
53 : :
54 : : /*
55 : : * bytea_catenate
56 : : * Guts of byteacat(), broken out so it can be used by other functions
57 : : *
58 : : * Arguments can be in short-header form, but not compressed or out-of-line
59 : : */
60 : : static bytea *
61 : 259 : bytea_catenate(bytea *t1, bytea *t2)
62 : : {
63 : 259 : bytea *result;
64 : 259 : int len1,
65 : : len2,
66 : : len;
67 : 259 : char *ptr;
68 : :
69 : 259 : len1 = VARSIZE_ANY_EXHDR(t1);
70 : 259 : len2 = VARSIZE_ANY_EXHDR(t2);
71 : :
72 : : /* paranoia ... probably should throw error instead? */
73 [ + - ]: 259 : if (len1 < 0)
74 : 0 : len1 = 0;
75 [ + - ]: 259 : if (len2 < 0)
76 : 0 : len2 = 0;
77 : :
78 : 259 : len = len1 + len2 + VARHDRSZ;
79 : 259 : result = (bytea *) palloc(len);
80 : :
81 : : /* Set size of result string... */
82 : 259 : SET_VARSIZE(result, len);
83 : :
84 : : /* Fill data field of result string... */
85 : 259 : ptr = VARDATA(result);
86 [ - + ]: 259 : if (len1 > 0)
87 : 259 : memcpy(ptr, VARDATA_ANY(t1), len1);
88 [ + + ]: 259 : if (len2 > 0)
89 : 256 : memcpy(ptr + len1, VARDATA_ANY(t2), len2);
90 : :
91 : 518 : return result;
92 : 259 : }
93 : :
94 : : #define PG_STR_GET_BYTEA(str_) \
95 : : DatumGetByteaPP(DirectFunctionCall1(byteain, CStringGetDatum(str_)))
96 : :
97 : : static bytea *
98 : 675 : bytea_substring(Datum str,
99 : : int S,
100 : : int L,
101 : : bool length_not_specified)
102 : : {
103 : 675 : int32 S1; /* adjusted start position */
104 : 675 : int32 L1; /* adjusted substring length */
105 : 675 : int32 E; /* end position */
106 : :
107 : : /*
108 : : * The logic here should generally match text_substring().
109 : : */
110 [ + + ]: 675 : S1 = Max(S, 1);
111 : :
112 [ + + ]: 675 : if (length_not_specified)
113 : : {
114 : : /*
115 : : * Not passed a length - DatumGetByteaPSlice() grabs everything to the
116 : : * end of the string if we pass it a negative value for length.
117 : : */
118 : 659 : L1 = -1;
119 : 659 : }
120 [ + + ]: 16 : else if (L < 0)
121 : : {
122 : : /* SQL99 says to throw an error for E < S, i.e., negative length */
123 [ + - + - ]: 2 : ereport(ERROR,
124 : : (errcode(ERRCODE_SUBSTRING_ERROR),
125 : : errmsg("negative substring length not allowed")));
126 : 0 : L1 = -1; /* silence stupider compilers */
127 : 0 : }
128 [ + + ]: 14 : else if (pg_add_s32_overflow(S, L, &E))
129 : : {
130 : : /*
131 : : * L could be large enough for S + L to overflow, in which case the
132 : : * substring must run to end of string.
133 : : */
134 : 1 : L1 = -1;
135 : 1 : }
136 : : else
137 : : {
138 : : /*
139 : : * A zero or negative value for the end position can happen if the
140 : : * start was negative or one. SQL99 says to return a zero-length
141 : : * string.
142 : : */
143 [ + - ]: 13 : if (E < 1)
144 : 0 : return PG_STR_GET_BYTEA("");
145 : :
146 : 13 : L1 = E - S1;
147 : : }
148 : :
149 : : /*
150 : : * If the start position is past the end of the string, SQL99 says to
151 : : * return a zero-length string -- DatumGetByteaPSlice() will do that for
152 : : * us. We need only convert S1 to zero-based starting position.
153 : : */
154 : 673 : return DatumGetByteaPSlice(str, S1 - 1, L1);
155 : 673 : }
156 : :
157 : : static bytea *
158 : 3 : bytea_overlay(bytea *t1, bytea *t2, int sp, int sl)
159 : : {
160 : 3 : bytea *result;
161 : 3 : bytea *s1;
162 : 3 : bytea *s2;
163 : 3 : int sp_pl_sl;
164 : :
165 : : /*
166 : : * Check for possible integer-overflow cases. For negative sp, throw a
167 : : * "substring length" error because that's what should be expected
168 : : * according to the spec's definition of OVERLAY().
169 : : */
170 [ + - ]: 3 : if (sp <= 0)
171 [ # # # # ]: 0 : ereport(ERROR,
172 : : (errcode(ERRCODE_SUBSTRING_ERROR),
173 : : errmsg("negative substring length not allowed")));
174 [ + - ]: 3 : if (pg_add_s32_overflow(sp, sl, &sp_pl_sl))
175 [ # # # # ]: 0 : ereport(ERROR,
176 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
177 : : errmsg("integer out of range")));
178 : :
179 : 3 : s1 = bytea_substring(PointerGetDatum(t1), 1, sp - 1, false);
180 : 3 : s2 = bytea_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
181 : 3 : result = bytea_catenate(s1, t2);
182 : 3 : result = bytea_catenate(result, s2);
183 : :
184 : 6 : return result;
185 : 3 : }
186 : :
187 : : /*****************************************************************************
188 : : * USER I/O ROUTINES *
189 : : *****************************************************************************/
190 : :
191 : : #define VAL(CH) ((CH) - '0')
192 : : #define DIG(VAL) ((VAL) + '0')
193 : :
194 : : /*
195 : : * byteain - converts from printable representation of byte array
196 : : *
197 : : * Non-printable characters must be passed as '\nnn' (octal) and are
198 : : * converted to internal form. '\' must be passed as '\\'.
199 : : */
200 : : Datum
201 : 45425 : byteain(PG_FUNCTION_ARGS)
202 : : {
203 : 45425 : char *inputText = PG_GETARG_CSTRING(0);
204 : 45425 : Node *escontext = fcinfo->context;
205 : 45425 : size_t len = strlen(inputText);
206 : 45425 : size_t bc;
207 : 45425 : char *tp;
208 : 45425 : char *rp;
209 : 45425 : bytea *result;
210 : :
211 : : /* Recognize hex input */
212 [ + + + + ]: 45425 : if (inputText[0] == '\\' && inputText[1] == 'x')
213 : : {
214 : 194 : bc = (len - 2) / 2 + VARHDRSZ; /* maximum possible length */
215 : 194 : result = palloc(bc);
216 : 388 : bc = hex_decode_safe(inputText + 2, len - 2, VARDATA(result),
217 : 194 : escontext);
218 : 194 : SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */
219 : :
220 : 194 : PG_RETURN_BYTEA_P(result);
221 : : }
222 : :
223 : : /* Else, it's the traditional escaped style */
224 : 45231 : result = (bytea *) palloc(len + VARHDRSZ); /* maximum possible length */
225 : :
226 : 45231 : tp = inputText;
227 : 45231 : rp = VARDATA(result);
228 [ + + ]: 708542 : while (*tp != '\0')
229 : : {
230 [ + + ]: 663314 : if (tp[0] != '\\')
231 : 663187 : *rp++ = *tp++;
232 [ + + + + ]: 127 : else if ((tp[1] >= '0' && tp[1] <= '3') &&
233 [ + - + - : 244 : (tp[2] >= '0' && tp[2] <= '7') &&
- + ]
234 [ + - ]: 122 : (tp[3] >= '0' && tp[3] <= '7'))
235 : : {
236 : 122 : int v;
237 : :
238 : 122 : v = VAL(tp[1]);
239 : 122 : v <<= 3;
240 : 122 : v += VAL(tp[2]);
241 : 122 : v <<= 3;
242 : 122 : *rp++ = v + VAL(tp[3]);
243 : :
244 : 122 : tp += 4;
245 : 122 : }
246 [ + + ]: 5 : else if (tp[1] == '\\')
247 : : {
248 : 2 : *rp++ = '\\';
249 : 2 : tp += 2;
250 : 2 : }
251 : : else
252 : : {
253 : : /*
254 : : * one backslash, not followed by another or ### valid octal
255 : : */
256 [ + + ]: 3 : ereturn(escontext, (Datum) 0,
257 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
258 : : errmsg("invalid input syntax for type %s", "bytea")));
259 : : }
260 : : }
261 : :
262 : 45228 : bc = rp - VARDATA(result); /* actual length */
263 : 45228 : SET_VARSIZE(result, bc + VARHDRSZ);
264 : :
265 : 45228 : PG_RETURN_BYTEA_P(result);
266 : 45423 : }
267 : :
268 : : /*
269 : : * byteaout - converts to printable representation of byte array
270 : : *
271 : : * In the traditional escaped format, non-printable characters are
272 : : * printed as '\nnn' (octal) and '\' as '\\'.
273 : : */
274 : : Datum
275 : 1875 : byteaout(PG_FUNCTION_ARGS)
276 : : {
277 : 1875 : bytea *vlena = PG_GETARG_BYTEA_PP(0);
278 : 1875 : char *result;
279 : 1875 : char *rp;
280 : :
281 [ + + ]: 1875 : if (bytea_output == BYTEA_OUTPUT_HEX)
282 : : {
283 : : /* Print hex format */
284 : 1815 : rp = result = palloc(VARSIZE_ANY_EXHDR(vlena) * 2 + 2 + 1);
285 : 1815 : *rp++ = '\\';
286 : 1815 : *rp++ = 'x';
287 : 1815 : rp += hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp);
288 : 1815 : }
289 [ + - ]: 60 : else if (bytea_output == BYTEA_OUTPUT_ESCAPE)
290 : : {
291 : : /* Print traditional escaped format */
292 : 60 : char *vp;
293 : 60 : uint64 len;
294 : 60 : int i;
295 : :
296 : 60 : len = 1; /* empty string has 1 char */
297 : 60 : vp = VARDATA_ANY(vlena);
298 [ + + ]: 36268 : for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++)
299 : : {
300 [ + + ]: 36208 : if (*vp == '\\')
301 : 1 : len += 2;
302 [ + + + + ]: 36207 : else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e)
303 : 81 : len += 4;
304 : : else
305 : 36126 : len++;
306 : 36208 : }
307 : :
308 : : /*
309 : : * In principle len can't overflow uint32 if the input fit in 1GB, but
310 : : * for safety let's check rather than relying on palloc's internal
311 : : * check.
312 : : */
313 [ + - ]: 60 : if (len > MaxAllocSize)
314 [ # # # # ]: 0 : ereport(ERROR,
315 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
316 : : errmsg_internal("result of bytea output conversion is too large")));
317 : 60 : rp = result = (char *) palloc(len);
318 : :
319 : 60 : vp = VARDATA_ANY(vlena);
320 [ + + ]: 36268 : for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++)
321 : : {
322 [ + + ]: 36208 : if (*vp == '\\')
323 : : {
324 : 1 : *rp++ = '\\';
325 : 1 : *rp++ = '\\';
326 : 1 : }
327 [ + + + + ]: 36207 : else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e)
328 : : {
329 : 81 : int val; /* holds unprintable chars */
330 : :
331 : 81 : val = *vp;
332 : 81 : rp[0] = '\\';
333 : 81 : rp[3] = DIG(val & 07);
334 : 81 : val >>= 3;
335 : 81 : rp[2] = DIG(val & 07);
336 : 81 : val >>= 3;
337 : 81 : rp[1] = DIG(val & 03);
338 : 81 : rp += 4;
339 : 81 : }
340 : : else
341 : 36126 : *rp++ = *vp;
342 : 36208 : }
343 : 60 : }
344 : : else
345 : : {
346 [ # # # # ]: 0 : elog(ERROR, "unrecognized \"bytea_output\" setting: %d",
347 : : bytea_output);
348 : 0 : rp = result = NULL; /* keep compiler quiet */
349 : : }
350 : 1875 : *rp = '\0';
351 : 3750 : PG_RETURN_CSTRING(result);
352 : 1875 : }
353 : :
354 : : /*
355 : : * bytearecv - converts external binary format to bytea
356 : : */
357 : : Datum
358 : 164 : bytearecv(PG_FUNCTION_ARGS)
359 : : {
360 : 164 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
361 : 164 : bytea *result;
362 : 164 : int nbytes;
363 : :
364 : 164 : nbytes = buf->len - buf->cursor;
365 : 164 : result = (bytea *) palloc(nbytes + VARHDRSZ);
366 : 164 : SET_VARSIZE(result, nbytes + VARHDRSZ);
367 : 164 : pq_copymsgbytes(buf, VARDATA(result), nbytes);
368 : 328 : PG_RETURN_BYTEA_P(result);
369 : 164 : }
370 : :
371 : : /*
372 : : * byteasend - converts bytea to binary format
373 : : *
374 : : * This is a special case: just copy the input...
375 : : */
376 : : Datum
377 : 83 : byteasend(PG_FUNCTION_ARGS)
378 : : {
379 : 83 : bytea *vlena = PG_GETARG_BYTEA_P_COPY(0);
380 : :
381 : 166 : PG_RETURN_BYTEA_P(vlena);
382 : 83 : }
383 : :
384 : : Datum
385 : 10007 : bytea_string_agg_transfn(PG_FUNCTION_ARGS)
386 : : {
387 : 10007 : StringInfo state;
388 : :
389 [ + + ]: 10007 : state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
390 : :
391 : : /* Append the value unless null, preceding it with the delimiter. */
392 [ + + ]: 10007 : if (!PG_ARGISNULL(1))
393 : : {
394 : 7507 : bytea *value = PG_GETARG_BYTEA_PP(1);
395 : 7507 : bool isfirst = false;
396 : :
397 : : /*
398 : : * You might think we can just throw away the first delimiter, however
399 : : * we must keep it as we may be a parallel worker doing partial
400 : : * aggregation building a state to send to the main process. We need
401 : : * to keep the delimiter of every aggregation so that the combine
402 : : * function can properly join up the strings of two separately
403 : : * partially aggregated results. The first delimiter is only stripped
404 : : * off in the final function. To know how much to strip off the front
405 : : * of the string, we store the length of the first delimiter in the
406 : : * StringInfo's cursor field, which we don't otherwise need here.
407 : : */
408 [ + + ]: 7507 : if (state == NULL)
409 : : {
410 : 34 : MemoryContext aggcontext;
411 : 34 : MemoryContext oldcontext;
412 : :
413 [ + - ]: 34 : if (!AggCheckCallContext(fcinfo, &aggcontext))
414 : : {
415 : : /* cannot be called directly because of internal-type argument */
416 [ # # # # ]: 0 : elog(ERROR, "bytea_string_agg_transfn called in non-aggregate context");
417 : 0 : }
418 : :
419 : : /*
420 : : * Create state in aggregate context. It'll stay there across
421 : : * subsequent calls.
422 : : */
423 : 34 : oldcontext = MemoryContextSwitchTo(aggcontext);
424 : 34 : state = makeStringInfo();
425 : 34 : MemoryContextSwitchTo(oldcontext);
426 : :
427 : 34 : isfirst = true;
428 : 34 : }
429 : :
430 [ + + ]: 7507 : if (!PG_ARGISNULL(2))
431 : : {
432 : 7505 : bytea *delim = PG_GETARG_BYTEA_PP(2);
433 : :
434 : 15010 : appendBinaryStringInfo(state, VARDATA_ANY(delim),
435 : 7505 : VARSIZE_ANY_EXHDR(delim));
436 [ + + ]: 7505 : if (isfirst)
437 : 33 : state->cursor = VARSIZE_ANY_EXHDR(delim);
438 : 7505 : }
439 : :
440 : 15014 : appendBinaryStringInfo(state, VARDATA_ANY(value),
441 : 7507 : VARSIZE_ANY_EXHDR(value));
442 : 7507 : }
443 : :
444 : : /*
445 : : * The transition type for string_agg() is declared to be "internal",
446 : : * which is a pass-by-value type the same size as a pointer.
447 : : */
448 [ + + ]: 10007 : if (state)
449 : 9999 : PG_RETURN_POINTER(state);
450 : 8 : PG_RETURN_NULL();
451 [ - + ]: 10007 : }
452 : :
453 : : Datum
454 : 25 : bytea_string_agg_finalfn(PG_FUNCTION_ARGS)
455 : : {
456 : 25 : StringInfo state;
457 : :
458 : : /* cannot be called directly because of internal-type argument */
459 [ + - ]: 25 : Assert(AggCheckCallContext(fcinfo, NULL));
460 : :
461 [ + + ]: 25 : state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);
462 : :
463 [ + + ]: 25 : if (state != NULL)
464 : : {
465 : : /* As per comment in transfn, strip data before the cursor position */
466 : 24 : bytea *result;
467 : 24 : int strippedlen = state->len - state->cursor;
468 : :
469 : 24 : result = (bytea *) palloc(strippedlen + VARHDRSZ);
470 : 24 : SET_VARSIZE(result, strippedlen + VARHDRSZ);
471 : 24 : memcpy(VARDATA(result), &state->data[state->cursor], strippedlen);
472 : 24 : PG_RETURN_BYTEA_P(result);
473 : 24 : }
474 : : else
475 : 1 : PG_RETURN_NULL();
476 [ - + ]: 25 : }
477 : :
478 : : /*-------------------------------------------------------------
479 : : * byteaoctetlen
480 : : *
481 : : * get the number of bytes contained in an instance of type 'bytea'
482 : : *-------------------------------------------------------------
483 : : */
484 : : Datum
485 : 104 : byteaoctetlen(PG_FUNCTION_ARGS)
486 : : {
487 : 104 : Datum str = PG_GETARG_DATUM(0);
488 : :
489 : : /* We need not detoast the input at all */
490 : 208 : PG_RETURN_INT32(toast_raw_datum_size(str) - VARHDRSZ);
491 : 104 : }
492 : :
493 : : /*
494 : : * byteacat -
495 : : * takes two bytea* and returns a bytea* that is the concatenation of
496 : : * the two.
497 : : *
498 : : * Cloned from textcat and modified as required.
499 : : */
500 : : Datum
501 : 253 : byteacat(PG_FUNCTION_ARGS)
502 : : {
503 : 253 : bytea *t1 = PG_GETARG_BYTEA_PP(0);
504 : 253 : bytea *t2 = PG_GETARG_BYTEA_PP(1);
505 : :
506 : 506 : PG_RETURN_BYTEA_P(bytea_catenate(t1, t2));
507 : 253 : }
508 : :
509 : : /*
510 : : * byteaoverlay
511 : : * Replace specified substring of first string with second
512 : : *
513 : : * The SQL standard defines OVERLAY() in terms of substring and concatenation.
514 : : * This code is a direct implementation of what the standard says.
515 : : */
516 : : Datum
517 : 1 : byteaoverlay(PG_FUNCTION_ARGS)
518 : : {
519 : 1 : bytea *t1 = PG_GETARG_BYTEA_PP(0);
520 : 1 : bytea *t2 = PG_GETARG_BYTEA_PP(1);
521 : 1 : int sp = PG_GETARG_INT32(2); /* substring start position */
522 : 1 : int sl = PG_GETARG_INT32(3); /* substring length */
523 : :
524 : 2 : PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
525 : 1 : }
526 : :
527 : : Datum
528 : 2 : byteaoverlay_no_len(PG_FUNCTION_ARGS)
529 : : {
530 : 2 : bytea *t1 = PG_GETARG_BYTEA_PP(0);
531 : 2 : bytea *t2 = PG_GETARG_BYTEA_PP(1);
532 : 2 : int sp = PG_GETARG_INT32(2); /* substring start position */
533 : 2 : int sl;
534 : :
535 : 2 : sl = VARSIZE_ANY_EXHDR(t2); /* defaults to length(t2) */
536 : 4 : PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
537 : 2 : }
538 : :
539 : : /*
540 : : * bytea_substr()
541 : : * Return a substring starting at the specified position.
542 : : * Cloned from text_substr and modified as required.
543 : : *
544 : : * Input:
545 : : * - string
546 : : * - starting position (is one-based)
547 : : * - string length (optional)
548 : : *
549 : : * If the starting position is zero or less, then return from the start of the string
550 : : * adjusting the length to be consistent with the "negative start" per SQL.
551 : : * If the length is less than zero, an ERROR is thrown. If no third argument
552 : : * (length) is provided, the length to the end of the string is assumed.
553 : : */
554 : : Datum
555 : 13 : bytea_substr(PG_FUNCTION_ARGS)
556 : : {
557 : 13 : PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
558 : : PG_GETARG_INT32(1),
559 : : PG_GETARG_INT32(2),
560 : : false));
561 : : }
562 : :
563 : : /*
564 : : * bytea_substr_no_len -
565 : : * Wrapper to avoid opr_sanity failure due to
566 : : * one function accepting a different number of args.
567 : : */
568 : : Datum
569 : 656 : bytea_substr_no_len(PG_FUNCTION_ARGS)
570 : : {
571 : 656 : PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
572 : : PG_GETARG_INT32(1),
573 : : -1,
574 : : true));
575 : : }
576 : :
577 : : /*
578 : : * bit_count
579 : : */
580 : : Datum
581 : 1 : bytea_bit_count(PG_FUNCTION_ARGS)
582 : : {
583 : 1 : bytea *t1 = PG_GETARG_BYTEA_PP(0);
584 : :
585 : 2 : PG_RETURN_INT64(pg_popcount(VARDATA_ANY(t1), VARSIZE_ANY_EXHDR(t1)));
586 : 1 : }
587 : :
588 : : /*
589 : : * byteapos -
590 : : * Return the position of the specified substring.
591 : : * Implements the SQL POSITION() function.
592 : : * Cloned from textpos and modified as required.
593 : : */
594 : : Datum
595 : 0 : byteapos(PG_FUNCTION_ARGS)
596 : : {
597 : 0 : bytea *t1 = PG_GETARG_BYTEA_PP(0);
598 : 0 : bytea *t2 = PG_GETARG_BYTEA_PP(1);
599 : 0 : int pos;
600 : 0 : int px,
601 : : p;
602 : 0 : int len1,
603 : : len2;
604 : 0 : char *p1,
605 : : *p2;
606 : :
607 : 0 : len1 = VARSIZE_ANY_EXHDR(t1);
608 : 0 : len2 = VARSIZE_ANY_EXHDR(t2);
609 : :
610 [ # # ]: 0 : if (len2 <= 0)
611 : 0 : PG_RETURN_INT32(1); /* result for empty pattern */
612 : :
613 : 0 : p1 = VARDATA_ANY(t1);
614 : 0 : p2 = VARDATA_ANY(t2);
615 : :
616 : 0 : pos = 0;
617 : 0 : px = (len1 - len2);
618 [ # # ]: 0 : for (p = 0; p <= px; p++)
619 : : {
620 [ # # # # ]: 0 : if ((*p2 == *p1) && (memcmp(p1, p2, len2) == 0))
621 : : {
622 : 0 : pos = p + 1;
623 : 0 : break;
624 : : };
625 : 0 : p1++;
626 : 0 : };
627 : :
628 : 0 : PG_RETURN_INT32(pos);
629 : 0 : }
630 : :
631 : : /*-------------------------------------------------------------
632 : : * byteaGetByte
633 : : *
634 : : * this routine treats "bytea" as an array of bytes.
635 : : * It returns the Nth byte (a number between 0 and 255).
636 : : *-------------------------------------------------------------
637 : : */
638 : : Datum
639 : 0 : byteaGetByte(PG_FUNCTION_ARGS)
640 : : {
641 : 0 : bytea *v = PG_GETARG_BYTEA_PP(0);
642 : 0 : int32 n = PG_GETARG_INT32(1);
643 : 0 : int len;
644 : 0 : int byte;
645 : :
646 : 0 : len = VARSIZE_ANY_EXHDR(v);
647 : :
648 [ # # ]: 0 : if (n < 0 || n >= len)
649 [ # # # # ]: 0 : ereport(ERROR,
650 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
651 : : errmsg("index %d out of valid range, 0..%d",
652 : : n, len - 1)));
653 : :
654 : 0 : byte = ((unsigned char *) VARDATA_ANY(v))[n];
655 : :
656 : 0 : PG_RETURN_INT32(byte);
657 : 0 : }
658 : :
659 : : /*-------------------------------------------------------------
660 : : * byteaGetBit
661 : : *
662 : : * This routine treats a "bytea" type like an array of bits.
663 : : * It returns the value of the Nth bit (0 or 1).
664 : : *
665 : : *-------------------------------------------------------------
666 : : */
667 : : Datum
668 : 0 : byteaGetBit(PG_FUNCTION_ARGS)
669 : : {
670 : 0 : bytea *v = PG_GETARG_BYTEA_PP(0);
671 : 0 : int64 n = PG_GETARG_INT64(1);
672 : 0 : int byteNo,
673 : : bitNo;
674 : 0 : int len;
675 : 0 : int byte;
676 : :
677 : 0 : len = VARSIZE_ANY_EXHDR(v);
678 : :
679 [ # # ]: 0 : if (n < 0 || n >= (int64) len * 8)
680 [ # # # # ]: 0 : ereport(ERROR,
681 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
682 : : errmsg("index %" PRId64 " out of valid range, 0..%" PRId64,
683 : : n, (int64) len * 8 - 1)));
684 : :
685 : : /* n/8 is now known < len, so safe to cast to int */
686 : 0 : byteNo = (int) (n / 8);
687 : 0 : bitNo = (int) (n % 8);
688 : :
689 : 0 : byte = ((unsigned char *) VARDATA_ANY(v))[byteNo];
690 : :
691 [ # # ]: 0 : if (byte & (1 << bitNo))
692 : 0 : PG_RETURN_INT32(1);
693 : : else
694 : 0 : PG_RETURN_INT32(0);
695 : 0 : }
696 : :
697 : : /*-------------------------------------------------------------
698 : : * byteaSetByte
699 : : *
700 : : * Given an instance of type 'bytea' creates a new one with
701 : : * the Nth byte set to the given value.
702 : : *
703 : : *-------------------------------------------------------------
704 : : */
705 : : Datum
706 : 0 : byteaSetByte(PG_FUNCTION_ARGS)
707 : : {
708 : 0 : bytea *res = PG_GETARG_BYTEA_P_COPY(0);
709 : 0 : int32 n = PG_GETARG_INT32(1);
710 : 0 : int32 newByte = PG_GETARG_INT32(2);
711 : 0 : int len;
712 : :
713 : 0 : len = VARSIZE(res) - VARHDRSZ;
714 : :
715 [ # # ]: 0 : if (n < 0 || n >= len)
716 [ # # # # ]: 0 : ereport(ERROR,
717 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
718 : : errmsg("index %d out of valid range, 0..%d",
719 : : n, len - 1)));
720 : :
721 : : /*
722 : : * Now set the byte.
723 : : */
724 : 0 : ((unsigned char *) VARDATA(res))[n] = newByte;
725 : :
726 : 0 : PG_RETURN_BYTEA_P(res);
727 : 0 : }
728 : :
729 : : /*-------------------------------------------------------------
730 : : * byteaSetBit
731 : : *
732 : : * Given an instance of type 'bytea' creates a new one with
733 : : * the Nth bit set to the given value.
734 : : *
735 : : *-------------------------------------------------------------
736 : : */
737 : : Datum
738 : 0 : byteaSetBit(PG_FUNCTION_ARGS)
739 : : {
740 : 0 : bytea *res = PG_GETARG_BYTEA_P_COPY(0);
741 : 0 : int64 n = PG_GETARG_INT64(1);
742 : 0 : int32 newBit = PG_GETARG_INT32(2);
743 : 0 : int len;
744 : 0 : int oldByte,
745 : : newByte;
746 : 0 : int byteNo,
747 : : bitNo;
748 : :
749 : 0 : len = VARSIZE(res) - VARHDRSZ;
750 : :
751 [ # # ]: 0 : if (n < 0 || n >= (int64) len * 8)
752 [ # # # # ]: 0 : ereport(ERROR,
753 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
754 : : errmsg("index %" PRId64 " out of valid range, 0..%" PRId64,
755 : : n, (int64) len * 8 - 1)));
756 : :
757 : : /* n/8 is now known < len, so safe to cast to int */
758 : 0 : byteNo = (int) (n / 8);
759 : 0 : bitNo = (int) (n % 8);
760 : :
761 : : /*
762 : : * sanity check!
763 : : */
764 [ # # # # ]: 0 : if (newBit != 0 && newBit != 1)
765 [ # # # # ]: 0 : ereport(ERROR,
766 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
767 : : errmsg("new bit must be 0 or 1")));
768 : :
769 : : /*
770 : : * Update the byte.
771 : : */
772 : 0 : oldByte = ((unsigned char *) VARDATA(res))[byteNo];
773 : :
774 [ # # ]: 0 : if (newBit == 0)
775 : 0 : newByte = oldByte & (~(1 << bitNo));
776 : : else
777 : 0 : newByte = oldByte | (1 << bitNo);
778 : :
779 : 0 : ((unsigned char *) VARDATA(res))[byteNo] = newByte;
780 : :
781 : 0 : PG_RETURN_BYTEA_P(res);
782 : 0 : }
783 : :
784 : : /*
785 : : * Return reversed bytea
786 : : */
787 : : Datum
788 : 0 : bytea_reverse(PG_FUNCTION_ARGS)
789 : : {
790 : 0 : bytea *v = PG_GETARG_BYTEA_PP(0);
791 : 0 : const char *p = VARDATA_ANY(v);
792 : 0 : int len = VARSIZE_ANY_EXHDR(v);
793 : 0 : const char *endp = p + len;
794 : 0 : bytea *result = palloc(len + VARHDRSZ);
795 : 0 : char *dst = (char *) VARDATA(result) + len;
796 : :
797 : 0 : SET_VARSIZE(result, len + VARHDRSZ);
798 : :
799 [ # # ]: 0 : while (p < endp)
800 : 0 : *(--dst) = *p++;
801 : :
802 : 0 : PG_RETURN_BYTEA_P(result);
803 : 0 : }
804 : :
805 : :
806 : : /*****************************************************************************
807 : : * Comparison Functions used for bytea
808 : : *
809 : : * Note: btree indexes need these routines not to leak memory; therefore,
810 : : * be careful to free working copies of toasted datums. Most places don't
811 : : * need to be so careful.
812 : : *****************************************************************************/
813 : :
814 : : Datum
815 : 0 : byteaeq(PG_FUNCTION_ARGS)
816 : : {
817 : 0 : Datum arg1 = PG_GETARG_DATUM(0);
818 : 0 : Datum arg2 = PG_GETARG_DATUM(1);
819 : 0 : bool result;
820 : 0 : Size len1,
821 : : len2;
822 : :
823 : : /*
824 : : * We can use a fast path for unequal lengths, which might save us from
825 : : * having to detoast one or both values.
826 : : */
827 : 0 : len1 = toast_raw_datum_size(arg1);
828 : 0 : len2 = toast_raw_datum_size(arg2);
829 [ # # ]: 0 : if (len1 != len2)
830 : 0 : result = false;
831 : : else
832 : : {
833 : 0 : bytea *barg1 = DatumGetByteaPP(arg1);
834 : 0 : bytea *barg2 = DatumGetByteaPP(arg2);
835 : :
836 : 0 : result = (memcmp(VARDATA_ANY(barg1), VARDATA_ANY(barg2),
837 : 0 : len1 - VARHDRSZ) == 0);
838 : :
839 [ # # ]: 0 : PG_FREE_IF_COPY(barg1, 0);
840 [ # # ]: 0 : PG_FREE_IF_COPY(barg2, 1);
841 : 0 : }
842 : :
843 : 0 : PG_RETURN_BOOL(result);
844 : 0 : }
845 : :
846 : : Datum
847 : 0 : byteane(PG_FUNCTION_ARGS)
848 : : {
849 : 0 : Datum arg1 = PG_GETARG_DATUM(0);
850 : 0 : Datum arg2 = PG_GETARG_DATUM(1);
851 : 0 : bool result;
852 : 0 : Size len1,
853 : : len2;
854 : :
855 : : /*
856 : : * We can use a fast path for unequal lengths, which might save us from
857 : : * having to detoast one or both values.
858 : : */
859 : 0 : len1 = toast_raw_datum_size(arg1);
860 : 0 : len2 = toast_raw_datum_size(arg2);
861 [ # # ]: 0 : if (len1 != len2)
862 : 0 : result = true;
863 : : else
864 : : {
865 : 0 : bytea *barg1 = DatumGetByteaPP(arg1);
866 : 0 : bytea *barg2 = DatumGetByteaPP(arg2);
867 : :
868 : 0 : result = (memcmp(VARDATA_ANY(barg1), VARDATA_ANY(barg2),
869 : 0 : len1 - VARHDRSZ) != 0);
870 : :
871 [ # # ]: 0 : PG_FREE_IF_COPY(barg1, 0);
872 [ # # ]: 0 : PG_FREE_IF_COPY(barg2, 1);
873 : 0 : }
874 : :
875 : 0 : PG_RETURN_BOOL(result);
876 : 0 : }
877 : :
878 : : Datum
879 : 0 : bytealt(PG_FUNCTION_ARGS)
880 : : {
881 : 0 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
882 : 0 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
883 : 0 : int len1,
884 : : len2;
885 : 0 : int cmp;
886 : :
887 : 0 : len1 = VARSIZE_ANY_EXHDR(arg1);
888 : 0 : len2 = VARSIZE_ANY_EXHDR(arg2);
889 : :
890 [ # # ]: 0 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
891 : :
892 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
893 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
894 : :
895 [ # # # # ]: 0 : PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 < len2)));
896 : 0 : }
897 : :
898 : : Datum
899 : 0 : byteale(PG_FUNCTION_ARGS)
900 : : {
901 : 0 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
902 : 0 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
903 : 0 : int len1,
904 : : len2;
905 : 0 : int cmp;
906 : :
907 : 0 : len1 = VARSIZE_ANY_EXHDR(arg1);
908 : 0 : len2 = VARSIZE_ANY_EXHDR(arg2);
909 : :
910 [ # # ]: 0 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
911 : :
912 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
913 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
914 : :
915 [ # # # # ]: 0 : PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 <= len2)));
916 : 0 : }
917 : :
918 : : Datum
919 : 0 : byteagt(PG_FUNCTION_ARGS)
920 : : {
921 : 0 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
922 : 0 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
923 : 0 : int len1,
924 : : len2;
925 : 0 : int cmp;
926 : :
927 : 0 : len1 = VARSIZE_ANY_EXHDR(arg1);
928 : 0 : len2 = VARSIZE_ANY_EXHDR(arg2);
929 : :
930 [ # # ]: 0 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
931 : :
932 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
933 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
934 : :
935 [ # # # # ]: 0 : PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 > len2)));
936 : 0 : }
937 : :
938 : : Datum
939 : 0 : byteage(PG_FUNCTION_ARGS)
940 : : {
941 : 0 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
942 : 0 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
943 : 0 : int len1,
944 : : len2;
945 : 0 : int cmp;
946 : :
947 : 0 : len1 = VARSIZE_ANY_EXHDR(arg1);
948 : 0 : len2 = VARSIZE_ANY_EXHDR(arg2);
949 : :
950 [ # # ]: 0 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
951 : :
952 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
953 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
954 : :
955 [ # # # # ]: 0 : PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 >= len2)));
956 : 0 : }
957 : :
958 : : Datum
959 : 0 : byteacmp(PG_FUNCTION_ARGS)
960 : : {
961 : 0 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
962 : 0 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
963 : 0 : int len1,
964 : : len2;
965 : 0 : int cmp;
966 : :
967 : 0 : len1 = VARSIZE_ANY_EXHDR(arg1);
968 : 0 : len2 = VARSIZE_ANY_EXHDR(arg2);
969 : :
970 [ # # ]: 0 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
971 [ # # # # ]: 0 : if ((cmp == 0) && (len1 != len2))
972 : 0 : cmp = (len1 < len2) ? -1 : 1;
973 : :
974 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
975 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
976 : :
977 : 0 : PG_RETURN_INT32(cmp);
978 : 0 : }
979 : :
980 : : Datum
981 : 0 : bytea_larger(PG_FUNCTION_ARGS)
982 : : {
983 : 0 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
984 : 0 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
985 : 0 : bytea *result;
986 : 0 : int len1,
987 : : len2;
988 : 0 : int cmp;
989 : :
990 : 0 : len1 = VARSIZE_ANY_EXHDR(arg1);
991 : 0 : len2 = VARSIZE_ANY_EXHDR(arg2);
992 : :
993 [ # # ]: 0 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
994 [ # # # # : 0 : result = ((cmp > 0) || ((cmp == 0) && (len1 > len2)) ? arg1 : arg2);
# # ]
995 : :
996 : 0 : PG_RETURN_BYTEA_P(result);
997 : 0 : }
998 : :
999 : : Datum
1000 : 0 : bytea_smaller(PG_FUNCTION_ARGS)
1001 : : {
1002 : 0 : bytea *arg1 = PG_GETARG_BYTEA_PP(0);
1003 : 0 : bytea *arg2 = PG_GETARG_BYTEA_PP(1);
1004 : 0 : bytea *result;
1005 : 0 : int len1,
1006 : : len2;
1007 : 0 : int cmp;
1008 : :
1009 : 0 : len1 = VARSIZE_ANY_EXHDR(arg1);
1010 : 0 : len2 = VARSIZE_ANY_EXHDR(arg2);
1011 : :
1012 [ # # ]: 0 : cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
1013 [ # # # # : 0 : result = ((cmp < 0) || ((cmp == 0) && (len1 < len2)) ? arg1 : arg2);
# # ]
1014 : :
1015 : 0 : PG_RETURN_BYTEA_P(result);
1016 : 0 : }
1017 : :
1018 : : /*
1019 : : * sortsupport comparison func
1020 : : */
1021 : : static int
1022 : 0 : byteafastcmp(Datum x, Datum y, SortSupport ssup)
1023 : : {
1024 : 0 : bytea *arg1 = DatumGetByteaPP(x);
1025 : 0 : bytea *arg2 = DatumGetByteaPP(y);
1026 : 0 : char *a1p,
1027 : : *a2p;
1028 : 0 : int len1,
1029 : : len2,
1030 : : result;
1031 : :
1032 : 0 : a1p = VARDATA_ANY(arg1);
1033 : 0 : a2p = VARDATA_ANY(arg2);
1034 : :
1035 : 0 : len1 = VARSIZE_ANY_EXHDR(arg1);
1036 : 0 : len2 = VARSIZE_ANY_EXHDR(arg2);
1037 : :
1038 [ # # ]: 0 : result = memcmp(a1p, a2p, Min(len1, len2));
1039 [ # # # # ]: 0 : if ((result == 0) && (len1 != len2))
1040 : 0 : result = (len1 < len2) ? -1 : 1;
1041 : :
1042 : : /* We can't afford to leak memory here. */
1043 [ # # ]: 0 : if (PointerGetDatum(arg1) != x)
1044 : 0 : pfree(arg1);
1045 [ # # ]: 0 : if (PointerGetDatum(arg2) != y)
1046 : 0 : pfree(arg2);
1047 : :
1048 : 0 : return result;
1049 : 0 : }
1050 : :
1051 : : /*
1052 : : * Conversion routine for sortsupport. Converts original to abbreviated key
1053 : : * representation. Our encoding strategy is simple -- pack the first 8 bytes
1054 : : * of the bytea data into a Datum (on little-endian machines, the bytes are
1055 : : * stored in reverse order), and treat it as an unsigned integer.
1056 : : */
1057 : : static Datum
1058 : 0 : bytea_abbrev_convert(Datum original, SortSupport ssup)
1059 : : {
1060 : 0 : const size_t max_prefix_bytes = sizeof(Datum);
1061 : 0 : ByteaSortSupport *bss = (ByteaSortSupport *) ssup->ssup_extra;
1062 : 0 : bytea *authoritative = DatumGetByteaPP(original);
1063 : 0 : char *authoritative_data = VARDATA_ANY(authoritative);
1064 : 0 : Datum res;
1065 : 0 : char *pres;
1066 : 0 : int len;
1067 : 0 : uint32 hash;
1068 : :
1069 : 0 : pres = (char *) &res;
1070 : :
1071 : : /* memset(), so any non-overwritten bytes are NUL */
1072 : 0 : memset(pres, 0, max_prefix_bytes);
1073 : 0 : len = VARSIZE_ANY_EXHDR(authoritative);
1074 : :
1075 : : /*
1076 : : * Short byteas will have terminating NUL bytes in the abbreviated datum.
1077 : : * Abbreviated comparison need not make a distinction between these NUL
1078 : : * bytes, and NUL bytes representing actual NULs in the authoritative
1079 : : * representation.
1080 : : *
1081 : : * Hopefully a comparison at or past one abbreviated key's terminating NUL
1082 : : * byte will resolve the comparison without consulting the authoritative
1083 : : * representation; specifically, some later non-NUL byte in the longer
1084 : : * bytea can resolve the comparison against a subsequent terminating NUL
1085 : : * in the shorter bytea. There will usually be what is effectively a
1086 : : * "length-wise" resolution there and then.
1087 : : *
1088 : : * If that doesn't work out -- if all bytes in the longer bytea positioned
1089 : : * at or past the offset of the smaller bytea (first) terminating NUL are
1090 : : * actually representative of NUL bytes in the authoritative binary bytea
1091 : : * (perhaps with some *terminating* NUL bytes towards the end of the
1092 : : * longer bytea iff it happens to still be small) -- then an authoritative
1093 : : * tie-breaker will happen, and do the right thing: explicitly consider
1094 : : * bytea length.
1095 : : */
1096 [ # # ]: 0 : memcpy(pres, authoritative_data, Min(len, max_prefix_bytes));
1097 : :
1098 : : /*
1099 : : * Maintain approximate cardinality of both abbreviated keys and original,
1100 : : * authoritative keys using HyperLogLog. Used as cheap insurance against
1101 : : * the worst case, where we do many string abbreviations for no saving in
1102 : : * full memcmp()-based comparisons. These statistics are used by
1103 : : * bytea_abbrev_abort().
1104 : : *
1105 : : * First, Hash key proper, or a significant fraction of it. Mix in length
1106 : : * in order to compensate for cases where differences are past
1107 : : * PG_CACHE_LINE_SIZE bytes, so as to limit the overhead of hashing.
1108 : : */
1109 : 0 : hash = DatumGetUInt32(hash_any((unsigned char *) authoritative_data,
1110 [ # # ]: 0 : Min(len, PG_CACHE_LINE_SIZE)));
1111 : :
1112 [ # # ]: 0 : if (len > PG_CACHE_LINE_SIZE)
1113 : 0 : hash ^= DatumGetUInt32(hash_uint32((uint32) len));
1114 : :
1115 : 0 : addHyperLogLog(&bss->full_card, hash);
1116 : :
1117 : : /* Hash abbreviated key */
1118 : : {
1119 : 0 : uint32 tmp;
1120 : :
1121 : 0 : tmp = DatumGetUInt32(res) ^ (uint32) (DatumGetUInt64(res) >> 32);
1122 : 0 : hash = DatumGetUInt32(hash_uint32(tmp));
1123 : 0 : }
1124 : :
1125 : 0 : addHyperLogLog(&bss->abbr_card, hash);
1126 : :
1127 : : /*
1128 : : * Byteswap on little-endian machines.
1129 : : *
1130 : : * This is needed so that ssup_datum_unsigned_cmp() works correctly on all
1131 : : * platforms.
1132 : : */
1133 : 0 : res = DatumBigEndianToNative(res);
1134 : :
1135 : : /* Don't leak memory here */
1136 [ # # ]: 0 : if (PointerGetDatum(authoritative) != original)
1137 : 0 : pfree(authoritative);
1138 : :
1139 : 0 : return res;
1140 : 0 : }
1141 : :
1142 : : /*
1143 : : * Callback for estimating effectiveness of abbreviated key optimization, using
1144 : : * heuristic rules. Returns value indicating if the abbreviation optimization
1145 : : * should be aborted, based on its projected effectiveness.
1146 : : *
1147 : : * This is based on varstr_abbrev_abort(), but some comments have been elided
1148 : : * for brevity. See there for more details.
1149 : : */
1150 : : static bool
1151 : 0 : bytea_abbrev_abort(int memtupcount, SortSupport ssup)
1152 : : {
1153 : 0 : ByteaSortSupport *bss = (ByteaSortSupport *) ssup->ssup_extra;
1154 : 0 : double abbrev_distinct,
1155 : : key_distinct;
1156 : :
1157 [ # # ]: 0 : Assert(ssup->abbreviate);
1158 : :
1159 : : /* Have a little patience */
1160 [ # # ]: 0 : if (memtupcount < 100)
1161 : 0 : return false;
1162 : :
1163 : 0 : abbrev_distinct = estimateHyperLogLog(&bss->abbr_card);
1164 : 0 : key_distinct = estimateHyperLogLog(&bss->full_card);
1165 : :
1166 : : /*
1167 : : * Clamp cardinality estimates to at least one distinct value. While
1168 : : * NULLs are generally disregarded, if only NULL values were seen so far,
1169 : : * that might misrepresent costs if we failed to clamp.
1170 : : */
1171 [ # # ]: 0 : if (abbrev_distinct < 1.0)
1172 : 0 : abbrev_distinct = 1.0;
1173 : :
1174 [ # # ]: 0 : if (key_distinct < 1.0)
1175 : 0 : key_distinct = 1.0;
1176 : :
1177 [ # # ]: 0 : if (trace_sort)
1178 : : {
1179 : 0 : double norm_abbrev_card = abbrev_distinct / (double) memtupcount;
1180 : :
1181 [ # # # # ]: 0 : elog(LOG, "bytea_abbrev: abbrev_distinct after %d: %f "
1182 : : "(key_distinct: %f, norm_abbrev_card: %f, prop_card: %f)",
1183 : : memtupcount, abbrev_distinct, key_distinct, norm_abbrev_card,
1184 : : bss->prop_card);
1185 : 0 : }
1186 : :
1187 : : /*
1188 : : * If the number of distinct abbreviated keys approximately matches the
1189 : : * number of distinct original keys, continue with abbreviation.
1190 : : */
1191 [ # # ]: 0 : if (abbrev_distinct > key_distinct * bss->prop_card)
1192 : : {
1193 : : /*
1194 : : * Decay required cardinality aggressively after 10,000 tuples.
1195 : : */
1196 [ # # ]: 0 : if (memtupcount > 10000)
1197 : 0 : bss->prop_card *= 0.65;
1198 : :
1199 : 0 : return false;
1200 : : }
1201 : :
1202 : : /*
1203 : : * Abort abbreviation strategy.
1204 : : */
1205 [ # # ]: 0 : if (trace_sort)
1206 [ # # # # ]: 0 : elog(LOG, "bytea_abbrev: aborted abbreviation at %d "
1207 : : "(abbrev_distinct: %f, key_distinct: %f, prop_card: %f)",
1208 : : memtupcount, abbrev_distinct, key_distinct, bss->prop_card);
1209 : :
1210 : 0 : return true;
1211 : 0 : }
1212 : :
1213 : : Datum
1214 : 0 : bytea_sortsupport(PG_FUNCTION_ARGS)
1215 : : {
1216 : 0 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
1217 : 0 : MemoryContext oldcontext;
1218 : :
1219 : 0 : oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
1220 : :
1221 : 0 : ssup->comparator = byteafastcmp;
1222 : :
1223 : : /*
1224 : : * Set up abbreviation support if requested.
1225 : : */
1226 [ # # ]: 0 : if (ssup->abbreviate)
1227 : : {
1228 : 0 : ByteaSortSupport *bss;
1229 : :
1230 : 0 : bss = palloc_object(ByteaSortSupport);
1231 : 0 : bss->abbreviate = true;
1232 : 0 : bss->prop_card = 0.20;
1233 : 0 : initHyperLogLog(&bss->abbr_card, 10);
1234 : 0 : initHyperLogLog(&bss->full_card, 10);
1235 : :
1236 : 0 : ssup->ssup_extra = bss;
1237 : 0 : ssup->abbrev_full_comparator = ssup->comparator;
1238 : 0 : ssup->comparator = ssup_datum_unsigned_cmp;
1239 : 0 : ssup->abbrev_converter = bytea_abbrev_convert;
1240 : 0 : ssup->abbrev_abort = bytea_abbrev_abort;
1241 : 0 : }
1242 : :
1243 : 0 : MemoryContextSwitchTo(oldcontext);
1244 : :
1245 : 0 : PG_RETURN_VOID();
1246 : 0 : }
1247 : :
1248 : : /* Cast bytea -> int2 */
1249 : : Datum
1250 : 0 : bytea_int2(PG_FUNCTION_ARGS)
1251 : : {
1252 : 0 : bytea *v = PG_GETARG_BYTEA_PP(0);
1253 : 0 : int len = VARSIZE_ANY_EXHDR(v);
1254 : 0 : uint16 result;
1255 : :
1256 : : /* Check that the byte array is not too long */
1257 [ # # ]: 0 : if (len > sizeof(result))
1258 [ # # # # ]: 0 : ereport(ERROR,
1259 : : errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1260 : : errmsg("smallint out of range"));
1261 : :
1262 : : /* Convert it to an integer; most significant bytes come first */
1263 : 0 : result = 0;
1264 [ # # ]: 0 : for (int i = 0; i < len; i++)
1265 : : {
1266 : 0 : result <<= BITS_PER_BYTE;
1267 : 0 : result |= ((unsigned char *) VARDATA_ANY(v))[i];
1268 : 0 : }
1269 : :
1270 : 0 : PG_RETURN_INT16(result);
1271 : 0 : }
1272 : :
1273 : : /* Cast bytea -> int4 */
1274 : : Datum
1275 : 0 : bytea_int4(PG_FUNCTION_ARGS)
1276 : : {
1277 : 0 : bytea *v = PG_GETARG_BYTEA_PP(0);
1278 : 0 : int len = VARSIZE_ANY_EXHDR(v);
1279 : 0 : uint32 result;
1280 : :
1281 : : /* Check that the byte array is not too long */
1282 [ # # ]: 0 : if (len > sizeof(result))
1283 [ # # # # ]: 0 : ereport(ERROR,
1284 : : errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1285 : : errmsg("integer out of range"));
1286 : :
1287 : : /* Convert it to an integer; most significant bytes come first */
1288 : 0 : result = 0;
1289 [ # # ]: 0 : for (int i = 0; i < len; i++)
1290 : : {
1291 : 0 : result <<= BITS_PER_BYTE;
1292 : 0 : result |= ((unsigned char *) VARDATA_ANY(v))[i];
1293 : 0 : }
1294 : :
1295 : 0 : PG_RETURN_INT32(result);
1296 : 0 : }
1297 : :
1298 : : /* Cast bytea -> int8 */
1299 : : Datum
1300 : 0 : bytea_int8(PG_FUNCTION_ARGS)
1301 : : {
1302 : 0 : bytea *v = PG_GETARG_BYTEA_PP(0);
1303 : 0 : int len = VARSIZE_ANY_EXHDR(v);
1304 : 0 : uint64 result;
1305 : :
1306 : : /* Check that the byte array is not too long */
1307 [ # # ]: 0 : if (len > sizeof(result))
1308 [ # # # # ]: 0 : ereport(ERROR,
1309 : : errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1310 : : errmsg("bigint out of range"));
1311 : :
1312 : : /* Convert it to an integer; most significant bytes come first */
1313 : 0 : result = 0;
1314 [ # # ]: 0 : for (int i = 0; i < len; i++)
1315 : : {
1316 : 0 : result <<= BITS_PER_BYTE;
1317 : 0 : result |= ((unsigned char *) VARDATA_ANY(v))[i];
1318 : 0 : }
1319 : :
1320 : 0 : PG_RETURN_INT64(result);
1321 : 0 : }
1322 : :
1323 : : /* Cast int2 -> bytea; can just use int2send() */
1324 : : Datum
1325 : 0 : int2_bytea(PG_FUNCTION_ARGS)
1326 : : {
1327 : 0 : return int2send(fcinfo);
1328 : : }
1329 : :
1330 : : /* Cast int4 -> bytea; can just use int4send() */
1331 : : Datum
1332 : 0 : int4_bytea(PG_FUNCTION_ARGS)
1333 : : {
1334 : 0 : return int4send(fcinfo);
1335 : : }
1336 : :
1337 : : /* Cast int8 -> bytea; can just use int8send() */
1338 : : Datum
1339 : 0 : int8_bytea(PG_FUNCTION_ARGS)
1340 : : {
1341 : 0 : return int8send(fcinfo);
1342 : : }
|