Age Owner TLA 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-2023, 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 "..." 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
8284 tgl 48 CBC 1737290 : namein(PG_FUNCTION_ARGS)
49 : {
50 1737290 : char *s = PG_GETARG_CSTRING(0);
51 : Name result;
52 : int len;
53 :
7605 ishii 54 1737290 : len = strlen(s);
55 :
56 : /* Truncate oversize input */
3971 tgl 57 1737290 : if (len >= NAMEDATALEN)
58 27 : len = pg_mbcliplen(s, len, NAMEDATALEN - 1);
59 :
60 : /* We use palloc0 here to ensure result is zero-padded */
61 1737290 : result = (Name) palloc0(NAMEDATALEN);
7605 ishii 62 1737290 : memcpy(NameStr(*result), s, len);
63 :
8284 tgl 64 1737290 : PG_RETURN_NAME(result);
65 : }
66 :
67 : /*
68 : * nameout - converts internal representation to "..."
69 : */
70 : Datum
71 970205 : nameout(PG_FUNCTION_ARGS)
72 : {
73 970205 : Name s = PG_GETARG_NAME(0);
74 :
75 970205 : PG_RETURN_CSTRING(pstrdup(NameStr(*s)));
76 : }
77 :
78 : /*
79 : * namerecv - converts external binary format to name
80 : */
81 : Datum
7275 82 3 : namerecv(PG_FUNCTION_ARGS)
83 : {
84 3 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
85 : Name result;
86 : char *str;
87 : int nbytes;
88 :
89 3 : str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
90 3 : if (nbytes >= NAMEDATALEN)
7196 tgl 91 UBC 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)));
7275 tgl 96 CBC 3 : result = (NameData *) palloc0(NAMEDATALEN);
97 3 : memcpy(result, str, nbytes);
98 3 : pfree(str);
99 3 : PG_RETURN_NAME(result);
100 : }
101 :
102 : /*
103 : * namesend - converts name to binary format
104 : */
105 : Datum
106 3 : namesend(PG_FUNCTION_ARGS)
107 : {
108 3 : Name s = PG_GETARG_NAME(0);
109 : StringInfoData buf;
110 :
111 3 : pq_begintypsend(&buf);
112 3 : pq_sendtext(&buf, NameStr(*s), strlen(NameStr(*s)));
113 3 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
114 : }
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
1479 peter 135 66179983 : namecmp(Name arg1, Name arg2, Oid collid)
136 : {
137 : /* Fast path for common case used in system catalogs */
138 66179983 : if (collid == C_COLLATION_OID)
139 66179983 : return strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN);
140 :
141 : /* Else rely on the varstr infrastructure */
1479 peter 142 UBC 0 : return varstr_cmp(NameStr(*arg1), strlen(NameStr(*arg1)),
143 0 : NameStr(*arg2), strlen(NameStr(*arg2)),
144 : collid);
145 : }
146 :
147 : Datum
8284 tgl 148 CBC 36083456 : nameeq(PG_FUNCTION_ARGS)
149 : {
150 36083456 : Name arg1 = PG_GETARG_NAME(0);
151 36083456 : Name arg2 = PG_GETARG_NAME(1);
152 :
1479 peter 153 36083456 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) == 0);
154 : }
155 :
156 : Datum
8284 tgl 157 18527 : namene(PG_FUNCTION_ARGS)
158 : {
159 18527 : Name arg1 = PG_GETARG_NAME(0);
160 18527 : Name arg2 = PG_GETARG_NAME(1);
161 :
1479 peter 162 18527 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) != 0);
163 : }
164 :
165 : Datum
8284 tgl 166 45307 : namelt(PG_FUNCTION_ARGS)
167 : {
168 45307 : Name arg1 = PG_GETARG_NAME(0);
169 45307 : Name arg2 = PG_GETARG_NAME(1);
170 :
1572 171 45307 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) < 0);
172 : }
173 :
174 : Datum
8284 175 5730 : namele(PG_FUNCTION_ARGS)
176 : {
177 5730 : Name arg1 = PG_GETARG_NAME(0);
178 5730 : Name arg2 = PG_GETARG_NAME(1);
179 :
1572 180 5730 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) <= 0);
181 : }
182 :
183 : Datum
8284 184 2008 : namegt(PG_FUNCTION_ARGS)
185 : {
186 2008 : Name arg1 = PG_GETARG_NAME(0);
187 2008 : Name arg2 = PG_GETARG_NAME(1);
188 :
1572 189 2008 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) > 0);
190 : }
191 :
192 : Datum
8284 193 7140 : namege(PG_FUNCTION_ARGS)
194 : {
195 7140 : Name arg1 = PG_GETARG_NAME(0);
196 7140 : Name arg2 = PG_GETARG_NAME(1);
197 :
1572 198 7140 : PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) >= 0);
199 : }
200 :
201 : Datum
202 30017815 : btnamecmp(PG_FUNCTION_ARGS)
203 : {
204 30017815 : Name arg1 = PG_GETARG_NAME(0);
205 30017815 : Name arg2 = PG_GETARG_NAME(1);
206 :
207 30017815 : PG_RETURN_INT32(namecmp(arg1, arg2, PG_GET_COLLATION()));
208 : }
209 :
210 : Datum
211 38227 : btnamesortsupport(PG_FUNCTION_ARGS)
212 : {
213 38227 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
214 38227 : Oid collid = ssup->ssup_collation;
215 : MemoryContext oldcontext;
216 :
217 38227 : oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
218 :
219 : /* Use generic string SortSupport */
220 38227 : varstr_sortsupport(ssup, NAMEOID, collid);
221 :
222 38227 : MemoryContextSwitchTo(oldcontext);
223 :
224 38227 : PG_RETURN_VOID();
225 : }
226 :
227 :
228 : /*****************************************************************************
229 : * MISCELLANEOUS PUBLIC ROUTINES *
230 : *****************************************************************************/
231 :
232 : void
8478 peter_e 233 7715214 : namestrcpy(Name name, const char *str)
234 : {
235 : /* NB: We need to zero-pad the destination. */
972 peter 236 7715214 : strncpy(NameStr(*name), str, NAMEDATALEN);
697 tgl 237 7715214 : NameStr(*name)[NAMEDATALEN - 1] = '\0';
9770 scrappy 238 7715214 : }
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
8478 peter_e 247 5156480 : namestrcmp(Name name, const char *str)
248 : {
9345 bruce 249 5156480 : if (!name && !str)
8986 bruce 250 UBC 0 : return 0;
9345 bruce 251 CBC 5156480 : if (!name)
8986 bruce 252 UBC 0 : return -1; /* NULL < anything */
9345 bruce 253 CBC 5156480 : if (!str)
8986 bruce 254 UBC 0 : return 1; /* NULL < anything */
8554 bruce 255 CBC 5156480 : return strncmp(NameStr(*name), str, NAMEDATALEN);
256 : }
257 :
258 :
259 : /*
260 : * SQL-functions CURRENT_USER, SESSION_USER
261 : */
262 : Datum
8237 peter_e 263 8253 : current_user(PG_FUNCTION_ARGS)
264 : {
2892 andrew 265 8253 : PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId(), false))));
266 : }
267 :
268 : Datum
8237 peter_e 269 34 : session_user(PG_FUNCTION_ARGS)
270 : {
2892 andrew 271 34 : PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetSessionUserId(), false))));
272 : }
273 :
274 :
275 : /*
276 : * SQL-functions CURRENT_SCHEMA, CURRENT_SCHEMAS
277 : */
278 : Datum
7653 tgl 279 16 : current_schema(PG_FUNCTION_ARGS)
280 : {
7522 bruce 281 16 : List *search_path = fetch_search_path(false);
282 : char *nspname;
283 :
7653 tgl 284 16 : if (search_path == NIL)
285 3 : PG_RETURN_NULL();
6892 neilc 286 13 : nspname = get_namespace_name(linitial_oid(search_path));
287 13 : list_free(search_path);
7287 tgl 288 13 : if (!nspname)
7287 tgl 289 UBC 0 : PG_RETURN_NULL(); /* recently-deleted namespace? */
7653 tgl 290 CBC 13 : PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(nspname)));
291 : }
292 :
293 : Datum
294 202 : current_schemas(PG_FUNCTION_ARGS)
295 : {
7522 bruce 296 202 : List *search_path = fetch_search_path(PG_GETARG_BOOL(0));
297 : ListCell *l;
298 : Datum *names;
299 : int i;
300 : ArrayType *array;
301 :
6882 tgl 302 202 : names = (Datum *) palloc(list_length(search_path) * sizeof(Datum));
7653 303 202 : i = 0;
6892 neilc 304 367 : foreach(l, search_path)
305 : {
306 : char *nspname;
307 :
308 165 : nspname = get_namespace_name(lfirst_oid(l));
7287 tgl 309 165 : if (nspname) /* watch out for deleted namespace */
310 : {
311 165 : names[i] = DirectFunctionCall1(namein, CStringGetDatum(nspname));
312 165 : i++;
313 : }
314 : }
6892 neilc 315 202 : list_free(search_path);
316 :
282 peter 317 GNC 202 : array = construct_array_builtin(names, i, NAMEOID);
318 :
7653 tgl 319 GIC 202 : PG_RETURN_POINTER(array);
320 : }
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
1571 tgl 329 ECB : * 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
1571 tgl 333 GIC 17309 : nameconcatoid(PG_FUNCTION_ARGS)
334 : {
335 17309 : Name nam = PG_GETARG_NAME(0);
336 17309 : Oid oid = PG_GETARG_OID(1);
337 : Name result;
1571 tgl 338 ECB : char suffix[20];
339 : int suflen;
340 : int namlen;
341 :
1571 tgl 342 CBC 17309 : suflen = snprintf(suffix, sizeof(suffix), "_%u", oid);
1571 tgl 343 GBC 17309 : namlen = strlen(NameStr(*nam));
344 :
345 : /* Truncate oversize input by truncating name part, not suffix */
1571 tgl 346 CBC 17309 : if (namlen + suflen >= NAMEDATALEN)
1571 tgl 347 LBC 0 : namlen = pg_mbcliplen(NameStr(*nam), namlen, NAMEDATALEN - 1 - suflen);
1571 tgl 348 ECB :
349 : /* We use palloc0 here to ensure result is zero-padded */
1571 tgl 350 CBC 17309 : result = (Name) palloc0(NAMEDATALEN);
1571 tgl 351 GIC 17309 : memcpy(NameStr(*result), NameStr(*nam), namlen);
352 17309 : memcpy(NameStr(*result) + namlen, suffix, suflen);
353 :
354 17309 : PG_RETURN_NAME(result);
355 : }
|