7

This does not work – the update has no effect:

command = "select content from blog where slug = 'meow'; update account_balance set balance=200 where id=1; select 1 from blog;"
content = db.engine.scalar(command)

Switching the statements performs the update and select successfully:

command = "update account_balance set balance=200 where id=1; select content from blog where slug = 'meow';"
content = db.engine.scalar(command)

Why does the first not work? It works in Pgadmin. I enabled autocommit with Flask-Sqlalchemy.

I am doing a workshop on SQL injection, so please dont rewrite the solution!

4
  • Define "doesn't work"? Exactly. Commented Jul 27, 2017 at 10:12
  • 1
    @CraigRinger the account_balance row doesn't update, of course Commented Jul 27, 2017 at 10:14
  • @IljaEverilä, I get no error since the db executes them, but the update statement has no effect Commented Jul 27, 2017 at 10:17
  • @IljaEverilä You are right. I forgot to include something to avoid the error. And I use 1.1.12 Commented Jul 27, 2017 at 10:25

3 Answers 3

8

The way SQLAlchemy's autocommit works is that it inspects the issued statements, trying to detect whether or not data is modified:

..., SQLAlchemy implements its own “autocommit” feature which works completely consistently across all backends. This is achieved by detecting statements which represent data-changing operations, i.e. INSERT, UPDATE, DELETE, as well as data definition language (DDL) statements such as CREATE TABLE, ALTER TABLE, and then issuing a COMMIT automatically if no transaction is in progress. The detection is based on the presence of the autocommit=True execution option on the statement. If the statement is a text-only statement and the flag is not set, a regular expression is used to detect INSERT, UPDATE, DELETE, as well as a variety of other commands for a particular backend

Since multiple result sets are not supported at SQLAlchemy level, in your first example the detection simply omits issuing a COMMIT because the first statement is a SELECT, where as in your second example it is an UPDATE. No attempt to detect data modifying statements from multiple statements takes place.

If you look at PGExecutionContext.should_autocommit_text(), you'll see that it does a regex match against AUTOCOMMIT_REGEXP. In other words it matches only at the beginning of the text.

Sign up to request clarification or add additional context in comments.

9 Comments

I appended a commit and now it works. SQLAlchemy must have forgotten to issue it by itself. Is your speculation that SQLA checks the last statement for whether it should issue a commit?
Sorry, I fixed the answer. It is the first statement that matters (like in your second example, where the first statement is the UPDATE). Also added some context as to why.
Wow seriously? That's an insane way to implement that. Don't use that feature!
@craig-ringer It works ok for single textual SQL statements, and if you really want both multi-statement SQL strings (which SQLA does not seem to officially support, but leaves for DBAPI level) and autocommit, there's text(...).execution_options(autocommit=True), as documented in "Understanding Autocommit", though I guess that's more commonly used for signalling that a function or SP mutates data and should commit. On the other hand personally I'm not a fan of autocommit in general.
@CraigRinger Absolutely. That's why the docs have the example engine.execute(text("SELECT my_mutating_procedure()").execution_options(autocommit=True)). I actually ran in to similar issues before support for REFRESH MATERIALIZED VIEW was added. Had to manually mark the session as dirty so that the transaction context handler would issue a COMMIT.
|
0

If you want to create a table using SELECT INTO:

As explained above engine.execute('select * into a from b') doesn't work. Instead you can do as follows:

conn = engine.raw_connection()
cursor = conn.cursor()

cursor.execute('select * into a from b')
conn.commit() 

Comments

-1

You should use db.engine.execute(...).first() if you want to execute everything and get only first row.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.