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