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