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