[Sqlalchemy-tickets] Issue #3923: pre-execute column defaults don't apply type processing (zzzeek/s
Brought to you by:
zzzeek
From: Michael B. <iss...@bi...> - 2017-02-27 21:29:55
|
New issue 3923: pre-execute column defaults don't apply type processing https://bitbucket.org/zzzeek/sqlalchemy/issues/3923/pre-execute-column-defaults-dont-apply Michael Bayer: it seems like pre-execute is much more rarely used but it still applies to primary keys, fails here as SQLite's column processing is missing: ``` #!python from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class A(Base): __tablename__ = 'a' id = Column(Integer, primary_key=True) date = Column(DateTime, default=text("datetime()"), primary_key=True) e = create_engine("sqlite://", echo=True) Base.metadata.create_all(e) s = Session(e) s.add(A(id=1)) s.commit() ``` patch: ``` #!diff diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index 18c3276..0210ad7 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -1039,7 +1039,11 @@ class DefaultExecutionContext(interfaces.ExecutionContext): # TODO: expensive branching here should be # pulled into _exec_scalar() conn = self.connection - c = expression.select([default.arg]).compile(bind=conn) + if not default._arg_is_typed: + default_arg = expression.type_coerce(default.arg, type_) + else: + default_arg = default.arg + c = expression.select([default_arg]).compile(bind=conn) return conn._execute_compiled(c, (), {}).scalar() else: return default.arg diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 9bb0eee..f5716af 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -2045,6 +2045,14 @@ class ColumnDefault(DefaultGenerator): not self.is_clause_element and \ not self.is_sequence + @util.memoized_property + @util.dependencies("sqlalchemy.sql.sqltypes") + def _arg_is_typed(self, sqltypes): + if self.is_clause_element: + return not isinstance(self.arg.type, sqltypes.NullType) + else: + return False + def _maybe_wrap_callable(self, fn): """Wrap callables that don't accept a context. ``` |