]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/oid.c
Add support for EUI-64 MAC addresses as macaddr8
[postgresql] / src / backend / utils / adt / oid.c
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 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
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
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
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
151 oidsend(PG_FUNCTION_ARGS)
152 {
153         Oid                     arg1 = PG_GETARG_OID(0);
154         StringInfoData buf;
155
156         pq_begintypsend(&buf);
157         pq_sendint(&buf, arg1, sizeof(Oid));
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
426 oidvectoreq(PG_FUNCTION_ARGS)
427 {
428         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
429
430         PG_RETURN_BOOL(cmp == 0);
431 }
432
433 Datum
434 oidvectorne(PG_FUNCTION_ARGS)
435 {
436         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
437
438         PG_RETURN_BOOL(cmp != 0);
439 }
440
441 Datum
442 oidvectorlt(PG_FUNCTION_ARGS)
443 {
444         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
445
446         PG_RETURN_BOOL(cmp < 0);
447 }
448
449 Datum
450 oidvectorle(PG_FUNCTION_ARGS)
451 {
452         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
453
454         PG_RETURN_BOOL(cmp <= 0);
455 }
456
457 Datum
458 oidvectorge(PG_FUNCTION_ARGS)
459 {
460         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
461
462         PG_RETURN_BOOL(cmp >= 0);
463 }
464
465 Datum
466 oidvectorgt(PG_FUNCTION_ARGS)
467 {
468         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
469
470         PG_RETURN_BOOL(cmp > 0);
471 }