Coverage Report

Created: 2026-08-13 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/adt/varchar.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * varchar.c
4
 *    Functions for the built-in types char(n) and varchar(n).
5
 *
6
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 *
10
 * IDENTIFICATION
11
 *    src/backend/utils/adt/varchar.c
12
 *
13
 *-------------------------------------------------------------------------
14
 */
15
#include "postgres.h"
16
17
#include "access/detoast.h"
18
#include "access/htup_details.h"
19
#include "catalog/pg_collation.h"
20
#include "catalog/pg_type.h"
21
#include "common/hashfn.h"
22
#include "libpq/pqformat.h"
23
#include "mb/pg_wchar.h"
24
#include "nodes/nodeFuncs.h"
25
#include "nodes/supportnodes.h"
26
#include "utils/array.h"
27
#include "utils/builtins.h"
28
#include "utils/pg_locale.h"
29
#include "utils/varlena.h"
30
31
/* common code for bpchartypmodin and varchartypmodin */
32
static int32
33
anychar_typmodin(ArrayType *ta, const char *typename)
34
0
{
35
0
  int32   typmod;
36
0
  int32    *tl;
37
0
  int     n;
38
39
0
  tl = ArrayGetIntegerTypmods(ta, &n);
40
41
  /*
42
   * we're not too tense about good error message here because grammar
43
   * shouldn't allow wrong number of modifiers for CHAR
44
   */
45
0
  if (n != 1)
46
0
    ereport(ERROR,
47
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
48
0
         errmsg("invalid type modifier")));
49
50
0
  if (*tl < 1)
51
0
    ereport(ERROR,
52
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
53
0
         errmsg("length for type %s must be at least 1", typename)));
54
0
  if (*tl > MaxAttrSize)
55
0
    ereport(ERROR,
56
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
57
0
         errmsg("length for type %s cannot exceed %d",
58
0
            typename, MaxAttrSize)));
59
60
  /*
61
   * For largely historical reasons, the typmod is VARHDRSZ plus the number
62
   * of characters; there is enough client-side code that knows about that
63
   * that we'd better not change it.
64
   */
65
0
  typmod = VARHDRSZ + *tl;
66
67
0
  return typmod;
68
0
}
69
70
/* common code for bpchartypmodout and varchartypmodout */
71
static char *
72
anychar_typmodout(int32 typmod)
73
0
{
74
0
  char     *res = (char *) palloc(64);
75
76
0
  if (typmod > VARHDRSZ)
77
0
    snprintf(res, 64, "(%d)", (int) (typmod - VARHDRSZ));
78
0
  else
79
0
    *res = '\0';
80
81
0
  return res;
82
0
}
83
84
85
/*
86
 * CHAR() and VARCHAR() types are part of the SQL standard. CHAR()
87
 * is for blank-padded string whose length is specified in CREATE TABLE.
88
 * VARCHAR is for storing string whose length is at most the length specified
89
 * at CREATE TABLE time.
90
 *
91
 * It's hard to implement these types because we cannot figure out
92
 * the length of the type from the type itself. I changed (hopefully all) the
93
 * fmgr calls that invoke input functions of a data type to supply the
94
 * length also. (eg. in INSERTs, we have the tupleDescriptor which contains
95
 * the length of the attributes and hence the exact length of the char() or
96
 * varchar(). We pass this to bpcharin() or varcharin().) In the case where
97
 * we cannot determine the length, we pass in -1 instead and the input
98
 * converter does not enforce any length check.
99
 *
100
 * We actually implement this as a varlena so that we don't have to pass in
101
 * the length for the comparison functions. (The difference between these
102
 * types and "text" is that we truncate and possibly blank-pad the string
103
 * at insertion time.)
104
 *
105
 *                                - ay 6/95
106
 */
107
108
109
/*****************************************************************************
110
 *   bpchar - char()                             *
111
 *****************************************************************************/
112
113
/*
114
 * bpchar_input -- common guts of bpcharin and bpcharrecv
115
 *
116
 * s is the input text of length len (may not be null-terminated)
117
 * atttypmod is the typmod value to apply
118
 *
119
 * Note that atttypmod is measured in characters, which
120
 * is not necessarily the same as the number of bytes.
121
 *
122
 * If the input string is too long, raise an error, unless the extra
123
 * characters are spaces, in which case they're truncated.  (per SQL)
124
 *
125
 * If escontext points to an ErrorSaveContext node, that is filled instead
126
 * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
127
 * to detect errors.
128
 */
129
static BpChar *
130
bpchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext)
131
0
{
132
0
  BpChar     *result;
133
0
  char     *r;
134
0
  size_t    maxlen;
135
136
  /* If typmod is -1 (or invalid), use the actual string length */
137
0
  if (atttypmod < (int32) VARHDRSZ)
138
0
    maxlen = len;
139
0
  else
140
0
  {
141
0
    size_t    charlen;  /* number of CHARACTERS in the input */
142
143
0
    maxlen = atttypmod - VARHDRSZ;
144
0
    charlen = pg_mbstrlen_with_len(s, len);
145
0
    if (charlen > maxlen)
146
0
    {
147
      /* Verify that extra characters are spaces, and clip them off */
148
0
      size_t    mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
149
0
      size_t    j;
150
151
      /*
152
       * at this point, len is the actual BYTE length of the input
153
       * string, maxlen is the max number of CHARACTERS allowed for this
154
       * bpchar type, mbmaxlen is the length in BYTES of those chars.
155
       */
156
0
      for (j = mbmaxlen; j < len; j++)
157
0
      {
158
0
        if (s[j] != ' ')
159
0
          ereturn(escontext, NULL,
160
0
              (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
161
0
               errmsg("value too long for type character(%zu)",
162
0
                  maxlen)));
163
0
      }
164
165
      /*
166
       * Now we set maxlen to the necessary byte length, not the number
167
       * of CHARACTERS!
168
       */
169
0
      maxlen = len = mbmaxlen;
170
0
    }
171
0
    else
172
0
    {
173
      /*
174
       * Now we set maxlen to the necessary byte length, not the number
175
       * of CHARACTERS!
176
       */
177
0
      maxlen = len + (maxlen - charlen);
178
0
    }
179
0
  }
180
181
0
  result = (BpChar *) palloc(maxlen + VARHDRSZ);
182
0
  SET_VARSIZE(result, maxlen + VARHDRSZ);
183
0
  r = VARDATA(result);
184
0
  memcpy(r, s, len);
185
186
  /* blank pad the string if necessary */
187
0
  if (maxlen > len)
188
0
    memset(r + len, ' ', maxlen - len);
189
190
0
  return result;
191
0
}
192
193
/*
194
 * Convert a C string to CHARACTER internal representation.  atttypmod
195
 * is the declared length of the type plus VARHDRSZ.
196
 */
197
Datum
198
bpcharin(PG_FUNCTION_ARGS)
199
0
{
200
0
  char     *s = PG_GETARG_CSTRING(0);
201
#ifdef NOT_USED
202
  Oid     typelem = PG_GETARG_OID(1);
203
#endif
204
0
  int32   atttypmod = PG_GETARG_INT32(2);
205
0
  BpChar     *result;
206
207
0
  result = bpchar_input(s, strlen(s), atttypmod, fcinfo->context);
208
0
  PG_RETURN_BPCHAR_P(result);
209
0
}
210
211
212
/*
213
 * Convert a CHARACTER value to a C string.
214
 *
215
 * Uses the text conversion functions, which is only appropriate if BpChar
216
 * and text are equivalent types.
217
 */
218
Datum
219
bpcharout(PG_FUNCTION_ARGS)
220
0
{
221
0
  Datum   txt = PG_GETARG_DATUM(0);
222
223
0
  PG_RETURN_CSTRING(TextDatumGetCString(txt));
224
0
}
225
226
/*
227
 *    bpcharrecv      - converts external binary format to bpchar
228
 */
229
Datum
230
bpcharrecv(PG_FUNCTION_ARGS)
231
0
{
232
0
  StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
233
#ifdef NOT_USED
234
  Oid     typelem = PG_GETARG_OID(1);
235
#endif
236
0
  int32   atttypmod = PG_GETARG_INT32(2);
237
0
  BpChar     *result;
238
0
  char     *str;
239
0
  int     nbytes;
240
241
0
  str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
242
0
  result = bpchar_input(str, nbytes, atttypmod, NULL);
243
0
  pfree(str);
244
0
  PG_RETURN_BPCHAR_P(result);
245
0
}
246
247
/*
248
 *    bpcharsend      - converts bpchar to binary format
249
 */
250
Datum
251
bpcharsend(PG_FUNCTION_ARGS)
252
0
{
253
  /* Exactly the same as textsend, so share code */
254
0
  return textsend(fcinfo);
255
0
}
256
257
258
/*
259
 * Converts a CHARACTER type to the specified size.
260
 *
261
 * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
262
 * isExplicit is true if this is for an explicit cast to char(N).
263
 *
264
 * Truncation rules: for an explicit cast, silently truncate to the given
265
 * length; for an implicit cast, raise error unless extra characters are
266
 * all spaces.  (This is sort-of per SQL: the spec would actually have us
267
 * raise a "completion condition" for the explicit cast case, but Postgres
268
 * hasn't got such a concept.)
269
 */
270
Datum
271
bpchar(PG_FUNCTION_ARGS)
272
0
{
273
0
  BpChar     *source = PG_GETARG_BPCHAR_PP(0);
274
0
  int32   maxlen = PG_GETARG_INT32(1);
275
0
  bool    isExplicit = PG_GETARG_BOOL(2);
276
0
  BpChar     *result;
277
0
  int32   len;
278
0
  char     *r;
279
0
  char     *s;
280
0
  int     i;
281
0
  int     charlen;    /* number of characters in the input string +
282
                 * VARHDRSZ */
283
284
  /* No work if typmod is invalid */
285
0
  if (maxlen < (int32) VARHDRSZ)
286
0
    PG_RETURN_BPCHAR_P(source);
287
288
0
  maxlen -= VARHDRSZ;
289
290
0
  len = VARSIZE_ANY_EXHDR(source);
291
0
  s = VARDATA_ANY(source);
292
293
0
  charlen = pg_mbstrlen_with_len(s, len);
294
295
  /* No work if supplied data matches typmod already */
296
0
  if (charlen == maxlen)
297
0
    PG_RETURN_BPCHAR_P(source);
298
299
0
  if (charlen > maxlen)
300
0
  {
301
    /* Verify that extra characters are spaces, and clip them off */
302
0
    size_t    maxmblen;
303
304
0
    maxmblen = pg_mbcharcliplen(s, len, maxlen);
305
306
0
    if (!isExplicit)
307
0
    {
308
0
      for (i = maxmblen; i < len; i++)
309
0
        if (s[i] != ' ')
310
0
          ereturn(fcinfo->context, (Datum) 0,
311
0
              (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
312
0
               errmsg("value too long for type character(%d)",
313
0
                  maxlen)));
314
0
    }
315
316
0
    len = maxmblen;
317
318
    /*
319
     * At this point, maxlen is the necessary byte length, not the number
320
     * of CHARACTERS!
321
     */
322
0
    maxlen = len;
323
0
  }
324
0
  else
325
0
  {
326
    /*
327
     * At this point, maxlen is the necessary byte length, not the number
328
     * of CHARACTERS!
329
     */
330
0
    maxlen = len + (maxlen - charlen);
331
0
  }
332
333
0
  Assert(maxlen >= len);
334
335
0
  result = palloc(maxlen + VARHDRSZ);
336
0
  SET_VARSIZE(result, maxlen + VARHDRSZ);
337
0
  r = VARDATA(result);
338
339
0
  memcpy(r, s, len);
340
341
  /* blank pad the string if necessary */
342
0
  if (maxlen > len)
343
0
    memset(r + len, ' ', maxlen - len);
344
345
0
  PG_RETURN_BPCHAR_P(result);
346
0
}
347
348
349
/*
350
 * char_bpchar()
351
 * Convert char to bpchar(1).
352
 */
353
Datum
354
char_bpchar(PG_FUNCTION_ARGS)
355
0
{
356
0
  char    c = PG_GETARG_CHAR(0);
357
0
  BpChar     *result;
358
359
0
  result = (BpChar *) palloc(VARHDRSZ + 1);
360
361
0
  SET_VARSIZE(result, VARHDRSZ + 1);
362
0
  *(VARDATA(result)) = c;
363
364
0
  PG_RETURN_BPCHAR_P(result);
365
0
}
366
367
368
/*
369
 * bpchar_name()
370
 * Converts a bpchar() type to a NameData type.
371
 */
372
Datum
373
bpchar_name(PG_FUNCTION_ARGS)
374
0
{
375
0
  BpChar     *s = PG_GETARG_BPCHAR_PP(0);
376
0
  char     *s_data;
377
0
  Name    result;
378
0
  int     len;
379
380
0
  len = VARSIZE_ANY_EXHDR(s);
381
0
  s_data = VARDATA_ANY(s);
382
383
  /* Truncate oversize input */
384
0
  if (len >= NAMEDATALEN)
385
0
    len = pg_mbcliplen(s_data, len, NAMEDATALEN - 1);
386
387
  /* Remove trailing blanks */
388
0
  while (len > 0)
389
0
  {
390
0
    if (s_data[len - 1] != ' ')
391
0
      break;
392
0
    len--;
393
0
  }
394
395
  /* We use palloc0 here to ensure result is zero-padded */
396
0
  result = (Name) palloc0(NAMEDATALEN);
397
0
  memcpy(NameStr(*result), s_data, len);
398
399
0
  PG_RETURN_NAME(result);
400
0
}
401
402
/*
403
 * name_bpchar()
404
 * Converts a NameData type to a bpchar type.
405
 *
406
 * Uses the text conversion functions, which is only appropriate if BpChar
407
 * and text are equivalent types.
408
 */
409
Datum
410
name_bpchar(PG_FUNCTION_ARGS)
411
0
{
412
0
  Name    s = PG_GETARG_NAME(0);
413
0
  BpChar     *result;
414
415
0
  result = (BpChar *) cstring_to_text(NameStr(*s));
416
0
  PG_RETURN_BPCHAR_P(result);
417
0
}
418
419
Datum
420
bpchartypmodin(PG_FUNCTION_ARGS)
421
0
{
422
0
  ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
423
424
0
  PG_RETURN_INT32(anychar_typmodin(ta, "char"));
425
0
}
426
427
Datum
428
bpchartypmodout(PG_FUNCTION_ARGS)
429
0
{
430
0
  int32   typmod = PG_GETARG_INT32(0);
431
432
0
  PG_RETURN_CSTRING(anychar_typmodout(typmod));
433
0
}
434
435
436
/*****************************************************************************
437
 *   varchar - varchar(n)
438
 *
439
 * Note: varchar piggybacks on type text for most operations, and so has no
440
 * C-coded functions except for I/O and typmod checking.
441
 *****************************************************************************/
442
443
/*
444
 * varchar_input -- common guts of varcharin and varcharrecv
445
 *
446
 * s is the input text of length len (may not be null-terminated)
447
 * atttypmod is the typmod value to apply
448
 *
449
 * Note that atttypmod is measured in characters, which
450
 * is not necessarily the same as the number of bytes.
451
 *
452
 * If the input string is too long, raise an error, unless the extra
453
 * characters are spaces, in which case they're truncated.  (per SQL)
454
 *
455
 * If escontext points to an ErrorSaveContext node, that is filled instead
456
 * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
457
 * to detect errors.
458
 */
459
static VarChar *
460
varchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext)
461
0
{
462
0
  VarChar    *result;
463
0
  size_t    maxlen;
464
465
0
  maxlen = atttypmod - VARHDRSZ;
466
467
0
  if (atttypmod >= (int32) VARHDRSZ && len > maxlen)
468
0
  {
469
    /* Verify that extra characters are spaces, and clip them off */
470
0
    size_t    mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
471
0
    size_t    j;
472
473
0
    for (j = mbmaxlen; j < len; j++)
474
0
    {
475
0
      if (s[j] != ' ')
476
0
        ereturn(escontext, NULL,
477
0
            (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
478
0
             errmsg("value too long for type character varying(%zu)",
479
0
                maxlen)));
480
0
    }
481
482
0
    len = mbmaxlen;
483
0
  }
484
485
  /*
486
   * We can use cstring_to_text_with_len because VarChar and text are
487
   * binary-compatible types.
488
   */
489
0
  result = (VarChar *) cstring_to_text_with_len(s, len);
490
0
  return result;
491
0
}
492
493
/*
494
 * Convert a C string to VARCHAR internal representation.  atttypmod
495
 * is the declared length of the type plus VARHDRSZ.
496
 */
497
Datum
498
varcharin(PG_FUNCTION_ARGS)
499
0
{
500
0
  char     *s = PG_GETARG_CSTRING(0);
501
#ifdef NOT_USED
502
  Oid     typelem = PG_GETARG_OID(1);
503
#endif
504
0
  int32   atttypmod = PG_GETARG_INT32(2);
505
0
  VarChar    *result;
506
507
0
  result = varchar_input(s, strlen(s), atttypmod, fcinfo->context);
508
0
  PG_RETURN_VARCHAR_P(result);
509
0
}
510
511
512
/*
513
 * Convert a VARCHAR value to a C string.
514
 *
515
 * Uses the text to C string conversion function, which is only appropriate
516
 * if VarChar and text are equivalent types.
517
 */
518
Datum
519
varcharout(PG_FUNCTION_ARGS)
520
0
{
521
0
  Datum   txt = PG_GETARG_DATUM(0);
522
523
0
  PG_RETURN_CSTRING(TextDatumGetCString(txt));
524
0
}
525
526
/*
527
 *    varcharrecv     - converts external binary format to varchar
528
 */
529
Datum
530
varcharrecv(PG_FUNCTION_ARGS)
531
0
{
532
0
  StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
533
#ifdef NOT_USED
534
  Oid     typelem = PG_GETARG_OID(1);
535
#endif
536
0
  int32   atttypmod = PG_GETARG_INT32(2);
537
0
  VarChar    *result;
538
0
  char     *str;
539
0
  int     nbytes;
540
541
0
  str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
542
0
  result = varchar_input(str, nbytes, atttypmod, NULL);
543
0
  pfree(str);
544
0
  PG_RETURN_VARCHAR_P(result);
545
0
}
546
547
/*
548
 *    varcharsend     - converts varchar to binary format
549
 */
550
Datum
551
varcharsend(PG_FUNCTION_ARGS)
552
0
{
553
  /* Exactly the same as textsend, so share code */
554
0
  return textsend(fcinfo);
555
0
}
556
557
558
/*
559
 * varchar_support()
560
 *
561
 * Planner support function for the varchar() length coercion function.
562
 *
563
 * Currently, the only interesting thing we can do is flatten calls that set
564
 * the new maximum length >= the previous maximum length.  We can ignore the
565
 * isExplicit argument, since that only affects truncation cases.
566
 */
567
Datum
568
varchar_support(PG_FUNCTION_ARGS)
569
0
{
570
0
  Node     *rawreq = (Node *) PG_GETARG_POINTER(0);
571
0
  Node     *ret = NULL;
572
573
0
  if (IsA(rawreq, SupportRequestSimplify))
574
0
  {
575
0
    SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
576
0
    FuncExpr   *expr = req->fcall;
577
0
    Node     *typmod;
578
579
0
    Assert(list_length(expr->args) >= 2);
580
581
0
    typmod = (Node *) lsecond(expr->args);
582
583
0
    if (IsA(typmod, Const) && !((Const *) typmod)->constisnull)
584
0
    {
585
0
      Node     *source = (Node *) linitial(expr->args);
586
0
      int32   old_typmod = exprTypmod(source);
587
0
      int32   new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
588
0
      int32   old_max = old_typmod - VARHDRSZ;
589
0
      int32   new_max = new_typmod - VARHDRSZ;
590
591
0
      if (new_typmod < 0 || (old_typmod >= 0 && old_max <= new_max))
592
0
        ret = relabel_to_typmod(source, new_typmod);
593
0
    }
594
0
  }
595
596
0
  PG_RETURN_POINTER(ret);
597
0
}
598
599
/*
600
 * Converts a VARCHAR type to the specified size.
601
 *
602
 * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
603
 * isExplicit is true if this is for an explicit cast to varchar(N).
604
 *
605
 * Truncation rules: for an explicit cast, silently truncate to the given
606
 * length; for an implicit cast, raise error unless extra characters are
607
 * all spaces.  (This is sort-of per SQL: the spec would actually have us
608
 * raise a "completion condition" for the explicit cast case, but Postgres
609
 * hasn't got such a concept.)
610
 */
611
Datum
612
varchar(PG_FUNCTION_ARGS)
613
0
{
614
0
  VarChar    *source = PG_GETARG_VARCHAR_PP(0);
615
0
  int32   typmod = PG_GETARG_INT32(1);
616
0
  bool    isExplicit = PG_GETARG_BOOL(2);
617
0
  int32   len,
618
0
        maxlen;
619
0
  size_t    maxmblen;
620
0
  int     i;
621
0
  char     *s_data;
622
623
0
  len = VARSIZE_ANY_EXHDR(source);
624
0
  s_data = VARDATA_ANY(source);
625
0
  maxlen = typmod - VARHDRSZ;
626
627
  /* No work if typmod is invalid or supplied data fits it already */
628
0
  if (maxlen < 0 || len <= maxlen)
629
0
    PG_RETURN_VARCHAR_P(source);
630
631
  /* only reach here if string is too long... */
632
633
  /* truncate multibyte string preserving multibyte boundary */
634
0
  maxmblen = pg_mbcharcliplen(s_data, len, maxlen);
635
636
0
  if (!isExplicit)
637
0
  {
638
0
    for (i = maxmblen; i < len; i++)
639
0
      if (s_data[i] != ' ')
640
0
        ereturn(fcinfo->context, (Datum) 0,
641
0
            (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
642
0
             errmsg("value too long for type character varying(%d)",
643
0
                maxlen)));
644
0
  }
645
646
0
  PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data,
647
0
                               maxmblen));
648
0
}
649
650
Datum
651
varchartypmodin(PG_FUNCTION_ARGS)
652
0
{
653
0
  ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
654
655
0
  PG_RETURN_INT32(anychar_typmodin(ta, "varchar"));
656
0
}
657
658
Datum
659
varchartypmodout(PG_FUNCTION_ARGS)
660
0
{
661
0
  int32   typmod = PG_GETARG_INT32(0);
662
663
0
  PG_RETURN_CSTRING(anychar_typmodout(typmod));
664
0
}
665
666
667
/*****************************************************************************
668
 * Exported functions
669
 *****************************************************************************/
670
671
/* "True" length (not counting trailing blanks) of a BpChar */
672
static inline int
673
bcTruelen(BpChar *arg)
674
0
{
675
0
  return bpchartruelen(VARDATA_ANY(arg), VARSIZE_ANY_EXHDR(arg));
676
0
}
677
678
int
679
bpchartruelen(char *s, int len)
680
0
{
681
0
  int     i;
682
683
  /*
684
   * Note that we rely on the assumption that ' ' is a singleton unit on
685
   * every supported multibyte server encoding.
686
   */
687
0
  for (i = len - 1; i >= 0; i--)
688
0
  {
689
0
    if (s[i] != ' ')
690
0
      break;
691
0
  }
692
0
  return i + 1;
693
0
}
694
695
Datum
696
bpcharlen(PG_FUNCTION_ARGS)
697
0
{
698
0
  BpChar     *arg = PG_GETARG_BPCHAR_PP(0);
699
0
  int     len;
700
701
  /* get number of bytes, ignoring trailing spaces */
702
0
  len = bcTruelen(arg);
703
704
  /* in multibyte encoding, convert to number of characters */
705
0
  if (pg_database_encoding_max_length() != 1)
706
0
    len = pg_mbstrlen_with_len(VARDATA_ANY(arg), len);
707
708
0
  PG_RETURN_INT32(len);
709
0
}
710
711
Datum
712
bpcharoctetlen(PG_FUNCTION_ARGS)
713
0
{
714
0
  Datum   arg = PG_GETARG_DATUM(0);
715
716
  /* We need not detoast the input at all */
717
0
  PG_RETURN_INT32(toast_raw_datum_size(arg) - VARHDRSZ);
718
0
}
719
720
721
/*****************************************************************************
722
 *  Comparison Functions used for bpchar
723
 *
724
 * Note: btree indexes need these routines not to leak memory; therefore,
725
 * be careful to free working copies of toasted datums.  Most places don't
726
 * need to be so careful.
727
 *****************************************************************************/
728
729
static void
730
check_collation_set(Oid collid)
731
0
{
732
0
  if (!OidIsValid(collid))
733
0
  {
734
    /*
735
     * This typically means that the parser could not resolve a conflict
736
     * of implicit collations, so report it that way.
737
     */
738
0
    ereport(ERROR,
739
0
        (errcode(ERRCODE_INDETERMINATE_COLLATION),
740
0
         errmsg("could not determine which collation to use for string comparison"),
741
0
         errhint("Use the COLLATE clause to set the collation explicitly.")));
742
0
  }
743
0
}
744
745
Datum
746
bpchareq(PG_FUNCTION_ARGS)
747
0
{
748
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
749
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
750
0
  int     len1,
751
0
        len2;
752
0
  bool    result;
753
0
  Oid     collid = PG_GET_COLLATION();
754
0
  pg_locale_t mylocale;
755
756
0
  check_collation_set(collid);
757
758
0
  len1 = bcTruelen(arg1);
759
0
  len2 = bcTruelen(arg2);
760
761
0
  mylocale = pg_newlocale_from_collation(collid);
762
763
0
  if (mylocale->deterministic)
764
0
  {
765
    /*
766
     * Since we only care about equality or not-equality, we can avoid all
767
     * the expense of strcoll() here, and just do bitwise comparison.
768
     */
769
0
    if (len1 != len2)
770
0
      result = false;
771
0
    else
772
0
      result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) == 0);
773
0
  }
774
0
  else
775
0
  {
776
0
    result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
777
0
               collid) == 0);
778
0
  }
779
780
0
  PG_FREE_IF_COPY(arg1, 0);
781
0
  PG_FREE_IF_COPY(arg2, 1);
782
783
0
  PG_RETURN_BOOL(result);
784
0
}
785
786
Datum
787
bpcharne(PG_FUNCTION_ARGS)
788
0
{
789
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
790
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
791
0
  int     len1,
792
0
        len2;
793
0
  bool    result;
794
0
  Oid     collid = PG_GET_COLLATION();
795
0
  pg_locale_t mylocale;
796
797
0
  check_collation_set(collid);
798
799
0
  len1 = bcTruelen(arg1);
800
0
  len2 = bcTruelen(arg2);
801
802
0
  mylocale = pg_newlocale_from_collation(collid);
803
804
0
  if (mylocale->deterministic)
805
0
  {
806
    /*
807
     * Since we only care about equality or not-equality, we can avoid all
808
     * the expense of strcoll() here, and just do bitwise comparison.
809
     */
810
0
    if (len1 != len2)
811
0
      result = true;
812
0
    else
813
0
      result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) != 0);
814
0
  }
815
0
  else
816
0
  {
817
0
    result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
818
0
               collid) != 0);
819
0
  }
820
821
0
  PG_FREE_IF_COPY(arg1, 0);
822
0
  PG_FREE_IF_COPY(arg2, 1);
823
824
0
  PG_RETURN_BOOL(result);
825
0
}
826
827
Datum
828
bpcharlt(PG_FUNCTION_ARGS)
829
0
{
830
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
831
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
832
0
  int     len1,
833
0
        len2;
834
0
  int     cmp;
835
836
0
  len1 = bcTruelen(arg1);
837
0
  len2 = bcTruelen(arg2);
838
839
0
  cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
840
0
           PG_GET_COLLATION());
841
842
0
  PG_FREE_IF_COPY(arg1, 0);
843
0
  PG_FREE_IF_COPY(arg2, 1);
844
845
0
  PG_RETURN_BOOL(cmp < 0);
846
0
}
847
848
Datum
849
bpcharle(PG_FUNCTION_ARGS)
850
0
{
851
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
852
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
853
0
  int     len1,
854
0
        len2;
855
0
  int     cmp;
856
857
0
  len1 = bcTruelen(arg1);
858
0
  len2 = bcTruelen(arg2);
859
860
0
  cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
861
0
           PG_GET_COLLATION());
862
863
0
  PG_FREE_IF_COPY(arg1, 0);
864
0
  PG_FREE_IF_COPY(arg2, 1);
865
866
0
  PG_RETURN_BOOL(cmp <= 0);
867
0
}
868
869
Datum
870
bpchargt(PG_FUNCTION_ARGS)
871
0
{
872
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
873
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
874
0
  int     len1,
875
0
        len2;
876
0
  int     cmp;
877
878
0
  len1 = bcTruelen(arg1);
879
0
  len2 = bcTruelen(arg2);
880
881
0
  cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
882
0
           PG_GET_COLLATION());
883
884
0
  PG_FREE_IF_COPY(arg1, 0);
885
0
  PG_FREE_IF_COPY(arg2, 1);
886
887
0
  PG_RETURN_BOOL(cmp > 0);
888
0
}
889
890
Datum
891
bpcharge(PG_FUNCTION_ARGS)
892
0
{
893
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
894
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
895
0
  int     len1,
896
0
        len2;
897
0
  int     cmp;
898
899
0
  len1 = bcTruelen(arg1);
900
0
  len2 = bcTruelen(arg2);
901
902
0
  cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
903
0
           PG_GET_COLLATION());
904
905
0
  PG_FREE_IF_COPY(arg1, 0);
906
0
  PG_FREE_IF_COPY(arg2, 1);
907
908
0
  PG_RETURN_BOOL(cmp >= 0);
909
0
}
910
911
Datum
912
bpcharcmp(PG_FUNCTION_ARGS)
913
0
{
914
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
915
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
916
0
  int     len1,
917
0
        len2;
918
0
  int     cmp;
919
920
0
  len1 = bcTruelen(arg1);
921
0
  len2 = bcTruelen(arg2);
922
923
0
  cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
924
0
           PG_GET_COLLATION());
925
926
0
  PG_FREE_IF_COPY(arg1, 0);
927
0
  PG_FREE_IF_COPY(arg2, 1);
928
929
0
  PG_RETURN_INT32(cmp);
930
0
}
931
932
Datum
933
bpchar_sortsupport(PG_FUNCTION_ARGS)
934
0
{
935
0
  SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
936
0
  Oid     collid = ssup->ssup_collation;
937
0
  MemoryContext oldcontext;
938
939
0
  oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
940
941
  /* Use generic string SortSupport */
942
0
  varstr_sortsupport(ssup, BPCHAROID, collid);
943
944
0
  MemoryContextSwitchTo(oldcontext);
945
946
0
  PG_RETURN_VOID();
947
0
}
948
949
Datum
950
bpchar_larger(PG_FUNCTION_ARGS)
951
0
{
952
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
953
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
954
0
  int     len1,
955
0
        len2;
956
0
  int     cmp;
957
958
0
  len1 = bcTruelen(arg1);
959
0
  len2 = bcTruelen(arg2);
960
961
0
  cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
962
0
           PG_GET_COLLATION());
963
964
0
  PG_RETURN_BPCHAR_P((cmp >= 0) ? arg1 : arg2);
965
0
}
966
967
Datum
968
bpchar_smaller(PG_FUNCTION_ARGS)
969
0
{
970
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
971
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
972
0
  int     len1,
973
0
        len2;
974
0
  int     cmp;
975
976
0
  len1 = bcTruelen(arg1);
977
0
  len2 = bcTruelen(arg2);
978
979
0
  cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
980
0
           PG_GET_COLLATION());
981
982
0
  PG_RETURN_BPCHAR_P((cmp <= 0) ? arg1 : arg2);
983
0
}
984
985
986
/*
987
 * bpchar needs a specialized hash function because we want to ignore
988
 * trailing blanks in comparisons.
989
 */
990
Datum
991
hashbpchar(PG_FUNCTION_ARGS)
992
0
{
993
0
  BpChar     *key = PG_GETARG_BPCHAR_PP(0);
994
0
  Oid     collid = PG_GET_COLLATION();
995
0
  char     *keydata;
996
0
  int     keylen;
997
0
  pg_locale_t mylocale;
998
0
  Datum   result;
999
1000
0
  if (!collid)
1001
0
    ereport(ERROR,
1002
0
        (errcode(ERRCODE_INDETERMINATE_COLLATION),
1003
0
         errmsg("could not determine which collation to use for string hashing"),
1004
0
         errhint("Use the COLLATE clause to set the collation explicitly.")));
1005
1006
0
  keydata = VARDATA_ANY(key);
1007
0
  keylen = bcTruelen(key);
1008
1009
0
  mylocale = pg_newlocale_from_collation(collid);
1010
1011
0
  if (mylocale->deterministic)
1012
0
  {
1013
0
    result = hash_any((unsigned char *) keydata, keylen);
1014
0
  }
1015
0
  else
1016
0
  {
1017
0
    Size    bsize,
1018
0
          rsize;
1019
0
    char     *buf;
1020
1021
0
    bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
1022
0
    buf = palloc(bsize + 1);
1023
1024
0
    rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
1025
1026
    /* the second call may return a smaller value than the first */
1027
0
    if (rsize > bsize)
1028
0
      elog(ERROR, "pg_strnxfrm() returned unexpected result");
1029
1030
    /*
1031
     * In principle, there's no reason to include the terminating NUL
1032
     * character in the hash, but it was done before and the behavior must
1033
     * be preserved.
1034
     */
1035
0
    result = hash_any((uint8_t *) buf, bsize + 1);
1036
1037
0
    pfree(buf);
1038
0
  }
1039
1040
  /* Avoid leaking memory for toasted inputs */
1041
0
  PG_FREE_IF_COPY(key, 0);
1042
1043
0
  return result;
1044
0
}
1045
1046
Datum
1047
hashbpcharextended(PG_FUNCTION_ARGS)
1048
0
{
1049
0
  BpChar     *key = PG_GETARG_BPCHAR_PP(0);
1050
0
  Oid     collid = PG_GET_COLLATION();
1051
0
  char     *keydata;
1052
0
  int     keylen;
1053
0
  pg_locale_t mylocale;
1054
0
  Datum   result;
1055
1056
0
  if (!collid)
1057
0
    ereport(ERROR,
1058
0
        (errcode(ERRCODE_INDETERMINATE_COLLATION),
1059
0
         errmsg("could not determine which collation to use for string hashing"),
1060
0
         errhint("Use the COLLATE clause to set the collation explicitly.")));
1061
1062
0
  keydata = VARDATA_ANY(key);
1063
0
  keylen = bcTruelen(key);
1064
1065
0
  mylocale = pg_newlocale_from_collation(collid);
1066
1067
0
  if (mylocale->deterministic)
1068
0
  {
1069
0
    result = hash_any_extended((unsigned char *) keydata, keylen,
1070
0
                   PG_GETARG_INT64(1));
1071
0
  }
1072
0
  else
1073
0
  {
1074
0
    Size    bsize,
1075
0
          rsize;
1076
0
    char     *buf;
1077
1078
0
    bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
1079
0
    buf = palloc(bsize + 1);
1080
1081
0
    rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
1082
1083
    /* the second call may return a smaller value than the first */
1084
0
    if (rsize > bsize)
1085
0
      elog(ERROR, "pg_strnxfrm() returned unexpected result");
1086
1087
    /*
1088
     * In principle, there's no reason to include the terminating NUL
1089
     * character in the hash, but it was done before and the behavior must
1090
     * be preserved.
1091
     */
1092
0
    result = hash_any_extended((uint8_t *) buf, bsize + 1,
1093
0
                   PG_GETARG_INT64(1));
1094
1095
0
    pfree(buf);
1096
0
  }
1097
1098
0
  PG_FREE_IF_COPY(key, 0);
1099
1100
0
  return result;
1101
0
}
1102
1103
/*
1104
 * The following operators support character-by-character comparison
1105
 * of bpchar datums, to allow building indexes suitable for LIKE clauses.
1106
 * Note that the regular bpchareq/bpcharne comparison operators, and
1107
 * regular support functions 1 and 2 with "C" collation are assumed to be
1108
 * compatible with these!
1109
 */
1110
1111
static int
1112
internal_bpchar_pattern_compare(BpChar *arg1, BpChar *arg2)
1113
0
{
1114
0
  int     result;
1115
0
  int     len1,
1116
0
        len2;
1117
1118
0
  len1 = bcTruelen(arg1);
1119
0
  len2 = bcTruelen(arg2);
1120
1121
0
  result = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
1122
0
  if (result != 0)
1123
0
    return result;
1124
0
  else if (len1 < len2)
1125
0
    return -1;
1126
0
  else if (len1 > len2)
1127
0
    return 1;
1128
0
  else
1129
0
    return 0;
1130
0
}
1131
1132
1133
Datum
1134
bpchar_pattern_lt(PG_FUNCTION_ARGS)
1135
0
{
1136
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
1137
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
1138
0
  int     result;
1139
1140
0
  result = internal_bpchar_pattern_compare(arg1, arg2);
1141
1142
0
  PG_FREE_IF_COPY(arg1, 0);
1143
0
  PG_FREE_IF_COPY(arg2, 1);
1144
1145
0
  PG_RETURN_BOOL(result < 0);
1146
0
}
1147
1148
1149
Datum
1150
bpchar_pattern_le(PG_FUNCTION_ARGS)
1151
0
{
1152
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
1153
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
1154
0
  int     result;
1155
1156
0
  result = internal_bpchar_pattern_compare(arg1, arg2);
1157
1158
0
  PG_FREE_IF_COPY(arg1, 0);
1159
0
  PG_FREE_IF_COPY(arg2, 1);
1160
1161
0
  PG_RETURN_BOOL(result <= 0);
1162
0
}
1163
1164
1165
Datum
1166
bpchar_pattern_ge(PG_FUNCTION_ARGS)
1167
0
{
1168
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
1169
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
1170
0
  int     result;
1171
1172
0
  result = internal_bpchar_pattern_compare(arg1, arg2);
1173
1174
0
  PG_FREE_IF_COPY(arg1, 0);
1175
0
  PG_FREE_IF_COPY(arg2, 1);
1176
1177
0
  PG_RETURN_BOOL(result >= 0);
1178
0
}
1179
1180
1181
Datum
1182
bpchar_pattern_gt(PG_FUNCTION_ARGS)
1183
0
{
1184
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
1185
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
1186
0
  int     result;
1187
1188
0
  result = internal_bpchar_pattern_compare(arg1, arg2);
1189
1190
0
  PG_FREE_IF_COPY(arg1, 0);
1191
0
  PG_FREE_IF_COPY(arg2, 1);
1192
1193
0
  PG_RETURN_BOOL(result > 0);
1194
0
}
1195
1196
1197
Datum
1198
btbpchar_pattern_cmp(PG_FUNCTION_ARGS)
1199
0
{
1200
0
  BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
1201
0
  BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
1202
0
  int     result;
1203
1204
0
  result = internal_bpchar_pattern_compare(arg1, arg2);
1205
1206
0
  PG_FREE_IF_COPY(arg1, 0);
1207
0
  PG_FREE_IF_COPY(arg2, 1);
1208
1209
0
  PG_RETURN_INT32(result);
1210
0
}
1211
1212
1213
Datum
1214
btbpchar_pattern_sortsupport(PG_FUNCTION_ARGS)
1215
0
{
1216
0
  SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
1217
0
  MemoryContext oldcontext;
1218
1219
0
  oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
1220
1221
  /* Use generic string SortSupport, forcing "C" collation */
1222
0
  varstr_sortsupport(ssup, BPCHAROID, C_COLLATION_OID);
1223
1224
0
  MemoryContextSwitchTo(oldcontext);
1225
1226
0
  PG_RETURN_VOID();
1227
0
}