1 /*-------------------------------------------------------------------------
2  *
3  * oid.c
4  *	  Functions for the built-in type Oid ... also oidvector.
5  *
6  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/utils/adt/oid.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include <ctype.h>
18 #include <limits.h>
19 
20 #include "catalog/pg_type.h"
21 #include "libpq/pqformat.h"
22 #include "nodes/value.h"
23 #include "utils/array.h"
24 #include "utils/builtins.h"
25 
26 
27 #define OidVectorSize(n)	(offsetof(oidvector, values) + (n) * sizeof(Oid))
28 
29 
30 /*****************************************************************************
31  *	 USER I/O ROUTINES														 *
32  *****************************************************************************/
33 
34 static Oid
oidin_subr(const char * s,char ** endloc)35 oidin_subr(const char *s, char **endloc)
36 {
37 	unsigned long cvt;
38 	char	   *endptr;
39 	Oid			result;
40 
41 	if (*s == '\0')
42 		ereport(ERROR,
43 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
44 				 errmsg("invalid input syntax for type %s: \"%s\"",
45 						"oid", s)));
46 
47 	errno = 0;
48 	cvt = strtoul(s, &endptr, 10);
49 
50 	/*
51 	 * strtoul() normally only sets ERANGE.  On some systems it also may set
52 	 * EINVAL, which simply means it couldn't parse the input string. This is
53 	 * handled by the second "if" consistent across platforms.
54 	 */
55 	if (errno && errno != ERANGE && errno != EINVAL)
56 		ereport(ERROR,
57 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
58 				 errmsg("invalid input syntax for type %s: \"%s\"",
59 						"oid", s)));
60 
61 	if (endptr == s && *s != '\0')
62 		ereport(ERROR,
63 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
64 				 errmsg("invalid input syntax for type %s: \"%s\"",
65 						"oid", s)));
66 
67 	if (errno == ERANGE)
68 		ereport(ERROR,
69 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
70 				 errmsg("value \"%s\" is out of range for type %s",
71 						s, "oid")));
72 
73 	if (endloc)
74 	{
75 		/* caller wants to deal with rest of string */
76 		*endloc = endptr;
77 	}
78 	else
79 	{
80 		/* allow only whitespace after number */
81 		while (*endptr && isspace((unsigned char) *endptr))
82 			endptr++;
83 		if (*endptr)
84 			ereport(ERROR,
85 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
86 					 errmsg("invalid input syntax for type %s: \"%s\"",
87 							"oid", s)));
88 	}
89 
90 	result = (Oid) cvt;
91 
92 	/*
93 	 * Cope with possibility that unsigned long is wider than Oid, in which
94 	 * case strtoul will not raise an error for some values that are out of
95 	 * the range of Oid.
96 	 *
97 	 * For backwards compatibility, we want to accept inputs that are given
98 	 * with a minus sign, so allow the input value if it matches after either
99 	 * signed or unsigned extension to long.
100 	 *
101 	 * To ensure consistent results on 32-bit and 64-bit platforms, make sure
102 	 * the error message is the same as if strtoul() had returned ERANGE.
103 	 */
104 #if OID_MAX != ULONG_MAX
105 	if (cvt != (unsigned long) result &&
106 		cvt != (unsigned long) ((int) result))
107 		ereport(ERROR,
108 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
109 				 errmsg("value \"%s\" is out of range for type %s",
110 						s, "oid")));
111 #endif
112 
113 	return result;
114 }
115 
116 Datum
oidin(PG_FUNCTION_ARGS)117 oidin(PG_FUNCTION_ARGS)
118 {
119 	char	   *s = PG_GETARG_CSTRING(0);
120 	Oid			result;
121 
122 	result = oidin_subr(s, NULL);
123 	PG_RETURN_OID(result);
124 }
125 
126 Datum
oidout(PG_FUNCTION_ARGS)127 oidout(PG_FUNCTION_ARGS)
128 {
129 	Oid			o = PG_GETARG_OID(0);
130 	char	   *result = (char *) palloc(12);
131 
132 	snprintf(result, 12, "%u", o);
133 	PG_RETURN_CSTRING(result);
134 }
135 
136 /*
137  *		oidrecv			- converts external binary format to oid
138  */
139 Datum
oidrecv(PG_FUNCTION_ARGS)140 oidrecv(PG_FUNCTION_ARGS)
141 {
142 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
143 
144 	PG_RETURN_OID((Oid) pq_getmsgint(buf, sizeof(Oid)));
145 }
146 
147 /*
148  *		oidsend			- converts oid to binary format
149  */
150 Datum
oidsend(PG_FUNCTION_ARGS)151 oidsend(PG_FUNCTION_ARGS)
152 {
153 	Oid			arg1 = PG_GETARG_OID(0);
154 	StringInfoData buf;
155 
156 	pq_begintypsend(&buf);
157 	pq_sendint32(&buf, arg1);
158 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
159 }
160 
161 /*
162  * construct oidvector given a raw array of Oids
163  *
164  * If oids is NULL then caller must fill values[] afterward
165  */
166 oidvector *
buildoidvector(const Oid * oids,int n)167 buildoidvector(const Oid *oids, int n)
168 {
169 	oidvector  *result;
170 
171 	result = (oidvector *) palloc0(OidVectorSize(n));
172 
173 	if (n > 0 && oids)
174 		memcpy(result->values, oids, n * sizeof(Oid));
175 
176 	/*
177 	 * Attach standard array header.  For historical reasons, we set the index
178 	 * lower bound to 0 not 1.
179 	 */
180 	SET_VARSIZE(result, OidVectorSize(n));
181 	result->ndim = 1;
182 	result->dataoffset = 0;		/* never any nulls */
183 	result->elemtype = OIDOID;
184 	result->dim1 = n;
185 	result->lbound1 = 0;
186 
187 	return result;
188 }
189 
190 /*
191  *		oidvectorin			- converts "num num ..." to internal form
192  */
193 Datum
oidvectorin(PG_FUNCTION_ARGS)194 oidvectorin(PG_FUNCTION_ARGS)
195 {
196 	char	   *oidString = PG_GETARG_CSTRING(0);
197 	oidvector  *result;
198 	int			n;
199 
200 	result = (oidvector *) palloc0(OidVectorSize(FUNC_MAX_ARGS));
201 
202 	for (n = 0; n < FUNC_MAX_ARGS; n++)
203 	{
204 		while (*oidString && isspace((unsigned char) *oidString))
205 			oidString++;
206 		if (*oidString == '\0')
207 			break;
208 		result->values[n] = oidin_subr(oidString, &oidString);
209 	}
210 	while (*oidString && isspace((unsigned char) *oidString))
211 		oidString++;
212 	if (*oidString)
213 		ereport(ERROR,
214 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
215 				 errmsg("oidvector has too many elements")));
216 
217 	SET_VARSIZE(result, OidVectorSize(n));
218 	result->ndim = 1;
219 	result->dataoffset = 0;		/* never any nulls */
220 	result->elemtype = OIDOID;
221 	result->dim1 = n;
222 	result->lbound1 = 0;
223 
224 	PG_RETURN_POINTER(result);
225 }
226 
227 /*
228  *		oidvectorout - converts internal form to "num num ..."
229  */
230 Datum
oidvectorout(PG_FUNCTION_ARGS)231 oidvectorout(PG_FUNCTION_ARGS)
232 {
233 	oidvector  *oidArray = (oidvector *) PG_GETARG_POINTER(0);
234 	int			num,
235 				nnums = oidArray->dim1;
236 	char	   *rp;
237 	char	   *result;
238 
239 	/* assumes sign, 10 digits, ' ' */
240 	rp = result = (char *) palloc(nnums * 12 + 1);
241 	for (num = 0; num < nnums; num++)
242 	{
243 		if (num != 0)
244 			*rp++ = ' ';
245 		sprintf(rp, "%u", oidArray->values[num]);
246 		while (*++rp != '\0')
247 			;
248 	}
249 	*rp = '\0';
250 	PG_RETURN_CSTRING(result);
251 }
252 
253 /*
254  *		oidvectorrecv			- converts external binary format to oidvector
255  */
256 Datum
oidvectorrecv(PG_FUNCTION_ARGS)257 oidvectorrecv(PG_FUNCTION_ARGS)
258 {
259 	LOCAL_FCINFO(locfcinfo, 3);
260 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
261 	oidvector  *result;
262 
263 	/*
264 	 * Normally one would call array_recv() using DirectFunctionCall3, but
265 	 * that does not work since array_recv wants to cache some data using
266 	 * fcinfo->flinfo->fn_extra.  So we need to pass it our own flinfo
267 	 * parameter.
268 	 */
269 	InitFunctionCallInfoData(*locfcinfo, fcinfo->flinfo, 3,
270 							 InvalidOid, NULL, NULL);
271 
272 	locfcinfo->args[0].value = PointerGetDatum(buf);
273 	locfcinfo->args[0].isnull = false;
274 	locfcinfo->args[1].value = ObjectIdGetDatum(OIDOID);
275 	locfcinfo->args[1].isnull = false;
276 	locfcinfo->args[2].value = Int32GetDatum(-1);
277 	locfcinfo->args[2].isnull = false;
278 
279 	result = (oidvector *) DatumGetPointer(array_recv(locfcinfo));
280 
281 	Assert(!locfcinfo->isnull);
282 
283 	/* sanity checks: oidvector must be 1-D, 0-based, no nulls */
284 	if (ARR_NDIM(result) != 1 ||
285 		ARR_HASNULL(result) ||
286 		ARR_ELEMTYPE(result) != OIDOID ||
287 		ARR_LBOUND(result)[0] != 0)
288 		ereport(ERROR,
289 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
290 				 errmsg("invalid oidvector data")));
291 
292 	/* check length for consistency with oidvectorin() */
293 	if (ARR_DIMS(result)[0] > FUNC_MAX_ARGS)
294 		ereport(ERROR,
295 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
296 				 errmsg("oidvector has too many elements")));
297 
298 	PG_RETURN_POINTER(result);
299 }
300 
301 /*
302  *		oidvectorsend			- converts oidvector to binary format
303  */
304 Datum
oidvectorsend(PG_FUNCTION_ARGS)305 oidvectorsend(PG_FUNCTION_ARGS)
306 {
307 	return array_send(fcinfo);
308 }
309 
310 /*
311  *		oidparse				- get OID from ICONST/FCONST node
312  */
313 Oid
oidparse(Node * node)314 oidparse(Node *node)
315 {
316 	switch (nodeTag(node))
317 	{
318 		case T_Integer:
319 			return intVal(node);
320 		case T_Float:
321 
322 			/*
323 			 * Values too large for int4 will be represented as Float
324 			 * constants by the lexer.  Accept these if they are valid OID
325 			 * strings.
326 			 */
327 			return oidin_subr(strVal(node), NULL);
328 		default:
329 			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
330 	}
331 	return InvalidOid;			/* keep compiler quiet */
332 }
333 
334 /* qsort comparison function for Oids */
335 int
oid_cmp(const void * p1,const void * p2)336 oid_cmp(const void *p1, const void *p2)
337 {
338 	Oid			v1 = *((const Oid *) p1);
339 	Oid			v2 = *((const Oid *) p2);
340 
341 	if (v1 < v2)
342 		return -1;
343 	if (v1 > v2)
344 		return 1;
345 	return 0;
346 }
347 
348 
349 /*****************************************************************************
350  *	 PUBLIC ROUTINES														 *
351  *****************************************************************************/
352 
353 Datum
oideq(PG_FUNCTION_ARGS)354 oideq(PG_FUNCTION_ARGS)
355 {
356 	Oid			arg1 = PG_GETARG_OID(0);
357 	Oid			arg2 = PG_GETARG_OID(1);
358 
359 	PG_RETURN_BOOL(arg1 == arg2);
360 }
361 
362 Datum
oidne(PG_FUNCTION_ARGS)363 oidne(PG_FUNCTION_ARGS)
364 {
365 	Oid			arg1 = PG_GETARG_OID(0);
366 	Oid			arg2 = PG_GETARG_OID(1);
367 
368 	PG_RETURN_BOOL(arg1 != arg2);
369 }
370 
371 Datum
oidlt(PG_FUNCTION_ARGS)372 oidlt(PG_FUNCTION_ARGS)
373 {
374 	Oid			arg1 = PG_GETARG_OID(0);
375 	Oid			arg2 = PG_GETARG_OID(1);
376 
377 	PG_RETURN_BOOL(arg1 < arg2);
378 }
379 
380 Datum
oidle(PG_FUNCTION_ARGS)381 oidle(PG_FUNCTION_ARGS)
382 {
383 	Oid			arg1 = PG_GETARG_OID(0);
384 	Oid			arg2 = PG_GETARG_OID(1);
385 
386 	PG_RETURN_BOOL(arg1 <= arg2);
387 }
388 
389 Datum
oidge(PG_FUNCTION_ARGS)390 oidge(PG_FUNCTION_ARGS)
391 {
392 	Oid			arg1 = PG_GETARG_OID(0);
393 	Oid			arg2 = PG_GETARG_OID(1);
394 
395 	PG_RETURN_BOOL(arg1 >= arg2);
396 }
397 
398 Datum
oidgt(PG_FUNCTION_ARGS)399 oidgt(PG_FUNCTION_ARGS)
400 {
401 	Oid			arg1 = PG_GETARG_OID(0);
402 	Oid			arg2 = PG_GETARG_OID(1);
403 
404 	PG_RETURN_BOOL(arg1 > arg2);
405 }
406 
407 Datum
oidlarger(PG_FUNCTION_ARGS)408 oidlarger(PG_FUNCTION_ARGS)
409 {
410 	Oid			arg1 = PG_GETARG_OID(0);
411 	Oid			arg2 = PG_GETARG_OID(1);
412 
413 	PG_RETURN_OID((arg1 > arg2) ? arg1 : arg2);
414 }
415 
416 Datum
oidsmaller(PG_FUNCTION_ARGS)417 oidsmaller(PG_FUNCTION_ARGS)
418 {
419 	Oid			arg1 = PG_GETARG_OID(0);
420 	Oid			arg2 = PG_GETARG_OID(1);
421 
422 	PG_RETURN_OID((arg1 < arg2) ? arg1 : arg2);
423 }
424 
425 Datum
oidvectoreq(PG_FUNCTION_ARGS)426 oidvectoreq(PG_FUNCTION_ARGS)
427 {
428 	int32		cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
429 
430 	PG_RETURN_BOOL(cmp == 0);
431 }
432 
433 Datum
oidvectorne(PG_FUNCTION_ARGS)434 oidvectorne(PG_FUNCTION_ARGS)
435 {
436 	int32		cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
437 
438 	PG_RETURN_BOOL(cmp != 0);
439 }
440 
441 Datum
oidvectorlt(PG_FUNCTION_ARGS)442 oidvectorlt(PG_FUNCTION_ARGS)
443 {
444 	int32		cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
445 
446 	PG_RETURN_BOOL(cmp < 0);
447 }
448 
449 Datum
oidvectorle(PG_FUNCTION_ARGS)450 oidvectorle(PG_FUNCTION_ARGS)
451 {
452 	int32		cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
453 
454 	PG_RETURN_BOOL(cmp <= 0);
455 }
456 
457 Datum
oidvectorge(PG_FUNCTION_ARGS)458 oidvectorge(PG_FUNCTION_ARGS)
459 {
460 	int32		cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
461 
462 	PG_RETURN_BOOL(cmp >= 0);
463 }
464 
465 Datum
oidvectorgt(PG_FUNCTION_ARGS)466 oidvectorgt(PG_FUNCTION_ARGS)
467 {
468 	int32		cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
469 
470 	PG_RETURN_BOOL(cmp > 0);
471 }
472