support DB's that magically get SQL expressions to come out in cursor.lastrowid

Issue #3133 new
Mike Bayer repo owner created an issue

key to this is that we should never put a "primary key" column in "postfetch". If we define "postfetch" as, "columns we will fetch by selecting by PK", then that's how we should go.

patch:

diff --git a/lib/sqlalchemy/orm/persistence.py b/lib/sqlalchemy/orm/persistence.py
index 6669efc..410bf33 100644
--- a/lib/sqlalchemy/orm/persistence.py
+++ b/lib/sqlalchemy/orm/persistence.py
@@ -595,13 +595,19 @@ def _emit_insert_statements(base_mapper, uowtransaction,
                                         execute(statement, params)

                 primary_key = result.context.inserted_primary_key
-
                 if primary_key is not None:
                     # set primary key attributes
                     for pk, col in zip(primary_key,
                                     mapper._pks_by_table[table]):
                         prop = mapper_rec._columntoproperty[col]
-                        if state_dict.get(prop.key) is None:
+                        existing = state_dict.get(prop.key)
+                        if existing is None or \
+                            (
+                                # inline executed statement somehow made
+                                # it into last inserted rec.  OK !
+                                pk is not None and
+                                isinstance(existing, sql.ClauseElement)
+                            ):
                             # TODO: would rather say:
                             #state_dict[prop.key] = pk
                             mapper_rec._set_state_attr_by_column(
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 384cf27..6cabe50 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -2080,7 +2080,8 @@ class SQLCompiler(Compiled):
                         self.returning.append(c)
                         value = self.process(value.self_group(), **kw)
                     else:
-                        self.postfetch.append(c)
+                        if not c.primary_key:
+                            self.postfetch.append(c)
                         value = self.process(value.self_group(), **kw)
                 values.append((c, value))

SQLite then lets us get at SQL expressions using lastrowid, who knew:

from sqlalchemy import *
from sqlalchemy import sql
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class Foo(Base):
    __tablename__ = 'foo'
    pk = Column(Integer, primary_key=True)
    bar = Column(Integer)

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

session = Session(e)

foo = Foo()
foo.pk = sql.select([sql.func.coalesce(sql.func.max(Foo.pk) + 1, 1)])
session.add(foo)
session.commit()

Comments (3)

  1. Mike Bayer reporter
    • changed milestone to 1.1
    • marked as major

    this isn't critical for now, this is a non-standard behavior for cursor.lastrowid. pushing out non-critical behavioral changes from 1.0 .

  2. Log in to comment