Branch data Line data Source code
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-2026, 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 : 71669 : namein(PG_FUNCTION_ARGS)
49 : : {
50 : 71669 : char *s = PG_GETARG_CSTRING(0);
51 : 71669 : Name result;
52 : 71669 : int len;
53 : :
54 : 71669 : len = strlen(s);
55 : :
56 : : /* Truncate oversize input */
57 [ + + ]: 71669 : if (len >= NAMEDATALEN)
58 : 9 : len = pg_mbcliplen(s, len, NAMEDATALEN - 1);
59 : :
60 : : /* We use palloc0 here to ensure result is zero-padded */
61 : 71669 : result = (Name) palloc0(NAMEDATALEN);
62 : 71669 : memcpy(NameStr(*result), s, len);
63 : :
64 : 143338 : PG_RETURN_NAME(result);
65 : 71669 : }
66 : :
67 : : /*
68 : : * nameout - converts internal representation to cstring
69 : : */
70 : : Datum
71 : 33928 : nameout(PG_FUNCTION_ARGS)
72 : : {
73 : 33928 : Name s = PG_GETARG_NAME(0);
74 : :
75 : 67856 : PG_RETURN_CSTRING(pstrdup(NameStr(*s)));
76 : 33928 : }
77 : :
78 : : /*
79 : : * namerecv - converts external binary format to name
80 : : */
81 : : Datum
82 : 1 : namerecv(PG_FUNCTION_ARGS)
83 : : {
84 : 1 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
85 : 1 : Name result;
86 : 1 : char *str;
87 : 1 : int nbytes;
88 : :
89 : 1 : str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
90 [ + - ]: 1 : if (nbytes >= NAMEDATALEN)
91 [ # # # # ]: 0 : ereport(ERROR,
92 : : (errcode(ERRCODE_NAME_TOO_LONG),
93 : : errmsg("identifier too long"),
94 : : errdetail("Identifier must be less than %d characters.",
95 : : NAMEDATALEN)));
96 : 1 : result = (NameData *) palloc0(NAMEDATALEN);
97 : 1 : memcpy(result, str, nbytes);
98 : 1 : pfree(str);
99 : 2 : PG_RETURN_NAME(result);
100 : 1 : }
101 : :
102 : : /*
103 : : * namesend - converts name to binary format
104 : : */
105 : : Datum
106 : 1 : namesend(PG_FUNCTION_ARGS)
107 : : {
108 : 1 : Name s = PG_GETARG_NAME(0);
109 : 1 : StringInfoData buf;
110 : :
111 : 1 : pq_begintypsend(&buf);
112 : 1 : pq_sendtext(&buf, NameStr(*s), strlen(NameStr(*s)));
113 : 2 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
114 : 1 : }
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 : 2245010 : namecmp(Name arg1, Name arg2, Oid collid)
136 : : {
137 : : /* Fast path for common case used in system catalogs */
138 [ + - ]: 2245010 : if (collid == C_COLLATION_OID)
139 : 2245010 : 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 : 2245010 : }
146 : :
147 : : Datum
148 : 433720 : nameeq(PG_FUNCTION_ARGS)
149 : : {
150 : 433720 : Name arg1 = PG_GETARG_NAME(0);
151 : 433720 : Name arg2 = PG_GETARG_NAME(1);
152 : :
153 : 867440 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) == 0);
154 : 433720 : }
155 : :
156 : : Datum
157 : 5929 : namene(PG_FUNCTION_ARGS)
158 : : {
159 : 5929 : Name arg1 = PG_GETARG_NAME(0);
160 : 5929 : Name arg2 = PG_GETARG_NAME(1);
161 : :
162 : 11858 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) != 0);
163 : 5929 : }
164 : :
165 : : Datum
166 : 15589 : namelt(PG_FUNCTION_ARGS)
167 : : {
168 : 15589 : Name arg1 = PG_GETARG_NAME(0);
169 : 15589 : Name arg2 = PG_GETARG_NAME(1);
170 : :
171 : 31178 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) < 0);
172 : 15589 : }
173 : :
174 : : Datum
175 : 2565 : namele(PG_FUNCTION_ARGS)
176 : : {
177 : 2565 : Name arg1 = PG_GETARG_NAME(0);
178 : 2565 : Name arg2 = PG_GETARG_NAME(1);
179 : :
180 : 5130 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) <= 0);
181 : 2565 : }
182 : :
183 : : Datum
184 : 1170 : namegt(PG_FUNCTION_ARGS)
185 : : {
186 : 1170 : Name arg1 = PG_GETARG_NAME(0);
187 : 1170 : Name arg2 = PG_GETARG_NAME(1);
188 : :
189 : 2340 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) > 0);
190 : 1170 : }
191 : :
192 : : Datum
193 : 3024 : namege(PG_FUNCTION_ARGS)
194 : : {
195 : 3024 : Name arg1 = PG_GETARG_NAME(0);
196 : 3024 : Name arg2 = PG_GETARG_NAME(1);
197 : :
198 : 6048 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) >= 0);
199 : 3024 : }
200 : :
201 : : Datum
202 : 1783013 : btnamecmp(PG_FUNCTION_ARGS)
203 : : {
204 : 1783013 : Name arg1 = PG_GETARG_NAME(0);
205 : 1783013 : Name arg2 = PG_GETARG_NAME(1);
206 : :
207 : 3566026 : PG_RETURN_INT32(namecmp(arg1, arg2, PG_GET_COLLATION()));
208 : 1783013 : }
209 : :
210 : : Datum
211 : 6068 : btnamesortsupport(PG_FUNCTION_ARGS)
212 : : {
213 : 6068 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
214 : 6068 : Oid collid = ssup->ssup_collation;
215 : 6068 : MemoryContext oldcontext;
216 : :
217 : 6068 : oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
218 : :
219 : : /* Use generic string SortSupport */
220 : 6068 : varstr_sortsupport(ssup, NAMEOID, collid);
221 : :
222 : 6068 : MemoryContextSwitchTo(oldcontext);
223 : :
224 : 6068 : PG_RETURN_VOID();
225 : 6068 : }
226 : :
227 : :
228 : : /*****************************************************************************
229 : : * MISCELLANEOUS PUBLIC ROUTINES *
230 : : *****************************************************************************/
231 : :
232 : : void
233 : 2414458 : namestrcpy(Name name, const char *str)
234 : : {
235 : : /* NB: We need to zero-pad the destination. */
236 : 2414458 : strncpy(NameStr(*name), str, NAMEDATALEN);
237 : 2414458 : NameStr(*name)[NAMEDATALEN - 1] = '\0';
238 : 2414458 : }
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 : 24146 : namestrcmp(Name name, const char *str)
248 : : {
249 [ - + # # ]: 24146 : if (!name && !str)
250 : 0 : return 0;
251 [ + - ]: 24146 : if (!name)
252 : 0 : return -1; /* NULL < anything */
253 [ + - ]: 24146 : if (!str)
254 : 0 : return 1; /* NULL < anything */
255 : 24146 : return strncmp(NameStr(*name), str, NAMEDATALEN);
256 : 24146 : }
257 : :
258 : :
259 : : /*
260 : : * SQL-functions CURRENT_USER, SESSION_USER
261 : : */
262 : : Datum
263 : 1194 : current_user(PG_FUNCTION_ARGS)
264 : : {
265 : 1194 : PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId(), false))));
266 : : }
267 : :
268 : : Datum
269 : 17 : session_user(PG_FUNCTION_ARGS)
270 : : {
271 : 17 : PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetSessionUserId(), false))));
272 : : }
273 : :
274 : :
275 : : /*
276 : : * SQL-functions CURRENT_SCHEMA, CURRENT_SCHEMAS
277 : : */
278 : : Datum
279 : 4 : current_schema(PG_FUNCTION_ARGS)
280 : : {
281 : 4 : List *search_path = fetch_search_path(false);
282 : 4 : char *nspname;
283 : :
284 [ + + ]: 4 : if (search_path == NIL)
285 : 1 : PG_RETURN_NULL();
286 : 3 : nspname = get_namespace_name(linitial_oid(search_path));
287 : 3 : list_free(search_path);
288 [ + - ]: 3 : if (!nspname)
289 : 0 : PG_RETURN_NULL(); /* recently-deleted namespace? */
290 : 3 : PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(nspname)));
291 : 4 : }
292 : :
293 : : Datum
294 : 4 : current_schemas(PG_FUNCTION_ARGS)
295 : : {
296 : 4 : List *search_path = fetch_search_path(PG_GETARG_BOOL(0));
297 : 4 : ListCell *l;
298 : 4 : Datum *names;
299 : 4 : int i;
300 : 4 : ArrayType *array;
301 : :
302 : 4 : names = (Datum *) palloc(list_length(search_path) * sizeof(Datum));
303 : 4 : i = 0;
304 [ + - + + : 11 : foreach(l, search_path)
+ + ]
305 : : {
306 : 7 : char *nspname;
307 : :
308 : 7 : nspname = get_namespace_name(lfirst_oid(l));
309 [ - + ]: 7 : if (nspname) /* watch out for deleted namespace */
310 : : {
311 : 7 : names[i] = DirectFunctionCall1(namein, CStringGetDatum(nspname));
312 : 7 : i++;
313 : 7 : }
314 : 7 : }
315 : 4 : list_free(search_path);
316 : :
317 : 4 : array = construct_array_builtin(names, i, NAMEOID);
318 : :
319 : 8 : PG_RETURN_POINTER(array);
320 : 4 : }
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 : 3667 : nameconcatoid(PG_FUNCTION_ARGS)
334 : : {
335 : 3667 : Name nam = PG_GETARG_NAME(0);
336 : 3667 : Oid oid = PG_GETARG_OID(1);
337 : 3667 : Name result;
338 : 3667 : char suffix[20];
339 : 3667 : int suflen;
340 : 3667 : int namlen;
341 : :
342 : 3667 : suflen = snprintf(suffix, sizeof(suffix), "_%u", oid);
343 : 3667 : namlen = strlen(NameStr(*nam));
344 : :
345 : : /* Truncate oversize input by truncating name part, not suffix */
346 [ + - ]: 3667 : 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 : 3667 : result = (Name) palloc0(NAMEDATALEN);
351 : 3667 : memcpy(NameStr(*result), NameStr(*nam), namlen);
352 : 3667 : memcpy(NameStr(*result) + namlen, suffix, suflen);
353 : :
354 : 7334 : PG_RETURN_NAME(result);
355 : 3667 : }
|