Header And Logo

PostgreSQL
| The world's most advanced open source database.

oid.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * oid.c
00004  *    Functions for the built-in type Oid ... also oidvector.
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/utils/adt/oid.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include <ctype.h>
00018 #include <limits.h>
00019 
00020 #include "catalog/pg_type.h"
00021 #include "libpq/pqformat.h"
00022 #include "utils/array.h"
00023 #include "utils/builtins.h"
00024 
00025 
00026 #define OidVectorSize(n)    (offsetof(oidvector, values) + (n) * sizeof(Oid))
00027 
00028 
00029 /*****************************************************************************
00030  *   USER I/O ROUTINES                                                       *
00031  *****************************************************************************/
00032 
00033 static Oid
00034 oidin_subr(const char *s, char **endloc)
00035 {
00036     unsigned long cvt;
00037     char       *endptr;
00038     Oid         result;
00039 
00040     if (*s == '\0')
00041         ereport(ERROR,
00042                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00043                  errmsg("invalid input syntax for type oid: \"%s\"",
00044                         s)));
00045 
00046     errno = 0;
00047     cvt = strtoul(s, &endptr, 10);
00048 
00049     /*
00050      * strtoul() normally only sets ERANGE.  On some systems it also may set
00051      * EINVAL, which simply means it couldn't parse the input string. This is
00052      * handled by the second "if" consistent across platforms.
00053      */
00054     if (errno && errno != ERANGE && errno != EINVAL)
00055         ereport(ERROR,
00056                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00057                  errmsg("invalid input syntax for type oid: \"%s\"",
00058                         s)));
00059 
00060     if (endptr == s && *s != '\0')
00061         ereport(ERROR,
00062                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00063                  errmsg("invalid input syntax for type oid: \"%s\"",
00064                         s)));
00065 
00066     if (errno == ERANGE)
00067         ereport(ERROR,
00068                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
00069                  errmsg("value \"%s\" is out of range for type oid", s)));
00070 
00071     if (endloc)
00072     {
00073         /* caller wants to deal with rest of string */
00074         *endloc = endptr;
00075     }
00076     else
00077     {
00078         /* allow only whitespace after number */
00079         while (*endptr && isspace((unsigned char) *endptr))
00080             endptr++;
00081         if (*endptr)
00082             ereport(ERROR,
00083                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00084                      errmsg("invalid input syntax for type oid: \"%s\"",
00085                             s)));
00086     }
00087 
00088     result = (Oid) cvt;
00089 
00090     /*
00091      * Cope with possibility that unsigned long is wider than Oid, in which
00092      * case strtoul will not raise an error for some values that are out of
00093      * the range of Oid.
00094      *
00095      * For backwards compatibility, we want to accept inputs that are given
00096      * with a minus sign, so allow the input value if it matches after either
00097      * signed or unsigned extension to long.
00098      *
00099      * To ensure consistent results on 32-bit and 64-bit platforms, make sure
00100      * the error message is the same as if strtoul() had returned ERANGE.
00101      */
00102 #if OID_MAX != ULONG_MAX
00103     if (cvt != (unsigned long) result &&
00104         cvt != (unsigned long) ((int) result))
00105         ereport(ERROR,
00106                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
00107                  errmsg("value \"%s\" is out of range for type oid", s)));
00108 #endif
00109 
00110     return result;
00111 }
00112 
00113 Datum
00114 oidin(PG_FUNCTION_ARGS)
00115 {
00116     char       *s = PG_GETARG_CSTRING(0);
00117     Oid         result;
00118 
00119     result = oidin_subr(s, NULL);
00120     PG_RETURN_OID(result);
00121 }
00122 
00123 Datum
00124 oidout(PG_FUNCTION_ARGS)
00125 {
00126     Oid         o = PG_GETARG_OID(0);
00127     char       *result = (char *) palloc(12);
00128 
00129     snprintf(result, 12, "%u", o);
00130     PG_RETURN_CSTRING(result);
00131 }
00132 
00133 /*
00134  *      oidrecv         - converts external binary format to oid
00135  */
00136 Datum
00137 oidrecv(PG_FUNCTION_ARGS)
00138 {
00139     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00140 
00141     PG_RETURN_OID((Oid) pq_getmsgint(buf, sizeof(Oid)));
00142 }
00143 
00144 /*
00145  *      oidsend         - converts oid to binary format
00146  */
00147 Datum
00148 oidsend(PG_FUNCTION_ARGS)
00149 {
00150     Oid         arg1 = PG_GETARG_OID(0);
00151     StringInfoData buf;
00152 
00153     pq_begintypsend(&buf);
00154     pq_sendint(&buf, arg1, sizeof(Oid));
00155     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00156 }
00157 
00158 /*
00159  * construct oidvector given a raw array of Oids
00160  *
00161  * If oids is NULL then caller must fill values[] afterward
00162  */
00163 oidvector *
00164 buildoidvector(const Oid *oids, int n)
00165 {
00166     oidvector  *result;
00167 
00168     result = (oidvector *) palloc0(OidVectorSize(n));
00169 
00170     if (n > 0 && oids)
00171         memcpy(result->values, oids, n * sizeof(Oid));
00172 
00173     /*
00174      * Attach standard array header.  For historical reasons, we set the index
00175      * lower bound to 0 not 1.
00176      */
00177     SET_VARSIZE(result, OidVectorSize(n));
00178     result->ndim = 1;
00179     result->dataoffset = 0;     /* never any nulls */
00180     result->elemtype = OIDOID;
00181     result->dim1 = n;
00182     result->lbound1 = 0;
00183 
00184     return result;
00185 }
00186 
00187 /*
00188  *      oidvectorin         - converts "num num ..." to internal form
00189  */
00190 Datum
00191 oidvectorin(PG_FUNCTION_ARGS)
00192 {
00193     char       *oidString = PG_GETARG_CSTRING(0);
00194     oidvector  *result;
00195     int         n;
00196 
00197     result = (oidvector *) palloc0(OidVectorSize(FUNC_MAX_ARGS));
00198 
00199     for (n = 0; n < FUNC_MAX_ARGS; n++)
00200     {
00201         while (*oidString && isspace((unsigned char) *oidString))
00202             oidString++;
00203         if (*oidString == '\0')
00204             break;
00205         result->values[n] = oidin_subr(oidString, &oidString);
00206     }
00207     while (*oidString && isspace((unsigned char) *oidString))
00208         oidString++;
00209     if (*oidString)
00210         ereport(ERROR,
00211                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00212                  errmsg("oidvector has too many elements")));
00213 
00214     SET_VARSIZE(result, OidVectorSize(n));
00215     result->ndim = 1;
00216     result->dataoffset = 0;     /* never any nulls */
00217     result->elemtype = OIDOID;
00218     result->dim1 = n;
00219     result->lbound1 = 0;
00220 
00221     PG_RETURN_POINTER(result);
00222 }
00223 
00224 /*
00225  *      oidvectorout - converts internal form to "num num ..."
00226  */
00227 Datum
00228 oidvectorout(PG_FUNCTION_ARGS)
00229 {
00230     oidvector  *oidArray = (oidvector *) PG_GETARG_POINTER(0);
00231     int         num,
00232                 nnums = oidArray->dim1;
00233     char       *rp;
00234     char       *result;
00235 
00236     /* assumes sign, 10 digits, ' ' */
00237     rp = result = (char *) palloc(nnums * 12 + 1);
00238     for (num = 0; num < nnums; num++)
00239     {
00240         if (num != 0)
00241             *rp++ = ' ';
00242         sprintf(rp, "%u", oidArray->values[num]);
00243         while (*++rp != '\0')
00244             ;
00245     }
00246     *rp = '\0';
00247     PG_RETURN_CSTRING(result);
00248 }
00249 
00250 /*
00251  *      oidvectorrecv           - converts external binary format to oidvector
00252  */
00253 Datum
00254 oidvectorrecv(PG_FUNCTION_ARGS)
00255 {
00256     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00257     FunctionCallInfoData locfcinfo;
00258     oidvector  *result;
00259 
00260     /*
00261      * Normally one would call array_recv() using DirectFunctionCall3, but
00262      * that does not work since array_recv wants to cache some data using
00263      * fcinfo->flinfo->fn_extra.  So we need to pass it our own flinfo
00264      * parameter.
00265      */
00266     InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3,
00267                              InvalidOid, NULL, NULL);
00268 
00269     locfcinfo.arg[0] = PointerGetDatum(buf);
00270     locfcinfo.arg[1] = ObjectIdGetDatum(OIDOID);
00271     locfcinfo.arg[2] = Int32GetDatum(-1);
00272     locfcinfo.argnull[0] = false;
00273     locfcinfo.argnull[1] = false;
00274     locfcinfo.argnull[2] = false;
00275 
00276     result = (oidvector *) DatumGetPointer(array_recv(&locfcinfo));
00277 
00278     Assert(!locfcinfo.isnull);
00279 
00280     /* sanity checks: oidvector must be 1-D, 0-based, no nulls */
00281     if (ARR_NDIM(result) != 1 ||
00282         ARR_HASNULL(result) ||
00283         ARR_ELEMTYPE(result) != OIDOID ||
00284         ARR_LBOUND(result)[0] != 0)
00285         ereport(ERROR,
00286                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00287                  errmsg("invalid oidvector data")));
00288 
00289     /* check length for consistency with oidvectorin() */
00290     if (ARR_DIMS(result)[0] > FUNC_MAX_ARGS)
00291         ereport(ERROR,
00292                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00293                  errmsg("oidvector has too many elements")));
00294 
00295     PG_RETURN_POINTER(result);
00296 }
00297 
00298 /*
00299  *      oidvectorsend           - converts oidvector to binary format
00300  */
00301 Datum
00302 oidvectorsend(PG_FUNCTION_ARGS)
00303 {
00304     return array_send(fcinfo);
00305 }
00306 
00307 /*
00308  *      oidparse                - get OID from IConst/FConst node
00309  */
00310 Oid
00311 oidparse(Node *node)
00312 {
00313     switch (nodeTag(node))
00314     {
00315         case T_Integer:
00316             return intVal(node);
00317         case T_Float:
00318 
00319             /*
00320              * Values too large for int4 will be represented as Float
00321              * constants by the lexer.  Accept these if they are valid OID
00322              * strings.
00323              */
00324             return oidin_subr(strVal(node), NULL);
00325         default:
00326             elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
00327     }
00328     return InvalidOid;          /* keep compiler quiet */
00329 }
00330 
00331 
00332 /*****************************************************************************
00333  *   PUBLIC ROUTINES                                                         *
00334  *****************************************************************************/
00335 
00336 Datum
00337 oideq(PG_FUNCTION_ARGS)
00338 {
00339     Oid         arg1 = PG_GETARG_OID(0);
00340     Oid         arg2 = PG_GETARG_OID(1);
00341 
00342     PG_RETURN_BOOL(arg1 == arg2);
00343 }
00344 
00345 Datum
00346 oidne(PG_FUNCTION_ARGS)
00347 {
00348     Oid         arg1 = PG_GETARG_OID(0);
00349     Oid         arg2 = PG_GETARG_OID(1);
00350 
00351     PG_RETURN_BOOL(arg1 != arg2);
00352 }
00353 
00354 Datum
00355 oidlt(PG_FUNCTION_ARGS)
00356 {
00357     Oid         arg1 = PG_GETARG_OID(0);
00358     Oid         arg2 = PG_GETARG_OID(1);
00359 
00360     PG_RETURN_BOOL(arg1 < arg2);
00361 }
00362 
00363 Datum
00364 oidle(PG_FUNCTION_ARGS)
00365 {
00366     Oid         arg1 = PG_GETARG_OID(0);
00367     Oid         arg2 = PG_GETARG_OID(1);
00368 
00369     PG_RETURN_BOOL(arg1 <= arg2);
00370 }
00371 
00372 Datum
00373 oidge(PG_FUNCTION_ARGS)
00374 {
00375     Oid         arg1 = PG_GETARG_OID(0);
00376     Oid         arg2 = PG_GETARG_OID(1);
00377 
00378     PG_RETURN_BOOL(arg1 >= arg2);
00379 }
00380 
00381 Datum
00382 oidgt(PG_FUNCTION_ARGS)
00383 {
00384     Oid         arg1 = PG_GETARG_OID(0);
00385     Oid         arg2 = PG_GETARG_OID(1);
00386 
00387     PG_RETURN_BOOL(arg1 > arg2);
00388 }
00389 
00390 Datum
00391 oidlarger(PG_FUNCTION_ARGS)
00392 {
00393     Oid         arg1 = PG_GETARG_OID(0);
00394     Oid         arg2 = PG_GETARG_OID(1);
00395 
00396     PG_RETURN_OID((arg1 > arg2) ? arg1 : arg2);
00397 }
00398 
00399 Datum
00400 oidsmaller(PG_FUNCTION_ARGS)
00401 {
00402     Oid         arg1 = PG_GETARG_OID(0);
00403     Oid         arg2 = PG_GETARG_OID(1);
00404 
00405     PG_RETURN_OID((arg1 < arg2) ? arg1 : arg2);
00406 }
00407 
00408 Datum
00409 oidvectoreq(PG_FUNCTION_ARGS)
00410 {
00411     int32       cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
00412 
00413     PG_RETURN_BOOL(cmp == 0);
00414 }
00415 
00416 Datum
00417 oidvectorne(PG_FUNCTION_ARGS)
00418 {
00419     int32       cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
00420 
00421     PG_RETURN_BOOL(cmp != 0);
00422 }
00423 
00424 Datum
00425 oidvectorlt(PG_FUNCTION_ARGS)
00426 {
00427     int32       cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
00428 
00429     PG_RETURN_BOOL(cmp < 0);
00430 }
00431 
00432 Datum
00433 oidvectorle(PG_FUNCTION_ARGS)
00434 {
00435     int32       cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
00436 
00437     PG_RETURN_BOOL(cmp <= 0);
00438 }
00439 
00440 Datum
00441 oidvectorge(PG_FUNCTION_ARGS)
00442 {
00443     int32       cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
00444 
00445     PG_RETURN_BOOL(cmp >= 0);
00446 }
00447 
00448 Datum
00449 oidvectorgt(PG_FUNCTION_ARGS)
00450 {
00451     int32       cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
00452 
00453     PG_RETURN_BOOL(cmp > 0);
00454 }