Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * oid.c
4 : * Functions for the built-in type Oid ... also oidvector.
5 : *
6 : * Portions Copyright (c) 1996-2017, 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
35 45980 : oidin_subr(const char *s, char **endloc)
36 : {
37 : unsigned long cvt;
38 : char *endptr;
39 : Oid result;
40 :
41 45980 : if (*s == '\0')
42 1 : ereport(ERROR,
43 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
44 : errmsg("invalid input syntax for type %s: \"%s\"",
45 : "oid", s)));
46 :
47 45979 : errno = 0;
48 45979 : 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 45979 : if (errno && errno != ERANGE && errno != EINVAL)
56 0 : ereport(ERROR,
57 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
58 : errmsg("invalid input syntax for type %s: \"%s\"",
59 : "oid", s)));
60 :
61 45979 : if (endptr == s && *s != '\0')
62 4 : ereport(ERROR,
63 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
64 : errmsg("invalid input syntax for type %s: \"%s\"",
65 : "oid", s)));
66 :
67 45975 : if (errno == ERANGE)
68 2 : 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 45973 : if (endloc)
74 : {
75 : /* caller wants to deal with rest of string */
76 4842 : *endloc = endptr;
77 : }
78 : else
79 : {
80 : /* allow only whitespace after number */
81 82281 : while (*endptr && isspace((unsigned char) *endptr))
82 19 : endptr++;
83 41131 : if (*endptr)
84 4 : ereport(ERROR,
85 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
86 : errmsg("invalid input syntax for type %s: \"%s\"",
87 : "oid", s)));
88 : }
89 :
90 45969 : 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 45969 : return result;
114 : }
115 :
116 : Datum
117 41136 : oidin(PG_FUNCTION_ARGS)
118 : {
119 41136 : char *s = PG_GETARG_CSTRING(0);
120 : Oid result;
121 :
122 41136 : result = oidin_subr(s, NULL);
123 41126 : PG_RETURN_OID(result);
124 : }
125 :
126 : Datum
127 991 : oidout(PG_FUNCTION_ARGS)
128 : {
129 991 : Oid o = PG_GETARG_OID(0);
130 991 : char *result = (char *) palloc(12);
131 :
132 991 : snprintf(result, 12, "%u", o);
133 991 : PG_RETURN_CSTRING(result);
134 : }
135 :
136 : /*
137 : * oidrecv - converts external binary format to oid
138 : */
139 : Datum
140 6 : oidrecv(PG_FUNCTION_ARGS)
141 : {
142 6 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
143 :
144 6 : PG_RETURN_OID((Oid) pq_getmsgint(buf, sizeof(Oid)));
145 : }
146 :
147 : /*
148 : * oidsend - converts oid to binary format
149 : */
150 : Datum
151 2 : oidsend(PG_FUNCTION_ARGS)
152 : {
153 2 : Oid arg1 = PG_GETARG_OID(0);
154 : StringInfoData buf;
155 :
156 2 : pq_begintypsend(&buf);
157 2 : pq_sendint(&buf, arg1, sizeof(Oid));
158 2 : 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 *
167 3776 : buildoidvector(const Oid *oids, int n)
168 : {
169 : oidvector *result;
170 :
171 3776 : result = (oidvector *) palloc0(OidVectorSize(n));
172 :
173 3776 : if (n > 0 && oids)
174 3501 : 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 3776 : SET_VARSIZE(result, OidVectorSize(n));
181 3776 : result->ndim = 1;
182 3776 : result->dataoffset = 0; /* never any nulls */
183 3776 : result->elemtype = OIDOID;
184 3776 : result->dim1 = n;
185 3776 : result->lbound1 = 0;
186 :
187 3776 : return result;
188 : }
189 :
190 : /*
191 : * oidvectorin - converts "num num ..." to internal form
192 : */
193 : Datum
194 2823 : oidvectorin(PG_FUNCTION_ARGS)
195 : {
196 2823 : char *oidString = PG_GETARG_CSTRING(0);
197 : oidvector *result;
198 : int n;
199 :
200 2823 : result = (oidvector *) palloc0(OidVectorSize(FUNC_MAX_ARGS));
201 :
202 7665 : for (n = 0; n < FUNC_MAX_ARGS; n++)
203 : {
204 17476 : while (*oidString && isspace((unsigned char) *oidString))
205 2146 : oidString++;
206 7665 : if (*oidString == '\0')
207 2823 : break;
208 4842 : result->values[n] = oidin_subr(oidString, &oidString);
209 : }
210 5646 : while (*oidString && isspace((unsigned char) *oidString))
211 0 : oidString++;
212 2823 : if (*oidString)
213 0 : ereport(ERROR,
214 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
215 : errmsg("oidvector has too many elements")));
216 :
217 2823 : SET_VARSIZE(result, OidVectorSize(n));
218 2823 : result->ndim = 1;
219 2823 : result->dataoffset = 0; /* never any nulls */
220 2823 : result->elemtype = OIDOID;
221 2823 : result->dim1 = n;
222 2823 : result->lbound1 = 0;
223 :
224 2823 : PG_RETURN_POINTER(result);
225 : }
226 :
227 : /*
228 : * oidvectorout - converts internal form to "num num ..."
229 : */
230 : Datum
231 2 : oidvectorout(PG_FUNCTION_ARGS)
232 : {
233 2 : oidvector *oidArray = (oidvector *) PG_GETARG_POINTER(0);
234 : int num,
235 2 : nnums = oidArray->dim1;
236 : char *rp;
237 : char *result;
238 :
239 : /* assumes sign, 10 digits, ' ' */
240 2 : rp = result = (char *) palloc(nnums * 12 + 1);
241 18 : for (num = 0; num < nnums; num++)
242 : {
243 16 : if (num != 0)
244 14 : *rp++ = ' ';
245 16 : sprintf(rp, "%u", oidArray->values[num]);
246 16 : while (*++rp != '\0')
247 : ;
248 : }
249 2 : *rp = '\0';
250 2 : PG_RETURN_CSTRING(result);
251 : }
252 :
253 : /*
254 : * oidvectorrecv - converts external binary format to oidvector
255 : */
256 : Datum
257 0 : oidvectorrecv(PG_FUNCTION_ARGS)
258 : {
259 0 : 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 0 : InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3,
270 : InvalidOid, NULL, NULL);
271 :
272 0 : locfcinfo.arg[0] = PointerGetDatum(buf);
273 0 : locfcinfo.arg[1] = ObjectIdGetDatum(OIDOID);
274 0 : locfcinfo.arg[2] = Int32GetDatum(-1);
275 0 : locfcinfo.argnull[0] = false;
276 0 : locfcinfo.argnull[1] = false;
277 0 : locfcinfo.argnull[2] = false;
278 :
279 0 : result = (oidvector *) DatumGetPointer(array_recv(&locfcinfo));
280 :
281 0 : Assert(!locfcinfo.isnull);
282 :
283 : /* sanity checks: oidvector must be 1-D, 0-based, no nulls */
284 0 : if (ARR_NDIM(result) != 1 ||
285 0 : ARR_HASNULL(result) ||
286 0 : ARR_ELEMTYPE(result) != OIDOID ||
287 0 : ARR_LBOUND(result)[0] != 0)
288 0 : ereport(ERROR,
289 : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
290 : errmsg("invalid oidvector data")));
291 :
292 : /* check length for consistency with oidvectorin() */
293 0 : if (ARR_DIMS(result)[0] > FUNC_MAX_ARGS)
294 0 : ereport(ERROR,
295 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
296 : errmsg("oidvector has too many elements")));
297 :
298 0 : PG_RETURN_POINTER(result);
299 : }
300 :
301 : /*
302 : * oidvectorsend - converts oidvector to binary format
303 : */
304 : Datum
305 0 : oidvectorsend(PG_FUNCTION_ARGS)
306 : {
307 0 : return array_send(fcinfo);
308 : }
309 :
310 : /*
311 : * oidparse - get OID from IConst/FConst node
312 : */
313 : Oid
314 18 : oidparse(Node *node)
315 : {
316 18 : switch (nodeTag(node))
317 : {
318 : case T_Integer:
319 16 : 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 2 : return oidin_subr(strVal(node), NULL);
328 : default:
329 0 : 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
336 3925 : oid_cmp(const void *p1, const void *p2)
337 : {
338 3925 : Oid v1 = *((const Oid *) p1);
339 3925 : Oid v2 = *((const Oid *) p2);
340 :
341 3925 : if (v1 < v2)
342 440 : return -1;
343 3485 : if (v1 > v2)
344 2494 : return 1;
345 991 : return 0;
346 : }
347 :
348 :
349 : /*****************************************************************************
350 : * PUBLIC ROUTINES *
351 : *****************************************************************************/
352 :
353 : Datum
354 4935343 : oideq(PG_FUNCTION_ARGS)
355 : {
356 4935343 : Oid arg1 = PG_GETARG_OID(0);
357 4935343 : Oid arg2 = PG_GETARG_OID(1);
358 :
359 4935343 : PG_RETURN_BOOL(arg1 == arg2);
360 : }
361 :
362 : Datum
363 185119 : oidne(PG_FUNCTION_ARGS)
364 : {
365 185119 : Oid arg1 = PG_GETARG_OID(0);
366 185119 : Oid arg2 = PG_GETARG_OID(1);
367 :
368 185119 : PG_RETURN_BOOL(arg1 != arg2);
369 : }
370 :
371 : Datum
372 27391 : oidlt(PG_FUNCTION_ARGS)
373 : {
374 27391 : Oid arg1 = PG_GETARG_OID(0);
375 27391 : Oid arg2 = PG_GETARG_OID(1);
376 :
377 27391 : PG_RETURN_BOOL(arg1 < arg2);
378 : }
379 :
380 : Datum
381 8188 : oidle(PG_FUNCTION_ARGS)
382 : {
383 8188 : Oid arg1 = PG_GETARG_OID(0);
384 8188 : Oid arg2 = PG_GETARG_OID(1);
385 :
386 8188 : PG_RETURN_BOOL(arg1 <= arg2);
387 : }
388 :
389 : Datum
390 436 : oidge(PG_FUNCTION_ARGS)
391 : {
392 436 : Oid arg1 = PG_GETARG_OID(0);
393 436 : Oid arg2 = PG_GETARG_OID(1);
394 :
395 436 : PG_RETURN_BOOL(arg1 >= arg2);
396 : }
397 :
398 : Datum
399 549 : oidgt(PG_FUNCTION_ARGS)
400 : {
401 549 : Oid arg1 = PG_GETARG_OID(0);
402 549 : Oid arg2 = PG_GETARG_OID(1);
403 :
404 549 : PG_RETURN_BOOL(arg1 > arg2);
405 : }
406 :
407 : Datum
408 0 : oidlarger(PG_FUNCTION_ARGS)
409 : {
410 0 : Oid arg1 = PG_GETARG_OID(0);
411 0 : Oid arg2 = PG_GETARG_OID(1);
412 :
413 0 : PG_RETURN_OID((arg1 > arg2) ? arg1 : arg2);
414 : }
415 :
416 : Datum
417 41 : oidsmaller(PG_FUNCTION_ARGS)
418 : {
419 41 : Oid arg1 = PG_GETARG_OID(0);
420 41 : Oid arg2 = PG_GETARG_OID(1);
421 :
422 41 : PG_RETURN_OID((arg1 < arg2) ? arg1 : arg2);
423 : }
424 :
425 : Datum
426 3253 : oidvectoreq(PG_FUNCTION_ARGS)
427 : {
428 3253 : int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
429 :
430 3253 : PG_RETURN_BOOL(cmp == 0);
431 : }
432 :
433 : Datum
434 0 : oidvectorne(PG_FUNCTION_ARGS)
435 : {
436 0 : int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
437 :
438 0 : PG_RETURN_BOOL(cmp != 0);
439 : }
440 :
441 : Datum
442 614 : oidvectorlt(PG_FUNCTION_ARGS)
443 : {
444 614 : int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
445 :
446 614 : PG_RETURN_BOOL(cmp < 0);
447 : }
448 :
449 : Datum
450 212 : oidvectorle(PG_FUNCTION_ARGS)
451 : {
452 212 : int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
453 :
454 212 : PG_RETURN_BOOL(cmp <= 0);
455 : }
456 :
457 : Datum
458 0 : oidvectorge(PG_FUNCTION_ARGS)
459 : {
460 0 : int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
461 :
462 0 : PG_RETURN_BOOL(cmp >= 0);
463 : }
464 :
465 : Datum
466 0 : oidvectorgt(PG_FUNCTION_ARGS)
467 : {
468 0 : int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
469 :
470 0 : PG_RETURN_BOOL(cmp > 0);
471 : }
|