]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Support SQLite WITHOUT ROWID tables
authorSean Anderson <seanga2@gmail.com>
Sun, 8 Nov 2020 00:52:04 +0000 (19:52 -0500)
committerGord Thompson <gord@gordthompson.com>
Sun, 8 Nov 2020 13:17:56 +0000 (06:17 -0700)
This adds support for creating tables WITHOUT ROWID in the SQLite
dialect. WITHOUT ROWID tables were introduced in SQLite version 3.8.2
(2013-12-06). They do not use an implicit rowid column as the primary
key. This may result in space and performance savings for tables without
INTEGER primary keys and tables with composite primary keys. For more
information about this feature, see the sqlite documentation [1].

[1] https://www.sqlite.org/withoutrowid.html

Fixes: #5685
### Checklist
This pull request is:

- [x] A new feature implementation
- please include the issue number, and create an issue if none exists, which must
  include a complete example of how the feature would look.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.

Closes: #5686
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/5686
Pull-request-sha: 2b44782d1b3d858e31ce1ff8e08e197af37344d8

Change-Id: Ifcf727b0c07c90e267b79828a8e3fd7a8260a074
(cherry picked from commit 4b39b0f89dfd47dc9f5ba948e564c2afbbd44fef)

doc/build/changelog/unreleased_13/5685.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/sqlite/base.py
test/dialect/test_sqlite.py

diff --git a/doc/build/changelog/unreleased_13/5685.rst b/doc/build/changelog/unreleased_13/5685.rst
new file mode 100644 (file)
index 0000000..6f98cfa
--- /dev/null
@@ -0,0 +1,6 @@
+.. change::
+    :tags: sqlite, usecase
+    :tickets: 5685
+
+    Added ``sqlite_with_rowid=False`` dialect keyword to enable creating
+    tables as ``CREATE TABLE … WITHOUT ROWID``. Patch courtesy Sean Anderson.
index 4e9a81b1d47a6c28bc61dde5c056ae3b7ff66e27..cb60905106d8ad64f9b8b41512f3898d9f466549 100644 (file)
@@ -584,6 +584,21 @@ or on a per-:class:`_engine.Engine` basis::
 When using the per-:class:`_engine.Engine` execution option, note that
 **Core and ORM queries that use UNION may not function properly**.
 
+SQLite-specific table options
+-----------------------------
+
+One option for CREATE TABLE is supported directly by the SQLite
+dialect in conjunction with the :class:`_schema.Table` construct:
+
+* ``WITHOUT ROWID``::
+
+    Table("some_table", metadata, ..., sqlite_with_rowid=False)
+
+.. seealso::
+
+    `SQLite CREATE TABLE options
+    <https://www.sqlite.org/lang_createtable.html>`_
+
 """  # noqa
 
 import datetime
@@ -1254,6 +1269,11 @@ class SQLiteDDLCompiler(compiler.DDLCompiler):
 
         return text
 
+    def post_create_table(self, table):
+        if table.dialect_options["sqlite"]["with_rowid"] is False:
+            return "\n WITHOUT ROWID"
+        return ""
+
 
 class SQLiteTypeCompiler(compiler.GenericTypeCompiler):
     def visit_large_binary(self, type_, **kw):
@@ -1461,7 +1481,13 @@ class SQLiteDialect(default.DefaultDialect):
     isolation_level = None
 
     construct_arguments = [
-        (sa_schema.Table, {"autoincrement": False}),
+        (
+            sa_schema.Table,
+            {
+                "autoincrement": False,
+                "with_rowid": True,
+            },
+        ),
         (sa_schema.Index, {"where": None}),
         (
             sa_schema.Column,
index 46ff6c9e7a6b35d82b1b750f9bf153416829ecbc..870f386bc0f3e27bad3155f28b05ff40f795a150 100644 (file)
@@ -1113,6 +1113,16 @@ class SQLTest(fixtures.TestBase, AssertsCompiledSQL):
             "(q, p) IN (VALUES (?, ?), (?, ?))",
         )
 
+    def test_create_table_without_rowid(self):
+        m = MetaData()
+        tbl = Table(
+            "atable", m, Column("id", Integer), sqlite_with_rowid=False
+        )
+        self.assert_compile(
+            schema.CreateTable(tbl),
+            "CREATE TABLE atable (id INTEGER) WITHOUT ROWID",
+        )
+
 
 class OnConflictDDLTest(fixtures.TestBase, AssertsCompiledSQL):