Reputation: 154664
I've got an insert statement like this:
insert = MyTable.insert()
row = {"foo": 42}
result = cxn.execute(insert, row)
But a Postgres trigger is redirecting inserts from mytable
to a new table, so the insert statement doesn't actually return anything:
# INSERT INTO mytable VALUES (DEFAULT, 'stuff') RETURNING LASTVAL();
lastval
---------
(0 rows)
This causes SQLAlchemy (0.8b2) to raise a TypeError: 'NoneType' is not subscriptable
. It looks like this is happening when the DefaultExecutionContext
tries to fetch the primary key of the inserted row.
Is this a bug that should be reported? And is there any way I can work around this, telling SQLAlchemy not to expect a return value?
… snip…
File "myfile.py", line 85, in store
result = cxn.execute(insert, row)
File ".../sqlalchemy/engine/base.py", line 664, in execute
params)
File ".../sqlalchemy/engine/base.py", line 764, in _execute_clauseelement
compiled_sql, distilled_params
File ".../sqlalchemy/engine/base.py", line 899, in _execute_context
context._fetch_implicit_returning(result)
File ".../sqlalchemy/engine/default.py", line 697, in _fetch_implicit_returning
ipk.append(row[c])
TypeError: 'NoneType' object is not subscriptable
CREATE OR REPLACE FUNCTION mytable_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO mytable_cur VALUES (NEW.*);
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER mytable_insert_trigger
BEFORE INSERT ON mytable
FOR EACH ROW EXECUTE PROCEDURE mytable_insert_trigger();
Upvotes: 2
Views: 796
Reputation: 75317
yeah, you can fall back to the old system of obtaining the last inserted id by turning off implicit_returning, which you can do for the Table:
Table('sometable', metadata, ... columns ..., implicit_returning=False)
what will happen there is, assuming this is a straight up SERIAL primary key, it will execute "tablename_id_seq" explicitly beforehand and just use that value in the INSERT statement.
Upvotes: 2
Reputation: 48594
You broke the contract here. Against a Postgres backend, SQLAlchemy will tend to use INSERT ... RETURNING
so that it can retrieve e.g. values from generated sequences. You're inserting a row but lying about it.
Based on the documentation, I think you want to use an INSTEAD OF
trigger rather than BEFORE
, and have it return the NEW
row unchanged. Postgres will assume you did whatever inserting is necessary, and merely shuttle the returned row back to the client.
Upvotes: 2