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-2020, 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
namein(PG_FUNCTION_ARGS)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
nameout(PG_FUNCTION_ARGS)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
namerecv(PG_FUNCTION_ARGS)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
namesend(PG_FUNCTION_ARGS)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
namecmp(Name arg1,Name arg2,Oid collid)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
nameeq(PG_FUNCTION_ARGS)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
namene(PG_FUNCTION_ARGS)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
namelt(PG_FUNCTION_ARGS)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
namele(PG_FUNCTION_ARGS)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
namegt(PG_FUNCTION_ARGS)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
namege(PG_FUNCTION_ARGS)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
btnamecmp(PG_FUNCTION_ARGS)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
btnamesortsupport(PG_FUNCTION_ARGS)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
namecpy(Name n1,const NameData * n2)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
namecat(Name n1,Name n2)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
namestrcpy(Name name,const char * str)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
namestrcat(Name name,const char * str)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
namestrcmp(Name name,const char * str)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
current_user(PG_FUNCTION_ARGS)303 current_user(PG_FUNCTION_ARGS)
304 {
305 PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId(), false))));
306 }
307
308 Datum
session_user(PG_FUNCTION_ARGS)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
current_schema(PG_FUNCTION_ARGS)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
current_schemas(PG_FUNCTION_ARGS)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 TYPALIGN_CHAR); /* 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
nameconcatoid(PG_FUNCTION_ARGS)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