|
From: Ian B. <ia...@co...> - 2003-06-03 07:35:31
|
On Thu, 2003-05-29 at 11:27, Magnus Lyck=E5 wrote:
> At 22:31 2003-05-28 -0500, Ian Bicking wrote:
> >I think __sqltype__ seems a little awkward. You have to agree on the
> >types (and type names) that the backend accepts, and that gets into a
> >whole discussion that seems rather endless ;)
>=20
> Most of the time, you only need to tell the DB-API whether it might
> need to escape/quote the data or not. In other words, is this a number
> or a string? If the class above the DB-API is to handle escape/quote,
> it would need to supply "that's" from __sqlrepr__ when it works with i.=
e.
> mxODBC or cx_Oracle, and "'that''s'" when it works with MySQLdb or a
> PostgreSQL driver. If it can just tell the DB-API whether it's a string
> or a number, it can always supply "that's", or "5" or "314159E-5", and
> the driver can handle it just like it does for ints, floats and strings
> etc today. This covers the overwhelming majority of used literals.
>=20
> Actually, it's not really the data type in the database that matters,
> but what kind of *literal* we are providing. Maybe the method should
> be called __sqlliteral__ or __sql_literal__ rather than __sqltype__
> (and the other method __sql_repr__ if we use __sql_literal__)?
>=20
> The SQL/92 standard supports four kinds of literals:
>=20
> character string ('that''s')
> bit string (B'01010101' or X'f5a1')
> exact numeric (4 or +365.2425)
> approximate numeric (4E3 or -.15E-15)
The problem is that those are the literals that don't matter -- since
SQL92 defines them, most all SQL databases handle them just fine. It's
other literals -- like dates -- that are likely to have problems. =20
> In addition to returning any of these, I think __sql_literal__ should
> be able to return 'raw' to inticate that the driver should just pass
> the value in as it is. It's then up to the application programmer to
> provide the right data. If she has to support many tricky backends and
> don't have very high performance requirements, she could put logic into
> the __sql_repr__ method that will check what backend it is and act base=
d
> on that.
>=20
> Obviously, MS Access is in clear violation with the SQL spec here, as i=
n
> a number of other cases :( so *this* would not solve the #1900-01-01#
> problem.
>=20
> I'd like to suggest the following: Each db driver has to supply a
> CONSTANT for each kind of literal it supports. At least, it should
> support the following constants:
> .literal.CHAR Action for such values is typically
> "'%s'" % x.replace("'", "''")
> .literal.BBIT (or BITS?) Action is typically "B'%s'" % x
> .literal.XBIT (or HEX?) Action is typically "X'%s'" % x
> .literal.EXACT Action is typically to use as is
> .literal.APPROX Action is typically to use as is
> .literal.RAW Action is always to us as is.
>=20
> It could optionally support other literal types such as
> .literal.DATE which could provide custom handling of date
> strings for some peculiar backend,
> .literal.MONEY if this is ever needed...
> .literal.BIN to let people pass in binary strings and not need to
> convert them to B'0101' or X'ffff'. This could then
> pass the binary data as it is if the backend supports
> that, or do "X'%s'" % x.encode('hex') as a convenience
> for the application programmer. I don't know if there i=
s
> a desire to be able to provide a stream instead of a st=
ring
> for binary data? How do people handle BLOBs today? But
> maybe I'm confused here. Backends might not handle bit
> fields and BLOBs etc in the same way.
It's only these non-standard ones that seem useful (besides RAW). Which
is why this seems problematic.
[snip]
> Something like this...
>=20
> # mydate.py
>=20
> def init_module(dbdriver):
> global sql_literal
> try: sql_literal =3D dbdriver.literal.DATE
> except: sql_literal =3D dbdriver.literal.CHAR
That init_module is a killer -- it's the same problem you get with
database exceptions right now, where you can't be database agnostic in
isolated parts of code. The optional stuff will be a pain too -- maybe
if there's a common DBI module it'd be more workable.
[snip quote function example]
> What if dbdriver is written in c? (I guess you can always have
> a thin wrapper.)
Mmm... no assigning the function in that case, I suppose. Well, you
could instead have all the drivers use a setQuoter() function, which
could just reassign quote(), or do something else if that's not
possible. The concept is really just about overriding a quoting
function in some manner.
> >The quote function is potentially database specific. After thinking
> >about it, this function should have the chance to get at the raw value
> >before __sqlrepr__ is called.
>=20
> I don't see why. If you want class X to behave differently in some
> situation, subclass it and put the different behaviour in __sqlrepr__
> of the subclass. These functions seem redundant to me. One is more
> OO, the other more procedural.
If you want class X to act differently for two different databases, then
you either need something more than __sqlrepr__ (like __sqlrepr_pg__,
__sqlrepr_oracle__), or maybe __sqlrepr__ gets called with the driver
name, or you implement your own thing in the quote function.
For instance, lets say datetime defines its own __sqlrepr__ that outputs
a string with an ISO date as its contents. But now you, not the author
of datetime, finds out Access doesn't like that, so you override quote
and do a special check to fix up this specific case.
If you want __sqlrepr_oracle__, you could also implement that in the
quote function. It's a general hook, and one which is tied to the
database, not the objects being quoted.
> >Anyway, people talked serious about including Gadfly in the standard
> >distribution, so there's interest in supporting database stuff. The
> >only weird part about the module is that it would be useless on its ow=
n.
>=20
> If Gadfly was included and used this module, it would be better. I
> would rather see sqlite in the standard library though. I don't see
> why we can have bsddb and not sqlite. SQLite is much more like a typica=
l
> SQL database than Gadfly is.
Yes, I like SQLite more as well, but it's not so much Gadfly in
particular -- rather, there are people interested in putting database
stuff into the main Python distribution. So it doesn't seem impossible
that a common DBI module could also be included.
Ian
|