1 /*-------------------------------------------------------------------------
2 *
3 * oid.c
4 * Functions for the built-in type Oid ... also oidvector.
5 *
6 * Portions Copyright (c) 1996-2018, 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 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
260 FunctionCallInfoData locfcinfo;
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.arg[0] = PointerGetDatum(buf);
273 locfcinfo.arg[1] = ObjectIdGetDatum(OIDOID);
274 locfcinfo.arg[2] = Int32GetDatum(-1);
275 locfcinfo.argnull[0] = false;
276 locfcinfo.argnull[1] = false;
277 locfcinfo.argnull[2] = 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