Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for prepared statements #116

Open
joerivanruth opened this issue Feb 8, 2023 · 4 comments
Open

Add support for prepared statements #116

joerivanruth opened this issue Feb 8, 2023 · 4 comments

Comments

@joerivanruth
Copy link
Member

Using prepared statements can be more efficient but PEP 249 does not provide an API for it. Instead, it mentions that

A reference to the operation will be retained by the cursor. If the same operation object is passed in again, then the cursor can optimize its behavior. This is most effective for algorithms where the same operation is used, but different parameters are bound to it (many times).

However, it is not safe for pymonetdb to simply prepend PREPARE to an arbitrary block of SQL code and expect it to work. For example, if there is more than one sql statement in there, only the first would get prepared, the rest would get executed. There could also be EXPLAIN, or ddl statements, misleading comments, or other things that would break.

Pymonetdb just cannot be sure that the user has taken into account that cursor.execute(code_with_percent_s, args) might actually be transformed into cursor.execute('PREPARE ' + code_with_question_marks); ...; cursor.execute('EXEC 42(...)', args).

Instead of having pymonetdb try to guess, I propose we add a .prepare() method to Cursor and maybe Connection. This method would prepare the statement and return an object that knows about the parameter- and result types, and which you can invoke .execute() and .executemany() on.

Alternatively, if we also want applications that are not pymonetdb-aware to benefit from prepared statements, we could augment the responses from the server with information on whether the given statements would have been suitable for PREPARE. Pymonetdb could remember this and if it encounters the same SQL code again, use it to decide whether or not to PREPARE this time.

It has also been suggested to add a connect parameter that says "use prepared statements, I promise not to pass any sql code that cannot be PREPAREd". I am a little uneasy with this because it seems very error prone. The person who writes the Connect statement (or MAPI URL parameter) may not be the same as the person who writes the individual execute statements.

@joerivanruth
Copy link
Member Author

Note that currently, cursor.execute("PREPARE SELECT ? + 42") crashes pymonetdb because it cannot handle the resulting response. At the very least, we should probably fix that crash, and provide access to the number of the prepared statement so the user can then do cursor.execute("EXEC %s(%s)", [prepnr, 99]) and cursor.execute("DEALLOCATE %s", [prepnr]).

Should this be a separate issue?

@joerivanruth
Copy link
Member Author

Also note that MonetDB destroys all existing prepared statements when a transaction aborts due to an error or a ROLLBACK. If we go the way of the .prepare method, it would be nice if the returned object would have the capability to reregister itself when this happens.

@njnes
Copy link
Contributor

njnes commented Feb 9, 2023

on the server side work has started to fix this by recompiling the prepared statements

joerivanruth added a commit that referenced this issue Feb 28, 2023
Just handle the result set.
Leave the id of the prepared statement in cursor.lastrowid
so it can be used with EXEC.

See also issue #116.
@njnes
Copy link
Contributor

njnes commented Jul 31, 2023

the server now handles :name paramstyle='named' formated queries. The multi statement remains an issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants