Coverage Report

Created: 2025-09-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/adt/name.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * name.c
4
 *    Functions for the built-in type "name".
5
 *
6
 * name replaces char16 and is carefully implemented so that it
7
 * is a string of physical length NAMEDATALEN.
8
 * DO NOT use hard-coded constants anywhere
9
 * always use NAMEDATALEN as the symbolic constant!   - jolly 8/21/95
10
 *
11
 *
12
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
13
 * Portions Copyright (c) 1994, Regents of the University of California
14
 *
15
 *
16
 * IDENTIFICATION
17
 *    src/backend/utils/adt/name.c
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
#include "postgres.h"
22
23
#include "catalog/namespace.h"
24
#include "catalog/pg_collation.h"
25
#include "catalog/pg_type.h"
26
#include "libpq/pqformat.h"
27
#include "mb/pg_wchar.h"
28
#include "miscadmin.h"
29
#include "utils/array.h"
30
#include "utils/builtins.h"
31
#include "utils/lsyscache.h"
32
#include "utils/varlena.h"
33
34
35
/*****************************************************************************
36
 *   USER I/O ROUTINES (none)                        *
37
 *****************************************************************************/
38
39
40
/*
41
 *    namein  - converts cstring to internal representation
42
 *
43
 *    Note:
44
 *        [Old] Currently if strlen(s) < NAMEDATALEN, the extra chars are nulls
45
 *        Now, always NULL terminated
46
 */
47
Datum
48
namein(PG_FUNCTION_ARGS)
49
0
{
50
0
  char     *s = PG_GETARG_CSTRING(0);
51
0
  Name    result;
52
0
  int     len;
53
54
0
  len = strlen(s);
55
56
  /* Truncate oversize input */
57
0
  if (len >= NAMEDATALEN)
58
0
    len = pg_mbcliplen(s, len, NAMEDATALEN - 1);
59
60
  /* We use palloc0 here to ensure result is zero-padded */
61
0
  result = (Name) palloc0(NAMEDATALEN);
62
0
  memcpy(NameStr(*result), s, len);
63
64
0
  PG_RETURN_NAME(result);
65
0
}
66
67
/*
68
 *    nameout - converts internal representation to cstring
69
 */
70
Datum
71
nameout(PG_FUNCTION_ARGS)
72
0
{
73
0
  Name    s = PG_GETARG_NAME(0);
74
75
0
  PG_RETURN_CSTRING(pstrdup(NameStr(*s)));
76
0
}
77
78
/*
79
 *    namerecv      - converts external binary format to name
80
 */
81
Datum
82
namerecv(PG_FUNCTION_ARGS)
83
0
{
84
0
  StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
85
0
  Name    result;
86
0
  char     *str;
87
0
  int     nbytes;
88
89
0
  str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
90
0
  if (nbytes >= NAMEDATALEN)
91
0
    ereport(ERROR,
92
0
        (errcode(ERRCODE_NAME_TOO_LONG),
93
0
         errmsg("identifier too long"),
94
0
         errdetail("Identifier must be less than %d characters.",
95
0
               NAMEDATALEN)));
96
0
  result = (NameData *) palloc0(NAMEDATALEN);
97
0
  memcpy(result, str, nbytes);
98
0
  pfree(str);
99
0
  PG_RETURN_NAME(result);
100
0
}
101
102
/*
103
 *    namesend      - converts name to binary format
104
 */
105
Datum
106
namesend(PG_FUNCTION_ARGS)
107
0
{
108
0
  Name    s = PG_GETARG_NAME(0);
109
0
  StringInfoData buf;
110
111
0
  pq_begintypsend(&buf);
112
0
  pq_sendtext(&buf, NameStr(*s), strlen(NameStr(*s)));
113
0
  PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
114
0
}
115
116
117
/*****************************************************************************
118
 *   COMPARISON/SORTING ROUTINES                       *
119
 *****************************************************************************/
120
121
/*
122
 *    nameeq  - returns 1 iff arguments are equal
123
 *    namene  - returns 1 iff arguments are not equal
124
 *    namelt  - returns 1 iff a < b
125
 *    namele  - returns 1 iff a <= b
126
 *    namegt  - returns 1 iff a > b
127
 *    namege  - returns 1 iff a >= b
128
 *
129
 * Note that the use of strncmp with NAMEDATALEN limit is mostly historical;
130
 * strcmp would do as well, because we do not allow NAME values that don't
131
 * have a '\0' terminator.  Whatever might be past the terminator is not
132
 * considered relevant to comparisons.
133
 */
134
static int
135
namecmp(Name arg1, Name arg2, Oid collid)
136
0
{
137
  /* Fast path for common case used in system catalogs */
138
0
  if (collid == C_COLLATION_OID)
139
0
    return strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN);
140
141
  /* Else rely on the varstr infrastructure */
142
0
  return varstr_cmp(NameStr(*arg1), strlen(NameStr(*arg1)),
143
0
            NameStr(*arg2), strlen(NameStr(*arg2)),
144
0
            collid);
145
0
}
146
147
Datum
148
nameeq(PG_FUNCTION_ARGS)
149
0
{
150
0
  Name    arg1 = PG_GETARG_NAME(0);
151
0
  Name    arg2 = PG_GETARG_NAME(1);
152
153
0
  PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) == 0);
154
0
}
155
156
Datum
157
namene(PG_FUNCTION_ARGS)
158
0
{
159
0
  Name    arg1 = PG_GETARG_NAME(0);
160
0
  Name    arg2 = PG_GETARG_NAME(1);
161
162
0
  PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) != 0);
163
0
}
164
165
Datum
166
namelt(PG_FUNCTION_ARGS)
167
0
{
168
0
  Name    arg1 = PG_GETARG_NAME(0);
169
0
  Name    arg2 = PG_GETARG_NAME(1);
170
171
0
  PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) < 0);
172
0
}
173
174
Datum
175
namele(PG_FUNCTION_ARGS)
176
0
{
177
0
  Name    arg1 = PG_GETARG_NAME(0);
178
0
  Name    arg2 = PG_GETARG_NAME(1);
179
180
0
  PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) <= 0);
181
0
}
182
183
Datum
184
namegt(PG_FUNCTION_ARGS)
185
0
{
186
0
  Name    arg1 = PG_GETARG_NAME(0);
187
0
  Name    arg2 = PG_GETARG_NAME(1);
188
189
0
  PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) > 0);
190
0
}
191
192
Datum
193
namege(PG_FUNCTION_ARGS)
194
0
{
195
0
  Name    arg1 = PG_GETARG_NAME(0);
196
0
  Name    arg2 = PG_GETARG_NAME(1);
197
198
0
  PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) >= 0);
199
0
}
200
201
Datum
202
btnamecmp(PG_FUNCTION_ARGS)
203
0
{
204
0
  Name    arg1 = PG_GETARG_NAME(0);
205
0
  Name    arg2 = PG_GETARG_NAME(1);
206
207
0
  PG_RETURN_INT32(namecmp(arg1, arg2, PG_GET_COLLATION()));
208
0
}
209
210
Datum
211
btnamesortsupport(PG_FUNCTION_ARGS)
212
0
{
213
0
  SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
214
0
  Oid     collid = ssup->ssup_collation;
215
0
  MemoryContext oldcontext;
216
217
0
  oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
218
219
  /* Use generic string SortSupport */
220
0
  varstr_sortsupport(ssup, NAMEOID, collid);
221
222
0
  MemoryContextSwitchTo(oldcontext);
223
224
0
  PG_RETURN_VOID();
225
0
}
226
227
228
/*****************************************************************************
229
 *   MISCELLANEOUS PUBLIC ROUTINES                       *
230
 *****************************************************************************/
231
232
void
233
namestrcpy(Name name, const char *str)
234
0
{
235
  /* NB: We need to zero-pad the destination. */
236
0
  strncpy(NameStr(*name), str, NAMEDATALEN);
237
0
  NameStr(*name)[NAMEDATALEN - 1] = '\0';
238
0
}
239
240
/*
241
 * Compare a NAME to a C string
242
 *
243
 * Assumes C collation always; be careful when using this for
244
 * anything but equality checks!
245
 */
246
int
247
namestrcmp(Name name, const char *str)
248
0
{
249
0
  if (!name && !str)
250
0
    return 0;
251
0
  if (!name)
252
0
    return -1;       /* NULL < anything */
253
0
  if (!str)
254
0
    return 1;       /* NULL < anything */
255
0
  return strncmp(NameStr(*name), str, NAMEDATALEN);
256
0
}
257
258
259
/*
260
 * SQL-functions CURRENT_USER, SESSION_USER
261
 */
262
Datum
263
current_user(PG_FUNCTION_ARGS)
264
0
{
265
0
  PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId(), false))));
266
0
}
267
268
Datum
269
session_user(PG_FUNCTION_ARGS)
270
0
{
271
0
  PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetSessionUserId(), false))));
272
0
}
273
274
275
/*
276
 * SQL-functions CURRENT_SCHEMA, CURRENT_SCHEMAS
277
 */
278
Datum
279
current_schema(PG_FUNCTION_ARGS)
280
0
{
281
0
  List     *search_path = fetch_search_path(false);
282
0
  char     *nspname;
283
284
0
  if (search_path == NIL)
285
0
    PG_RETURN_NULL();
286
0
  nspname = get_namespace_name(linitial_oid(search_path));
287
0
  list_free(search_path);
288
0
  if (!nspname)
289
0
    PG_RETURN_NULL();   /* recently-deleted namespace? */
290
0
  PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(nspname)));
291
0
}
292
293
Datum
294
current_schemas(PG_FUNCTION_ARGS)
295
0
{
296
0
  List     *search_path = fetch_search_path(PG_GETARG_BOOL(0));
297
0
  ListCell   *l;
298
0
  Datum    *names;
299
0
  int     i;
300
0
  ArrayType  *array;
301
302
0
  names = (Datum *) palloc(list_length(search_path) * sizeof(Datum));
303
0
  i = 0;
304
0
  foreach(l, search_path)
305
0
  {
306
0
    char     *nspname;
307
308
0
    nspname = get_namespace_name(lfirst_oid(l));
309
0
    if (nspname)     /* watch out for deleted namespace */
310
0
    {
311
0
      names[i] = DirectFunctionCall1(namein, CStringGetDatum(nspname));
312
0
      i++;
313
0
    }
314
0
  }
315
0
  list_free(search_path);
316
317
0
  array = construct_array_builtin(names, i, NAMEOID);
318
319
0
  PG_RETURN_POINTER(array);
320
0
}
321
322
/*
323
 * SQL-function nameconcatoid(name, oid) returns name
324
 *
325
 * This is used in the information_schema to produce specific_name columns,
326
 * which are supposed to be unique per schema.  We achieve that (in an ugly
327
 * way) by appending the object's OID.  The result is the same as
328
 *    ($1::text || '_' || $2::text)::name
329
 * except that, if it would not fit in NAMEDATALEN, we make it do so by
330
 * truncating the name input (not the oid).
331
 */
332
Datum
333
nameconcatoid(PG_FUNCTION_ARGS)
334
0
{
335
0
  Name    nam = PG_GETARG_NAME(0);
336
0
  Oid     oid = PG_GETARG_OID(1);
337
0
  Name    result;
338
0
  char    suffix[20];
339
0
  int     suflen;
340
0
  int     namlen;
341
342
0
  suflen = snprintf(suffix, sizeof(suffix), "_%u", oid);
343
0
  namlen = strlen(NameStr(*nam));
344
345
  /* Truncate oversize input by truncating name part, not suffix */
346
0
  if (namlen + suflen >= NAMEDATALEN)
347
0
    namlen = pg_mbcliplen(NameStr(*nam), namlen, NAMEDATALEN - 1 - suflen);
348
349
  /* We use palloc0 here to ensure result is zero-padded */
350
0
  result = (Name) palloc0(NAMEDATALEN);
351
0
  memcpy(NameStr(*result), NameStr(*nam), namlen);
352
0
  memcpy(NameStr(*result) + namlen, suffix, suflen);
353
354
0
  PG_RETURN_NAME(result);
355
0
}