[DB-SIG] Towards a single parameter style
Kevin Jacobs
jacobs@penguin.theopalgroup.com
Wed, 19 Feb 2003 06:59:28 -0500 (EST)
On Wed, 19 Feb 2003, Stuart Bishop wrote:
> On Tuesday, February 18, 2003, at 11:01 PM, Kevin Jacobs wrote:
>
> > connection = connect(...)
> > cursor = connection.cursor()
> > command = cursor.prepare(sql)
> > cursor.execute(command, (arg1, arg2, arg3))
>
> As this example stands, I don't see what this syntax gains us except an
> extra needless line.
> connection = connect(...)
> command = connection.cursor()
> command.execute(sql, (arg1, arg2, arg3))
This requires storing a cursor for each prepared command, and still does not
address the main point of prepared statements -- they only make sense if you
call them many times! DB-API 2.0 provides a simplistic version of this
concept -- executemany -- though it requires that all of the arguments are
available at once, and does not allow any other statements interleaved
between them.
Now that I have thought about it more, the above
would read better as:
connection = connect(...)
command = connection.prepare(sql)
cursor = connection.cursor()
cursor.execute(command, (arg1, arg2, arg3))
> It also makes things a lot more complex:
> - We now have to make sure that both our cursor *and* our
> prepared statements are being used in a thread safe manner.
I don't see this as being a huge implementation hurdle. Can you clarify
where you see likely pittfalls? The way I look at it, prepared statements
will have to be used in the context of a cursor, so proper thread safe use
of a cursor will also, by default, protect statements.
> - Can my command be used with cursor that didn't create it? Or a cursor
> created from a different connection?
I would restrict it to a given connection, and cursors derived from it.
> One of your previous examples gave a better justification, where you had a
> 'print statement.description' in between the prepare and execute commands.
> You then gave a reason why this isn't a good idea because 'this syntax
> _requires_ that the backend support prepared statements'.
I still think it is a good idea. Any backend that does not support prepared
statements can partially emulate a prepared query by creating a wrapper
around a cursor object. Or maybe we should simply raise NotImplementedError
when prepare() is called for those backends.
> The only use I can see for a PreparedStatement object would be to:
> Query it for its 'description'
> Execute it
>
> So would a better alternative be to simply have a new (optional)
> cursor method?:
> cursor.fetchDescription(sql) -- returns the cursor.description
> sequence for the given statement, without actually executing
> it. This method will not be implemented if the backend cannot
> retrieve this information without actually executing the statement,
> or it may be defined and raise NotImplementedError in this case.
That wouldn't be a bad idea either. Currently, we have an SQL rewriting
process that adds a LIMIT 0 (or whatever the appropriate backend syntax) to
an existing query to do exactly this. Having native support for this
operation would be a step in the right direction.
> > So instead of the cursor keeping a reference to command, the command is
> > returned to the user and passed back in as the first argument to
> > execute.
>
> Icky. If you go this way, the command should have a reference to the
> cursor IMHO. At which point it becomes apparent that only one object is
> actually desired :-)
Again, no. The goal is to have multiple commands floating around. In the
interest of clarity, here is a more realistic use case:
connection = connect(...)
commands = getSQL()
commands = [ connection.prepare(sql) for sql in commands ]
descrs = [ command.description for command in commands ]
cursor = connection.cursor()
while 1:
op = getNextOperation()
i,args = decodeOp(op, descrs)
cursor.execute(commands[i], args)
This is a little contrived, since our real code doesn't dispatch commands in
a single loop. They're spread out in a hierarchy of object and triggered by
data-driven events. In some tests using native (vs. DB-API) interfaces, we
obtain a 2.4x speedup by using prepared queries against a local database.
-Kevin
--
--
Kevin Jacobs
The OPAL Group - Enterprise Systems Architect
Voice: (216) 986-0710 x 19 E-mail: jacobs@theopalgroup.com
Fax: (216) 986-0714 WWW: http://www.theopalgroup.com