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-2019, 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 |
48 | namein(PG_FUNCTION_ARGS) |
49 | { |
50 | char *s = PG_GETARG_CSTRING(0); |
51 | Name result; |
52 | int len; |
53 | |
54 | len = strlen(s); |
55 | |
56 | /* Truncate oversize input */ |
57 | if (len >= NAMEDATALEN) |
58 | len = pg_mbcliplen(s, len, NAMEDATALEN - 1); |
59 | |
60 | /* We use palloc0 here to ensure result is zero-padded */ |
61 | result = (Name) palloc0(NAMEDATALEN); |
62 | memcpy(NameStr(*result), s, len); |
63 | |
64 | PG_RETURN_NAME(result); |
65 | } |
66 | |
67 | /* |
68 | * nameout - converts internal representation to "..." |
69 | */ |
70 | Datum |
71 | nameout(PG_FUNCTION_ARGS) |
72 | { |
73 | Name s = PG_GETARG_NAME(0); |
74 | |
75 | PG_RETURN_CSTRING(pstrdup(NameStr(*s))); |
76 | } |
77 | |
78 | /* |
79 | * namerecv - converts external binary format to name |
80 | */ |
81 | Datum |
82 | namerecv(PG_FUNCTION_ARGS) |
83 | { |
84 | StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); |
85 | Name result; |
86 | char *str; |
87 | int nbytes; |
88 | |
89 | str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); |
90 | if (nbytes >= NAMEDATALEN) |
91 | 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 | result = (NameData *) palloc0(NAMEDATALEN); |
97 | memcpy(result, str, nbytes); |
98 | pfree(str); |
99 | PG_RETURN_NAME(result); |
100 | } |
101 | |
102 | /* |
103 | * namesend - converts name to binary format |
104 | */ |
105 | Datum |
106 | namesend(PG_FUNCTION_ARGS) |
107 | { |
108 | Name s = PG_GETARG_NAME(0); |
109 | StringInfoData buf; |
110 | |
111 | pq_begintypsend(&buf); |
112 | pq_sendtext(&buf, NameStr(*s), strlen(NameStr(*s))); |
113 | 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 |
135 | namecmp(Name arg1, Name arg2, Oid collid) |
136 | { |
137 | /* Fast path for common case used in system catalogs */ |
138 | if (collid == C_COLLATION_OID) |
139 | return strncmp(NameStr(*arg1), NameStr(*arg2), NAMEDATALEN); |
140 | |
141 | /* Else rely on the varstr infrastructure */ |
142 | return varstr_cmp(NameStr(*arg1), strlen(NameStr(*arg1)), |
143 | NameStr(*arg2), strlen(NameStr(*arg2)), |
144 | collid); |
145 | } |
146 | |
147 | Datum |
148 | nameeq(PG_FUNCTION_ARGS) |
149 | { |
150 | Name arg1 = PG_GETARG_NAME(0); |
151 | Name arg2 = PG_GETARG_NAME(1); |
152 | |
153 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) == 0); |
154 | } |
155 | |
156 | Datum |
157 | namene(PG_FUNCTION_ARGS) |
158 | { |
159 | Name arg1 = PG_GETARG_NAME(0); |
160 | Name arg2 = PG_GETARG_NAME(1); |
161 | |
162 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) != 0); |
163 | } |
164 | |
165 | Datum |
166 | namelt(PG_FUNCTION_ARGS) |
167 | { |
168 | Name arg1 = PG_GETARG_NAME(0); |
169 | Name arg2 = PG_GETARG_NAME(1); |
170 | |
171 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) < 0); |
172 | } |
173 | |
174 | Datum |
175 | namele(PG_FUNCTION_ARGS) |
176 | { |
177 | Name arg1 = PG_GETARG_NAME(0); |
178 | Name arg2 = PG_GETARG_NAME(1); |
179 | |
180 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) <= 0); |
181 | } |
182 | |
183 | Datum |
184 | namegt(PG_FUNCTION_ARGS) |
185 | { |
186 | Name arg1 = PG_GETARG_NAME(0); |
187 | Name arg2 = PG_GETARG_NAME(1); |
188 | |
189 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) > 0); |
190 | } |
191 | |
192 | Datum |
193 | namege(PG_FUNCTION_ARGS) |
194 | { |
195 | Name arg1 = PG_GETARG_NAME(0); |
196 | Name arg2 = PG_GETARG_NAME(1); |
197 | |
198 | PG_RETURN_BOOL(namecmp(arg1, arg2, PG_GET_COLLATION()) >= 0); |
199 | } |
200 | |
201 | Datum |
202 | btnamecmp(PG_FUNCTION_ARGS) |
203 | { |
204 | Name arg1 = PG_GETARG_NAME(0); |
205 | Name arg2 = PG_GETARG_NAME(1); |
206 | |
207 | PG_RETURN_INT32(namecmp(arg1, arg2, PG_GET_COLLATION())); |
208 | } |
209 | |
210 | Datum |
211 | btnamesortsupport(PG_FUNCTION_ARGS) |
212 | { |
213 | SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0); |
214 | Oid collid = ssup->ssup_collation; |
215 | MemoryContext oldcontext; |
216 | |
217 | oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt); |
218 | |
219 | /* Use generic string SortSupport */ |
220 | varstr_sortsupport(ssup, NAMEOID, collid); |
221 | |
222 | MemoryContextSwitchTo(oldcontext); |
223 | |
224 | PG_RETURN_VOID(); |
225 | } |
226 | |
227 | |
228 | /***************************************************************************** |
229 | * MISCELLANEOUS PUBLIC ROUTINES * |
230 | *****************************************************************************/ |
231 | |
232 | int |
233 | namecpy(Name n1, const NameData *n2) |
234 | { |
235 | if (!n1 || !n2) |
236 | return -1; |
237 | StrNCpy(NameStr(*n1), NameStr(*n2), NAMEDATALEN); |
238 | return 0; |
239 | } |
240 | |
241 | #ifdef NOT_USED |
242 | int |
243 | namecat(Name n1, Name n2) |
244 | { |
245 | return namestrcat(n1, NameStr(*n2)); /* n2 can't be any longer than n1 */ |
246 | } |
247 | #endif |
248 | |
249 | int |
250 | namestrcpy(Name name, const char *str) |
251 | { |
252 | if (!name || !str) |
253 | return -1; |
254 | StrNCpy(NameStr(*name), str, NAMEDATALEN); |
255 | return 0; |
256 | } |
257 | |
258 | #ifdef NOT_USED |
259 | int |
260 | namestrcat(Name name, const char *str) |
261 | { |
262 | int i; |
263 | char *p, |
264 | *q; |
265 | |
266 | if (!name || !str) |
267 | return -1; |
268 | for (i = 0, p = NameStr(*name); i < NAMEDATALEN && *p; ++i, ++p) |
269 | ; |
270 | for (q = str; i < NAMEDATALEN; ++i, ++p, ++q) |
271 | { |
272 | *p = *q; |
273 | if (!*q) |
274 | break; |
275 | } |
276 | return 0; |
277 | } |
278 | #endif |
279 | |
280 | /* |
281 | * Compare a NAME to a C string |
282 | * |
283 | * Assumes C collation always; be careful when using this for |
284 | * anything but equality checks! |
285 | */ |
286 | int |
287 | namestrcmp(Name name, const char *str) |
288 | { |
289 | if (!name && !str) |
290 | return 0; |
291 | if (!name) |
292 | return -1; /* NULL < anything */ |
293 | if (!str) |
294 | return 1; /* NULL < anything */ |
295 | return strncmp(NameStr(*name), str, NAMEDATALEN); |
296 | } |
297 | |
298 | |
299 | /* |
300 | * SQL-functions CURRENT_USER, SESSION_USER |
301 | */ |
302 | Datum |
303 | current_user(PG_FUNCTION_ARGS) |
304 | { |
305 | PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId(), false)))); |
306 | } |
307 | |
308 | Datum |
309 | session_user(PG_FUNCTION_ARGS) |
310 | { |
311 | PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetSessionUserId(), false)))); |
312 | } |
313 | |
314 | |
315 | /* |
316 | * SQL-functions CURRENT_SCHEMA, CURRENT_SCHEMAS |
317 | */ |
318 | Datum |
319 | current_schema(PG_FUNCTION_ARGS) |
320 | { |
321 | List *search_path = fetch_search_path(false); |
322 | char *nspname; |
323 | |
324 | if (search_path == NIL) |
325 | PG_RETURN_NULL(); |
326 | nspname = get_namespace_name(linitial_oid(search_path)); |
327 | list_free(search_path); |
328 | if (!nspname) |
329 | PG_RETURN_NULL(); /* recently-deleted namespace? */ |
330 | PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(nspname))); |
331 | } |
332 | |
333 | Datum |
334 | current_schemas(PG_FUNCTION_ARGS) |
335 | { |
336 | List *search_path = fetch_search_path(PG_GETARG_BOOL(0)); |
337 | ListCell *l; |
338 | Datum *names; |
339 | int i; |
340 | ArrayType *array; |
341 | |
342 | names = (Datum *) palloc(list_length(search_path) * sizeof(Datum)); |
343 | i = 0; |
344 | foreach(l, search_path) |
345 | { |
346 | char *nspname; |
347 | |
348 | nspname = get_namespace_name(lfirst_oid(l)); |
349 | if (nspname) /* watch out for deleted namespace */ |
350 | { |
351 | names[i] = DirectFunctionCall1(namein, CStringGetDatum(nspname)); |
352 | i++; |
353 | } |
354 | } |
355 | list_free(search_path); |
356 | |
357 | array = construct_array(names, i, |
358 | NAMEOID, |
359 | NAMEDATALEN, /* sizeof(Name) */ |
360 | false, /* Name is not by-val */ |
361 | 'c'); /* alignment of Name */ |
362 | |
363 | PG_RETURN_POINTER(array); |
364 | } |
365 | |
366 | /* |
367 | * SQL-function nameconcatoid(name, oid) returns name |
368 | * |
369 | * This is used in the information_schema to produce specific_name columns, |
370 | * which are supposed to be unique per schema. We achieve that (in an ugly |
371 | * way) by appending the object's OID. The result is the same as |
372 | * ($1::text || '_' || $2::text)::name |
373 | * except that, if it would not fit in NAMEDATALEN, we make it do so by |
374 | * truncating the name input (not the oid). |
375 | */ |
376 | Datum |
377 | nameconcatoid(PG_FUNCTION_ARGS) |
378 | { |
379 | Name nam = PG_GETARG_NAME(0); |
380 | Oid oid = PG_GETARG_OID(1); |
381 | Name result; |
382 | char suffix[20]; |
383 | int suflen; |
384 | int namlen; |
385 | |
386 | suflen = snprintf(suffix, sizeof(suffix), "_%u" , oid); |
387 | namlen = strlen(NameStr(*nam)); |
388 | |
389 | /* Truncate oversize input by truncating name part, not suffix */ |
390 | if (namlen + suflen >= NAMEDATALEN) |
391 | namlen = pg_mbcliplen(NameStr(*nam), namlen, NAMEDATALEN - 1 - suflen); |
392 | |
393 | /* We use palloc0 here to ensure result is zero-padded */ |
394 | result = (Name) palloc0(NAMEDATALEN); |
395 | memcpy(NameStr(*result), NameStr(*nam), namlen); |
396 | memcpy(NameStr(*result) + namlen, suffix, suflen); |
397 | |
398 | PG_RETURN_NAME(result); |
399 | } |
400 | |