|
From: Ian B. <ia...@co...> - 2003-05-26 20:08:24
|
On Mon, 2003-05-26 at 05:15, Magnus Lyck=E5 wrote:
> But Date is really just an example... The thing is that if I use
> something like "INSERT INTO X (a,b,c) VALUES (?,?,?)" or
> "SELECT * FROM X WHERE A < ?", and pass in the literals in a params
> tuple, the problem goes away, regadless of what kind of data this
> might be. (Of course, I still have to provide data in the right
> format, but I don't have to solve quoting or escaping.)
>=20
> After all, the point with the second parameter to cursor.execute()
> is there to promote this kind of coding. As far as I understand, neithe=
r
> MySQL, PostGreSQL or SQLite supports Dynamic SQL or the SQL CLI properl=
y,
> so there %s is used, and the parameters are passed into the SQL string =
in
> the interface, but for interfaces to databases with proper Dynamic SQL
> support, both the SQL string with question marks and the parameter tupl=
e
> are just passed to a lower layer, and handled by the database vendor's
> driver. I think this is the right way to do it.
>=20
> There are certinaly lots of other problems in various SQL dialects that
> we can't solve with this fix. Contatenation operators and join syntax e=
tc
> makes it difficult to always get SQL to work cross platform, but for
> handling of quoting and escaping of literals used in SQL queries, there
> *is* a right way to do it, so trying to solve it again in the Python la=
yer
> seems...well, non-optimal.
I don't think the DB-API is not complete enough to be considered "right"
for this. AFAIK, there is no standard way to indicate how non-standard
types should be quoted, and I cannot see what the *actual* SQL sent is.=20
By giving up control to the underlying adapter, I fear that other
compatibility issues will be harder to fix later.
Additionally, the underlying vendor's driver *cannot* be the most
authoritative participant. That driver is written in C, with C types --
the Python type system is much richer. At the Python level we can offer
a much more complete interface (with things like SQLBuilder.func.NOW()).
Parameter passing will solve this date quoting problem, but at some
later date I expect a problem that parameter passing *won't* solve, and
in fact will be made much more difficult to solve because of parameter
passing.
> As far as I understand, it's only the code for INSERT and UPDATE that
> I *need* to fix. For INSERT it seems that the easiest way is to fix it
> in _queryInsertID and not even call _insertSQL. Just call execute with
> the values as a separate parameter, and pass in ",".join(['?']*len(valu=
es))
> in the second parenthesis.
>=20
> For updates I need to override _SO_update so that I just insert
> "SET A =3D ?, B =3D ?" and pass the parameters to self.query. This in
> turn means that I need to add an optional param parameter to query
> and _query, but it seems like a reasonable thing to do.
>=20
> Then I still don't have perfect support for selects, but I can do
> without that for now I think.
Yes, that implementation would work. You should be able to do that all
in a subclass, without changing any current classes, though I imagine
you'll have to override most of DBAPIConnection. =20
> >Well, for select in particular, maybe params would be fine. However,
> >SQLObject has maintained database independence fairly well, and the
> >annoying paramstyle issue would make code that uses params less
> >portable.
>=20
> So far, you ony seem to support backends that don't support parameter
> passing though.
Perhaps -- I don't even know, because I'm not using parameters. That
ignorance makes me happy ;) I don't see a big advantage to using
parameters besides quoting -- AFAIK, prepared statements and whatnot
only offer advantages in a certain context, a context which will not
exist in SQLObject. =20
> > Though I'm certainly okay with:
> >
> > Person.select('birthdate < %s', params=3D(Date(1999, 4, 12),))
> >
> >Where any non-param %'s have to be quoted (like %%), then the database
> >connection changes %s to ? or whatever the paramstyle is. Should be
> >easy enough to implement.
>=20
> As you might have seen in the db-sig mailing list, I recently wrote
> code that goes the other way: ? to %s. This has the advantage that
> you can write your SQL queries just the way a proper SQL book describes
> them, i.e. you can write "SELECT * FROM X WHERE A =3D ? AND B LIKE 'X%'=
"
> without having to think about doubling % or using any other non-SQL
> construct in the SQL code. It's also fairly simple to convert qmark
> style SQL to named, numbered or even Sybase @-style quoting if that
> is needed.
Can you change the ?'s reasonably efficiently, while protecting against
literals that contain ?'s ?
> >I don't use params, and don't plan to, for other SQL construction.
> >Mostly it's because I like having complete control over the SQL, which=
I
> >do when I do the string substitution myself.
>=20
> I think you are doing more work than you have to that way. As
> I said, for MySQL, PostgreSQL and SQLite it's no big difference,
> since they do that in a simple way in the interface code anyway,
> but for most commercial it might well be. At least for interfaces
> like ADO and ODBC where you use one interface but can have any of
> many backends behind that interface.
>=20
> This also means that you place a burden on the application developer
> to solve this right for filtering in the select statement.
>=20
> I do realize that changing this now is quite some work though...
It's not so much the work of changing this -- it wouldn't be all that
difficult, as I've tried to keep SQL generation isolated -- but I'm not
convinced this is the right thing to do.
Ian
|