summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartlomiej Biernacki <pax0r@o2.pl>2019-01-31 09:33:01 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2019-02-01 22:04:22 -0500
commit620bfde695079eeab35467086956764616de037c (patch)
treea25675d8b6ed2b0000ebd999c51853c100c24cde
parent5ae8a54ed381735a88141b8ec5326b21c36e793b (diff)
downloadsqlalchemy-620bfde695079eeab35467086956764616de037c.tar.gz
Render parenthesis around sqlite expression defaults
Fixed bug in SQLite DDL where using an expression as a server side default required that it be contained within parenthesis to be accepted by the sqlite parser. Pull request courtesy Bartlomiej Biernacki. Fixes: #4474 Closes: #4475 Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/4475 Pull-request-sha: 0af3238c69c2610333cf62082c12047d45c31ce0 Change-Id: I888c69bfba5a5ab8ffa420f512557ac311a36b31 (cherry picked from commit f7ce37e9dd493d4b60b3156f08ef4c98fd63904d)
-rw-r--r--doc/build/changelog/unreleased_12/4474.rst7
-rw-r--r--lib/sqlalchemy/dialects/sqlite/base.py3
-rw-r--r--test/dialect/test_sqlite.py77
3 files changed, 82 insertions, 5 deletions
diff --git a/doc/build/changelog/unreleased_12/4474.rst b/doc/build/changelog/unreleased_12/4474.rst
new file mode 100644
index 000000000..ba4c6b7c6
--- /dev/null
+++ b/doc/build/changelog/unreleased_12/4474.rst
@@ -0,0 +1,7 @@
+.. change::
+ :tags: bug, sqlite
+ :tickets: 4474
+
+ Fixed bug in SQLite DDL where using an expression as a server side default
+ required that it be contained within parenthesis to be accepted by the
+ sqlite parser. Pull request courtesy Bartlomiej Biernacki.
diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py
index bc7f7fce4..d6a713988 100644
--- a/lib/sqlalchemy/dialects/sqlite/base.py
+++ b/lib/sqlalchemy/dialects/sqlite/base.py
@@ -583,6 +583,7 @@ from ... import types as sqltypes
from ... import util
from ...engine import default
from ...engine import reflection
+from ...sql import ColumnElement
from ...sql import compiler
from ...types import BLOB # noqa
from ...types import BOOLEAN # noqa
@@ -1034,6 +1035,8 @@ class SQLiteDDLCompiler(compiler.DDLCompiler):
colspec = self.preparer.format_column(column) + " " + coltype
default = self.get_column_default_string(column)
if default is not None:
+ if isinstance(column.server_default.arg, ColumnElement):
+ default = "(" + default + ")"
colspec += " DEFAULT " + default
if not column.nullable:
diff --git a/test/dialect/test_sqlite.py b/test/dialect/test_sqlite.py
index adfca5b53..b9a5c28c1 100644
--- a/test/dialect/test_sqlite.py
+++ b/test/dialect/test_sqlite.py
@@ -504,12 +504,49 @@ class DefaultsTest(fixtures.TestBase, AssertsCompiledSQL):
Column("x", Boolean, server_default=sql.false()),
)
t.create(testing.db)
- testing.db.execute(t.insert())
- testing.db.execute(t.insert().values(x=True))
- eq_(
- testing.db.execute(t.select().order_by(t.c.x)).fetchall(),
- [(False,), (True,)],
+ with testing.db.connect() as conn:
+ conn.execute(t.insert())
+ conn.execute(t.insert().values(x=True))
+ eq_(
+ conn.execute(t.select().order_by(t.c.x)).fetchall(),
+ [(False,), (True,)],
+ )
+
+ @testing.provide_metadata
+ def test_function_default(self):
+ t = Table(
+ "t",
+ self.metadata,
+ Column("id", Integer, primary_key=True),
+ Column("x", DateTime(), server_default=func.now()),
+ )
+ t.create(testing.db)
+ with testing.db.connect() as conn:
+ now = conn.scalar(func.now())
+ today = datetime.datetime.today()
+ conn.execute(t.insert())
+ conn.execute(t.insert().values(x=today))
+ eq_(
+ conn.execute(select([t.c.x]).order_by(t.c.id)).fetchall(),
+ [(now,), (today,)],
+ )
+
+ @testing.provide_metadata
+ def test_expression_with_function_default(self):
+ t = Table(
+ "t",
+ self.metadata,
+ Column("id", Integer, primary_key=True),
+ Column("x", Integer(), server_default=func.abs(-5) + 17),
)
+ t.create(testing.db)
+ with testing.db.connect() as conn:
+ conn.execute(t.insert())
+ conn.execute(t.insert().values(x=35))
+ eq_(
+ conn.execute(select([t.c.x]).order_by(t.c.id)).fetchall(),
+ [(22,), (35,)],
+ )
def test_old_style_default(self):
"""test non-quoted integer value on older sqlite pragma"""
@@ -851,6 +888,36 @@ class SQLTest(fixtures.TestBase, AssertsCompiledSQL):
")",
)
+ def test_column_defaults_ddl(self):
+
+ t = Table(
+ "t", MetaData(), Column("x", Boolean, server_default=sql.false())
+ )
+
+ self.assert_compile(
+ CreateTable(t),
+ "CREATE TABLE t (x BOOLEAN DEFAULT (0), CHECK (x IN (0, 1)))",
+ )
+
+ t = Table(
+ "t",
+ MetaData(),
+ Column("x", String(), server_default=func.sqlite_version()),
+ )
+ self.assert_compile(
+ CreateTable(t),
+ "CREATE TABLE t (x VARCHAR DEFAULT (sqlite_version()))",
+ )
+
+ t = Table(
+ "t",
+ MetaData(),
+ Column("x", Integer(), server_default=func.abs(-5) + 17),
+ )
+ self.assert_compile(
+ CreateTable(t), "CREATE TABLE t (x INTEGER DEFAULT (abs(-5) + 17))"
+ )
+
def test_create_partial_index(self):
m = MetaData()
tbl = Table("testtbl", m, Column("data", Integer))