]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/oid.c
Update copyright for 2009.
[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-2009, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/utils/adt/oid.c,v 1.74 2009/01/01 17:23:49 momjian Exp $
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
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
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
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
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
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 *
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
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
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
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, NULL, NULL);
267
268         locfcinfo.arg[0] = PointerGetDatum(buf);
269         locfcinfo.arg[1] = ObjectIdGetDatum(OIDOID);
270         locfcinfo.arg[2] = Int32GetDatum(-1);
271         locfcinfo.argnull[0] = false;
272         locfcinfo.argnull[1] = false;
273         locfcinfo.argnull[2] = false;
274
275         result = (oidvector *) DatumGetPointer(array_recv(&locfcinfo));
276
277         Assert(!locfcinfo.isnull);
278
279         /* sanity checks: oidvector must be 1-D, no nulls */
280         if (ARR_NDIM(result) != 1 ||
281                 ARR_HASNULL(result) ||
282                 ARR_ELEMTYPE(result) != OIDOID)
283                 ereport(ERROR,
284                                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
285                                  errmsg("invalid oidvector data")));
286         PG_RETURN_POINTER(result);
287 }
288
289 /*
290  *              oidvectorsend                   - converts oidvector to binary format
291  */
292 Datum
293 oidvectorsend(PG_FUNCTION_ARGS)
294 {
295         return array_send(fcinfo);
296 }
297
298
299 /*****************************************************************************
300  *       PUBLIC ROUTINES                                                                                                                 *
301  *****************************************************************************/
302
303 Datum
304 oideq(PG_FUNCTION_ARGS)
305 {
306         Oid                     arg1 = PG_GETARG_OID(0);
307         Oid                     arg2 = PG_GETARG_OID(1);
308
309         PG_RETURN_BOOL(arg1 == arg2);
310 }
311
312 Datum
313 oidne(PG_FUNCTION_ARGS)
314 {
315         Oid                     arg1 = PG_GETARG_OID(0);
316         Oid                     arg2 = PG_GETARG_OID(1);
317
318         PG_RETURN_BOOL(arg1 != arg2);
319 }
320
321 Datum
322 oidlt(PG_FUNCTION_ARGS)
323 {
324         Oid                     arg1 = PG_GETARG_OID(0);
325         Oid                     arg2 = PG_GETARG_OID(1);
326
327         PG_RETURN_BOOL(arg1 < arg2);
328 }
329
330 Datum
331 oidle(PG_FUNCTION_ARGS)
332 {
333         Oid                     arg1 = PG_GETARG_OID(0);
334         Oid                     arg2 = PG_GETARG_OID(1);
335
336         PG_RETURN_BOOL(arg1 <= arg2);
337 }
338
339 Datum
340 oidge(PG_FUNCTION_ARGS)
341 {
342         Oid                     arg1 = PG_GETARG_OID(0);
343         Oid                     arg2 = PG_GETARG_OID(1);
344
345         PG_RETURN_BOOL(arg1 >= arg2);
346 }
347
348 Datum
349 oidgt(PG_FUNCTION_ARGS)
350 {
351         Oid                     arg1 = PG_GETARG_OID(0);
352         Oid                     arg2 = PG_GETARG_OID(1);
353
354         PG_RETURN_BOOL(arg1 > arg2);
355 }
356
357 Datum
358 oidlarger(PG_FUNCTION_ARGS)
359 {
360         Oid                     arg1 = PG_GETARG_OID(0);
361         Oid                     arg2 = PG_GETARG_OID(1);
362
363         PG_RETURN_OID((arg1 > arg2) ? arg1 : arg2);
364 }
365
366 Datum
367 oidsmaller(PG_FUNCTION_ARGS)
368 {
369         Oid                     arg1 = PG_GETARG_OID(0);
370         Oid                     arg2 = PG_GETARG_OID(1);
371
372         PG_RETURN_OID((arg1 < arg2) ? arg1 : arg2);
373 }
374
375 Datum
376 oidvectoreq(PG_FUNCTION_ARGS)
377 {
378         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
379
380         PG_RETURN_BOOL(cmp == 0);
381 }
382
383 Datum
384 oidvectorne(PG_FUNCTION_ARGS)
385 {
386         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
387
388         PG_RETURN_BOOL(cmp != 0);
389 }
390
391 Datum
392 oidvectorlt(PG_FUNCTION_ARGS)
393 {
394         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
395
396         PG_RETURN_BOOL(cmp < 0);
397 }
398
399 Datum
400 oidvectorle(PG_FUNCTION_ARGS)
401 {
402         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
403
404         PG_RETURN_BOOL(cmp <= 0);
405 }
406
407 Datum
408 oidvectorge(PG_FUNCTION_ARGS)
409 {
410         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
411
412         PG_RETURN_BOOL(cmp >= 0);
413 }
414
415 Datum
416 oidvectorgt(PG_FUNCTION_ARGS)
417 {
418         int32           cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
419
420         PG_RETURN_BOOL(cmp > 0);
421 }