Re: libpq type system 0.9a - Mailing list pgsql-patches
From | Andrew Chernow |
---|---|
Subject | Re: libpq type system 0.9a |
Date | |
Msg-id | 47CF3709.7030901@esilo.com Whole thread Raw |
In response to | Re: libpq type system 0.9a ("Merlin Moncure" <mmoncure@gmail.com>) |
List | pgsql-patches |
Merlin Moncure wrote: > On Wed, Mar 5, 2008 at 5:47 PM, Florian G. Pflug <fgp@phlo.org> wrote: >> Merlin Moncure wrote: >> > Yesterday, we notified -hackers of the latest version of the libpq >> > type system. Just to be sure the right people are getting notified, >> > we are posting the latest patch here as well. Would love to get some >> > feedback on this. >> Sorry if this has been discussed before, but why is it necessary >> to specify the type when calling PQgetf on a result? It seems that this >> formatting string *always* has to match the type list of your select >> statement, no? > > yes...it always has to match. the format string requirements could in > theory be relaxed (for 'get') but this would break symmetry with 'put' > and you would lose a sanity check...getf like scanf writes directly > into application memory so the double-specifying (directly in the > format string and indirectly in the query) isn't necessarily a bad > thing. imagine if your application was 'select * from table' and one > of the field types changed...disaster. > > merlin > > A few other reasons.... >>why is it necessary to specify the type when calling PQgetf on a result Unlike PQgetvalue, all values returned by PQgetf are either native C types or structures ... not C strings. When you call getf you must tell it what types to read out of the result object. Like scanf, they must be the correctly sized data types. PGdate date; int i4; PQgetf(result, tup_num, "%date %int4", 0, &date, 1, &i4); Specifying anything other than a %date or %int4 in the above example is a programming error. You would be asking to fetch a value of the wrong type. Without the formatting string, libpq would have to va_arg(ASSUME_T) your value. // no specifier int i; PQgetf(result, tup, field, &i); In the above, libpq would have to use PQftype to determine what the native C type is of your variable argument. If PQftype returned INT8OID, you begin to clobber your application's memory space ... va_arg(ap, long long) on a 32-bit value. This problem is solved by telling libpq what data type you want from a field. Also, the libpq type system enforces strict type checking when performing getf calls. This protects from mis-matches "programming errors" on types: For example: -- create table t (a int8); PQresult *result = PQexec(conn, "SELECT a FROM t"); char *val = PQgetvalue(result, ...); int a = atoi(val); // assumed its an int4 In the above example, the libpq user thinks the 'a' column of the 't' table is an int4 when in fact its an int8. The above may work most of the time but will eventually truncate the value and nip you in the butt. With PQgetf, you would get an error saying the server returned an int8 and you are asking for an int4. Thus, the programming bug would be squashed immediately. Also, user-defined types are not known to libpq so PQftype would not really work. They could if the libpq type system referenced data types by OID, but this is not portable to other servers. It is more portable to use the type name. For example, a company with 15 postgresql servers that use the same collection of company-specific user-defined data types. The type names would be the same across the 15 servers but there is no guarentee the OIDs would be. Composites and arrays caused a few issues as well. We also tried to provide as much protection as possible ... in the spirit of the backend. -- Andrew Chernow eSilo, LLC every bit counts http://www.esilo.com/
pgsql-patches by date: