1# sqlite/base.py
2# Copyright (C) 2005-2021 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: http://www.opensource.org/licenses/mit-license.php
7
8r"""
9.. dialect:: sqlite
10 :name: SQLite
11
12.. _sqlite_datetime:
13
14Date and Time Types
15-------------------
16
17SQLite does not have built-in DATE, TIME, or DATETIME types, and pysqlite does
18not provide out of the box functionality for translating values between Python
19`datetime` objects and a SQLite-supported format. SQLAlchemy's own
20:class:`~sqlalchemy.types.DateTime` and related types provide date formatting
21and parsing functionality when SQLite is used. The implementation classes are
22:class:`_sqlite.DATETIME`, :class:`_sqlite.DATE` and :class:`_sqlite.TIME`.
23These types represent dates and times as ISO formatted strings, which also
24nicely support ordering. There's no reliance on typical "libc" internals for
25these functions so historical dates are fully supported.
26
27Ensuring Text affinity
28^^^^^^^^^^^^^^^^^^^^^^
29
30The DDL rendered for these types is the standard ``DATE``, ``TIME``
31and ``DATETIME`` indicators. However, custom storage formats can also be
32applied to these types. When the
33storage format is detected as containing no alpha characters, the DDL for
34these types is rendered as ``DATE_CHAR``, ``TIME_CHAR``, and ``DATETIME_CHAR``,
35so that the column continues to have textual affinity.
36
37.. seealso::
38
39 `Type Affinity <http://www.sqlite.org/datatype3.html#affinity>`_ -
40 in the SQLite documentation
41
42.. _sqlite_autoincrement:
43
44SQLite Auto Incrementing Behavior
45----------------------------------
46
47Background on SQLite's autoincrement is at: http://sqlite.org/autoinc.html
48
49Key concepts:
50
51* SQLite has an implicit "auto increment" feature that takes place for any
52 non-composite primary-key column that is specifically created using
53 "INTEGER PRIMARY KEY" for the type + primary key.
54
55* SQLite also has an explicit "AUTOINCREMENT" keyword, that is **not**
56 equivalent to the implicit autoincrement feature; this keyword is not
57 recommended for general use. SQLAlchemy does not render this keyword
58 unless a special SQLite-specific directive is used (see below). However,
59 it still requires that the column's type is named "INTEGER".
60
61Using the AUTOINCREMENT Keyword
62^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
63
64To specifically render the AUTOINCREMENT keyword on the primary key column
65when rendering DDL, add the flag ``sqlite_autoincrement=True`` to the Table
66construct::
67
68 Table('sometable', metadata,
69 Column('id', Integer, primary_key=True),
70 sqlite_autoincrement=True)
71
72Allowing autoincrement behavior SQLAlchemy types other than Integer/INTEGER
73^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
74
75SQLite's typing model is based on naming conventions. Among other things, this
76means that any type name which contains the substring ``"INT"`` will be
77determined to be of "integer affinity". A type named ``"BIGINT"``,
78``"SPECIAL_INT"`` or even ``"XYZINTQPR"``, will be considered by SQLite to be
79of "integer" affinity. However, **the SQLite autoincrement feature, whether
80implicitly or explicitly enabled, requires that the name of the column's type
81is exactly the string "INTEGER"**. Therefore, if an application uses a type
82like :class:`.BigInteger` for a primary key, on SQLite this type will need to
83be rendered as the name ``"INTEGER"`` when emitting the initial ``CREATE
84TABLE`` statement in order for the autoincrement behavior to be available.
85
86One approach to achieve this is to use :class:`.Integer` on SQLite
87only using :meth:`.TypeEngine.with_variant`::
88
89 table = Table(
90 "my_table", metadata,
91 Column("id", BigInteger().with_variant(Integer, "sqlite"), primary_key=True)
92 )
93
94Another is to use a subclass of :class:`.BigInteger` that overrides its DDL
95name to be ``INTEGER`` when compiled against SQLite::
96
97 from sqlalchemy import BigInteger
98 from sqlalchemy.ext.compiler import compiles
99
100 class SLBigInteger(BigInteger):
101 pass
102
103 @compiles(SLBigInteger, 'sqlite')
104 def bi_c(element, compiler, **kw):
105 return "INTEGER"
106
107 @compiles(SLBigInteger)
108 def bi_c(element, compiler, **kw):
109 return compiler.visit_BIGINT(element, **kw)
110
111
112 table = Table(
113 "my_table", metadata,
114 Column("id", SLBigInteger(), primary_key=True)
115 )
116
117.. seealso::
118
119 :meth:`.TypeEngine.with_variant`
120
121 :ref:`sqlalchemy.ext.compiler_toplevel`
122
123 `Datatypes In SQLite Version 3 <http://sqlite.org/datatype3.html>`_
124
125.. _sqlite_concurrency:
126
127Database Locking Behavior / Concurrency
128---------------------------------------
129
130SQLite is not designed for a high level of write concurrency. The database
131itself, being a file, is locked completely during write operations within
132transactions, meaning exactly one "connection" (in reality a file handle)
133has exclusive access to the database during this period - all other
134"connections" will be blocked during this time.
135
136The Python DBAPI specification also calls for a connection model that is
137always in a transaction; there is no ``connection.begin()`` method,
138only ``connection.commit()`` and ``connection.rollback()``, upon which a
139new transaction is to be begun immediately. This may seem to imply
140that the SQLite driver would in theory allow only a single filehandle on a
141particular database file at any time; however, there are several
142factors both within SQLite itself as well as within the pysqlite driver
143which loosen this restriction significantly.
144
145However, no matter what locking modes are used, SQLite will still always
146lock the database file once a transaction is started and DML (e.g. INSERT,
147UPDATE, DELETE) has at least been emitted, and this will block
148other transactions at least at the point that they also attempt to emit DML.
149By default, the length of time on this block is very short before it times out
150with an error.
151
152This behavior becomes more critical when used in conjunction with the
153SQLAlchemy ORM. SQLAlchemy's :class:`.Session` object by default runs
154within a transaction, and with its autoflush model, may emit DML preceding
155any SELECT statement. This may lead to a SQLite database that locks
156more quickly than is expected. The locking mode of SQLite and the pysqlite
157driver can be manipulated to some degree, however it should be noted that
158achieving a high degree of write-concurrency with SQLite is a losing battle.
159
160For more information on SQLite's lack of write concurrency by design, please
161see
162`Situations Where Another RDBMS May Work Better - High Concurrency
163<http://www.sqlite.org/whentouse.html>`_ near the bottom of the page.
164
165The following subsections introduce areas that are impacted by SQLite's
166file-based architecture and additionally will usually require workarounds to
167work when using the pysqlite driver.
168
169.. _sqlite_isolation_level:
170
171Transaction Isolation Level / Autocommit
172----------------------------------------
173
174SQLite supports "transaction isolation" in a non-standard way, along two
175axes. One is that of the
176`PRAGMA read_uncommitted <http://www.sqlite.org/pragma.html#pragma_read_uncommitted>`_
177instruction. This setting can essentially switch SQLite between its
178default mode of ``SERIALIZABLE`` isolation, and a "dirty read" isolation
179mode normally referred to as ``READ UNCOMMITTED``.
180
181SQLAlchemy ties into this PRAGMA statement using the
182:paramref:`_sa.create_engine.isolation_level` parameter of
183:func:`_sa.create_engine`.
184Valid values for this parameter when used with SQLite are ``"SERIALIZABLE"``
185and ``"READ UNCOMMITTED"`` corresponding to a value of 0 and 1, respectively.
186SQLite defaults to ``SERIALIZABLE``, however its behavior is impacted by
187the pysqlite driver's default behavior.
188
189When using the pysqlite driver, the ``"AUTOCOMMIT"`` isolation level is also
190available, which will alter the pysqlite connection using the ``.isolation_level``
191attribute on the DBAPI connection and set it to None for the duration
192of the setting.
193
194.. versionadded:: 1.3.16 added support for SQLite AUTOCOMMIT isolation level
195 when using the pysqlite / sqlite3 SQLite driver.
196
197
198The other axis along which SQLite's transactional locking is impacted is
199via the nature of the ``BEGIN`` statement used. The three varieties
200are "deferred", "immediate", and "exclusive", as described at
201`BEGIN TRANSACTION <http://sqlite.org/lang_transaction.html>`_. A straight
202``BEGIN`` statement uses the "deferred" mode, where the database file is
203not locked until the first read or write operation, and read access remains
204open to other transactions until the first write operation. But again,
205it is critical to note that the pysqlite driver interferes with this behavior
206by *not even emitting BEGIN* until the first write operation.
207
208.. warning::
209
210 SQLite's transactional scope is impacted by unresolved
211 issues in the pysqlite driver, which defers BEGIN statements to a greater
212 degree than is often feasible. See the section :ref:`pysqlite_serializable`
213 for techniques to work around this behavior.
214
215.. seealso::
216
217 :ref:`dbapi_autocommit`
218
219SAVEPOINT Support
220----------------------------
221
222SQLite supports SAVEPOINTs, which only function once a transaction is
223begun. SQLAlchemy's SAVEPOINT support is available using the
224:meth:`_engine.Connection.begin_nested` method at the Core level, and
225:meth:`.Session.begin_nested` at the ORM level. However, SAVEPOINTs
226won't work at all with pysqlite unless workarounds are taken.
227
228.. warning::
229
230 SQLite's SAVEPOINT feature is impacted by unresolved
231 issues in the pysqlite driver, which defers BEGIN statements to a greater
232 degree than is often feasible. See the section :ref:`pysqlite_serializable`
233 for techniques to work around this behavior.
234
235Transactional DDL
236----------------------------
237
238The SQLite database supports transactional :term:`DDL` as well.
239In this case, the pysqlite driver is not only failing to start transactions,
240it also is ending any existing transaction when DDL is detected, so again,
241workarounds are required.
242
243.. warning::
244
245 SQLite's transactional DDL is impacted by unresolved issues
246 in the pysqlite driver, which fails to emit BEGIN and additionally
247 forces a COMMIT to cancel any transaction when DDL is encountered.
248 See the section :ref:`pysqlite_serializable`
249 for techniques to work around this behavior.
250
251.. _sqlite_foreign_keys:
252
253Foreign Key Support
254-------------------
255
256SQLite supports FOREIGN KEY syntax when emitting CREATE statements for tables,
257however by default these constraints have no effect on the operation of the
258table.
259
260Constraint checking on SQLite has three prerequisites:
261
262* At least version 3.6.19 of SQLite must be in use
263* The SQLite library must be compiled *without* the SQLITE_OMIT_FOREIGN_KEY
264 or SQLITE_OMIT_TRIGGER symbols enabled.
265* The ``PRAGMA foreign_keys = ON`` statement must be emitted on all
266 connections before use.
267
268SQLAlchemy allows for the ``PRAGMA`` statement to be emitted automatically for
269new connections through the usage of events::
270
271 from sqlalchemy.engine import Engine
272 from sqlalchemy import event
273
274 @event.listens_for(Engine, "connect")
275 def set_sqlite_pragma(dbapi_connection, connection_record):
276 cursor = dbapi_connection.cursor()
277 cursor.execute("PRAGMA foreign_keys=ON")
278 cursor.close()
279
280.. warning::
281
282 When SQLite foreign keys are enabled, it is **not possible**
283 to emit CREATE or DROP statements for tables that contain
284 mutually-dependent foreign key constraints;
285 to emit the DDL for these tables requires that ALTER TABLE be used to
286 create or drop these constraints separately, for which SQLite has
287 no support.
288
289.. seealso::
290
291 `SQLite Foreign Key Support <http://www.sqlite.org/foreignkeys.html>`_
292 - on the SQLite web site.
293
294 :ref:`event_toplevel` - SQLAlchemy event API.
295
296 :ref:`use_alter` - more information on SQLAlchemy's facilities for handling
297 mutually-dependent foreign key constraints.
298
299.. _sqlite_on_conflict_ddl:
300
301ON CONFLICT support for constraints
302-----------------------------------
303
304SQLite supports a non-standard clause known as ON CONFLICT which can be applied
305to primary key, unique, check, and not null constraints. In DDL, it is
306rendered either within the "CONSTRAINT" clause or within the column definition
307itself depending on the location of the target constraint. To render this
308clause within DDL, the extension parameter ``sqlite_on_conflict`` can be
309specified with a string conflict resolution algorithm within the
310:class:`.PrimaryKeyConstraint`, :class:`.UniqueConstraint`,
311:class:`.CheckConstraint` objects. Within the :class:`_schema.Column` object,
312there
313are individual parameters ``sqlite_on_conflict_not_null``,
314``sqlite_on_conflict_primary_key``, ``sqlite_on_conflict_unique`` which each
315correspond to the three types of relevant constraint types that can be
316indicated from a :class:`_schema.Column` object.
317
318.. seealso::
319
320 `ON CONFLICT <https://www.sqlite.org/lang_conflict.html>`_ - in the SQLite
321 documentation
322
323.. versionadded:: 1.3
324
325
326The ``sqlite_on_conflict`` parameters accept a string argument which is just
327the resolution name to be chosen, which on SQLite can be one of ROLLBACK,
328ABORT, FAIL, IGNORE, and REPLACE. For example, to add a UNIQUE constraint
329that specifies the IGNORE algorithm::
330
331 some_table = Table(
332 'some_table', metadata,
333 Column('id', Integer, primary_key=True),
334 Column('data', Integer),
335 UniqueConstraint('id', 'data', sqlite_on_conflict='IGNORE')
336 )
337
338The above renders CREATE TABLE DDL as::
339
340 CREATE TABLE some_table (
341 id INTEGER NOT NULL,
342 data INTEGER,
343 PRIMARY KEY (id),
344 UNIQUE (id, data) ON CONFLICT IGNORE
345 )
346
347
348When using the :paramref:`_schema.Column.unique`
349flag to add a UNIQUE constraint
350to a single column, the ``sqlite_on_conflict_unique`` parameter can
351be added to the :class:`_schema.Column` as well, which will be added to the
352UNIQUE constraint in the DDL::
353
354 some_table = Table(
355 'some_table', metadata,
356 Column('id', Integer, primary_key=True),
357 Column('data', Integer, unique=True,
358 sqlite_on_conflict_unique='IGNORE')
359 )
360
361rendering::
362
363 CREATE TABLE some_table (
364 id INTEGER NOT NULL,
365 data INTEGER,
366 PRIMARY KEY (id),
367 UNIQUE (data) ON CONFLICT IGNORE
368 )
369
370To apply the FAIL algorithm for a NOT NULL constraint,
371``sqlite_on_conflict_not_null`` is used::
372
373 some_table = Table(
374 'some_table', metadata,
375 Column('id', Integer, primary_key=True),
376 Column('data', Integer, nullable=False,
377 sqlite_on_conflict_not_null='FAIL')
378 )
379
380this renders the column inline ON CONFLICT phrase::
381
382 CREATE TABLE some_table (
383 id INTEGER NOT NULL,
384 data INTEGER NOT NULL ON CONFLICT FAIL,
385 PRIMARY KEY (id)
386 )
387
388
389Similarly, for an inline primary key, use ``sqlite_on_conflict_primary_key``::
390
391 some_table = Table(
392 'some_table', metadata,
393 Column('id', Integer, primary_key=True,
394 sqlite_on_conflict_primary_key='FAIL')
395 )
396
397SQLAlchemy renders the PRIMARY KEY constraint separately, so the conflict
398resolution algorithm is applied to the constraint itself::
399
400 CREATE TABLE some_table (
401 id INTEGER NOT NULL,
402 PRIMARY KEY (id) ON CONFLICT FAIL
403 )
404
405.. _sqlite_type_reflection:
406
407Type Reflection
408---------------
409
410SQLite types are unlike those of most other database backends, in that
411the string name of the type usually does not correspond to a "type" in a
412one-to-one fashion. Instead, SQLite links per-column typing behavior
413to one of five so-called "type affinities" based on a string matching
414pattern for the type.
415
416SQLAlchemy's reflection process, when inspecting types, uses a simple
417lookup table to link the keywords returned to provided SQLAlchemy types.
418This lookup table is present within the SQLite dialect as it is for all
419other dialects. However, the SQLite dialect has a different "fallback"
420routine for when a particular type name is not located in the lookup map;
421it instead implements the SQLite "type affinity" scheme located at
422http://www.sqlite.org/datatype3.html section 2.1.
423
424The provided typemap will make direct associations from an exact string
425name match for the following types:
426
427:class:`_types.BIGINT`, :class:`_types.BLOB`,
428:class:`_types.BOOLEAN`, :class:`_types.BOOLEAN`,
429:class:`_types.CHAR`, :class:`_types.DATE`,
430:class:`_types.DATETIME`, :class:`_types.FLOAT`,
431:class:`_types.DECIMAL`, :class:`_types.FLOAT`,
432:class:`_types.INTEGER`, :class:`_types.INTEGER`,
433:class:`_types.NUMERIC`, :class:`_types.REAL`,
434:class:`_types.SMALLINT`, :class:`_types.TEXT`,
435:class:`_types.TIME`, :class:`_types.TIMESTAMP`,
436:class:`_types.VARCHAR`, :class:`_types.NVARCHAR`,
437:class:`_types.NCHAR`
438
439When a type name does not match one of the above types, the "type affinity"
440lookup is used instead:
441
442* :class:`_types.INTEGER` is returned if the type name includes the
443 string ``INT``
444* :class:`_types.TEXT` is returned if the type name includes the
445 string ``CHAR``, ``CLOB`` or ``TEXT``
446* :class:`_types.NullType` is returned if the type name includes the
447 string ``BLOB``
448* :class:`_types.REAL` is returned if the type name includes the string
449 ``REAL``, ``FLOA`` or ``DOUB``.
450* Otherwise, the :class:`_types.NUMERIC` type is used.
451
452.. versionadded:: 0.9.3 Support for SQLite type affinity rules when reflecting
453 columns.
454
455
456.. _sqlite_partial_index:
457
458Partial Indexes
459---------------
460
461A partial index, e.g. one which uses a WHERE clause, can be specified
462with the DDL system using the argument ``sqlite_where``::
463
464 tbl = Table('testtbl', m, Column('data', Integer))
465 idx = Index('test_idx1', tbl.c.data,
466 sqlite_where=and_(tbl.c.data > 5, tbl.c.data < 10))
467
468The index will be rendered at create time as::
469
470 CREATE INDEX test_idx1 ON testtbl (data)
471 WHERE data > 5 AND data < 10
472
473.. versionadded:: 0.9.9
474
475.. _sqlite_dotted_column_names:
476
477Dotted Column Names
478-------------------
479
480Using table or column names that explicitly have periods in them is
481**not recommended**. While this is generally a bad idea for relational
482databases in general, as the dot is a syntactically significant character,
483the SQLite driver up until version **3.10.0** of SQLite has a bug which
484requires that SQLAlchemy filter out these dots in result sets.
485
486.. versionchanged:: 1.1
487
488 The following SQLite issue has been resolved as of version 3.10.0
489 of SQLite. SQLAlchemy as of **1.1** automatically disables its internal
490 workarounds based on detection of this version.
491
492The bug, entirely outside of SQLAlchemy, can be illustrated thusly::
493
494 import sqlite3
495
496 assert sqlite3.sqlite_version_info < (3, 10, 0), "bug is fixed in this version"
497
498 conn = sqlite3.connect(":memory:")
499 cursor = conn.cursor()
500
501 cursor.execute("create table x (a integer, b integer)")
502 cursor.execute("insert into x (a, b) values (1, 1)")
503 cursor.execute("insert into x (a, b) values (2, 2)")
504
505 cursor.execute("select x.a, x.b from x")
506 assert [c[0] for c in cursor.description] == ['a', 'b']
507
508 cursor.execute('''
509 select x.a, x.b from x where a=1
510 union
511 select x.a, x.b from x where a=2
512 ''')
513 assert [c[0] for c in cursor.description] == ['a', 'b'], \
514 [c[0] for c in cursor.description]
515
516The second assertion fails::
517
518 Traceback (most recent call last):
519 File "test.py", line 19, in <module>
520 [c[0] for c in cursor.description]
521 AssertionError: ['x.a', 'x.b']
522
523Where above, the driver incorrectly reports the names of the columns
524including the name of the table, which is entirely inconsistent vs.
525when the UNION is not present.
526
527SQLAlchemy relies upon column names being predictable in how they match
528to the original statement, so the SQLAlchemy dialect has no choice but
529to filter these out::
530
531
532 from sqlalchemy import create_engine
533
534 eng = create_engine("sqlite://")
535 conn = eng.connect()
536
537 conn.execute("create table x (a integer, b integer)")
538 conn.execute("insert into x (a, b) values (1, 1)")
539 conn.execute("insert into x (a, b) values (2, 2)")
540
541 result = conn.execute("select x.a, x.b from x")
542 assert result.keys() == ["a", "b"]
543
544 result = conn.execute('''
545 select x.a, x.b from x where a=1
546 union
547 select x.a, x.b from x where a=2
548 ''')
549 assert result.keys() == ["a", "b"]
550
551Note that above, even though SQLAlchemy filters out the dots, *both
552names are still addressable*::
553
554 >>> row = result.first()
555 >>> row["a"]
556 1
557 >>> row["x.a"]
558 1
559 >>> row["b"]
560 1
561 >>> row["x.b"]
562 1
563
564Therefore, the workaround applied by SQLAlchemy only impacts
565:meth:`_engine.ResultProxy.keys` and :meth:`.RowProxy.keys()`
566in the public API. In
567the very specific case where an application is forced to use column names that
568contain dots, and the functionality of :meth:`_engine.ResultProxy.keys` and
569:meth:`.RowProxy.keys()` is required to return these dotted names unmodified,
570the ``sqlite_raw_colnames`` execution option may be provided, either on a
571per-:class:`_engine.Connection` basis::
572
573 result = conn.execution_options(sqlite_raw_colnames=True).execute('''
574 select x.a, x.b from x where a=1
575 union
576 select x.a, x.b from x where a=2
577 ''')
578 assert result.keys() == ["x.a", "x.b"]
579
580or on a per-:class:`_engine.Engine` basis::
581
582 engine = create_engine("sqlite://", execution_options={"sqlite_raw_colnames": True})
583
584When using the per-:class:`_engine.Engine` execution option, note that
585**Core and ORM queries that use UNION may not function properly**.
586
587SQLite-specific table options
588-----------------------------
589
590One option for CREATE TABLE is supported directly by the SQLite
591dialect in conjunction with the :class:`_schema.Table` construct:
592
593* ``WITHOUT ROWID``::
594
595 Table("some_table", metadata, ..., sqlite_with_rowid=False)
596
597.. seealso::
598
599 `SQLite CREATE TABLE options
600 <https://www.sqlite.org/lang_createtable.html>`_
601
602""" # noqa
603
604import datetime
605import numbers
606import re
607
608from .json import JSON
609from .json import JSONIndexType
610from .json import JSONPathType
611from ... import exc
612from ... import processors
613from ... import schema as sa_schema
614from ... import sql
615from ... import types as sqltypes
616from ... import util
617from ...engine import default
618from ...engine import reflection
619from ...sql import ColumnElement
620from ...sql import compiler
621from ...sql import schema
622from ...types import BLOB # noqa
623from ...types import BOOLEAN # noqa
624from ...types import CHAR # noqa
625from ...types import DECIMAL # noqa
626from ...types import FLOAT # noqa
627from ...types import INTEGER # noqa
628from ...types import NUMERIC # noqa
629from ...types import REAL # noqa
630from ...types import SMALLINT # noqa
631from ...types import TEXT # noqa
632from ...types import TIMESTAMP # noqa
633from ...types import VARCHAR # noqa
634
635
636class _SQliteJson(JSON):
637 def result_processor(self, dialect, coltype):
638 default_processor = super(_SQliteJson, self).result_processor(
639 dialect, coltype
640 )
641
642 def process(value):
643 try:
644 return default_processor(value)
645 except TypeError:
646 if isinstance(value, numbers.Number):
647 return value
648 else:
649 raise
650
651 return process
652
653
654class _DateTimeMixin(object):
655 _reg = None
656 _storage_format = None
657
658 def __init__(self, storage_format=None, regexp=None, **kw):
659 super(_DateTimeMixin, self).__init__(**kw)
660 if regexp is not None:
661 self._reg = re.compile(regexp)
662 if storage_format is not None:
663 self._storage_format = storage_format
664
665 @property
666 def format_is_text_affinity(self):
667 """return True if the storage format will automatically imply
668 a TEXT affinity.
669
670 If the storage format contains no non-numeric characters,
671 it will imply a NUMERIC storage format on SQLite; in this case,
672 the type will generate its DDL as DATE_CHAR, DATETIME_CHAR,
673 TIME_CHAR.
674
675 .. versionadded:: 1.0.0
676
677 """
678 spec = self._storage_format % {
679 "year": 0,
680 "month": 0,
681 "day": 0,
682 "hour": 0,
683 "minute": 0,
684 "second": 0,
685 "microsecond": 0,
686 }
687 return bool(re.search(r"[^0-9]", spec))
688
689 def adapt(self, cls, **kw):
690 if issubclass(cls, _DateTimeMixin):
691 if self._storage_format:
692 kw["storage_format"] = self._storage_format
693 if self._reg:
694 kw["regexp"] = self._reg
695 return super(_DateTimeMixin, self).adapt(cls, **kw)
696
697 def literal_processor(self, dialect):
698 bp = self.bind_processor(dialect)
699
700 def process(value):
701 return "'%s'" % bp(value)
702
703 return process
704
705
706class DATETIME(_DateTimeMixin, sqltypes.DateTime):
707 r"""Represent a Python datetime object in SQLite using a string.
708
709 The default string storage format is::
710
711 "%(year)04d-%(month)02d-%(day)02d %(hour)02d:%(minute)02d:%(second)02d.%(microsecond)06d"
712
713 e.g.::
714
715 2011-03-15 12:05:57.10558
716
717 The storage format can be customized to some degree using the
718 ``storage_format`` and ``regexp`` parameters, such as::
719
720 import re
721 from sqlalchemy.dialects.sqlite import DATETIME
722
723 dt = DATETIME(storage_format="%(year)04d/%(month)02d/%(day)02d "
724 "%(hour)02d:%(minute)02d:%(second)02d",
725 regexp=r"(\d+)/(\d+)/(\d+) (\d+)-(\d+)-(\d+)"
726 )
727
728 :param storage_format: format string which will be applied to the dict
729 with keys year, month, day, hour, minute, second, and microsecond.
730
731 :param regexp: regular expression which will be applied to incoming result
732 rows. If the regexp contains named groups, the resulting match dict is
733 applied to the Python datetime() constructor as keyword arguments.
734 Otherwise, if positional groups are used, the datetime() constructor
735 is called with positional arguments via
736 ``*map(int, match_obj.groups(0))``.
737
738 """ # noqa
739
740 _storage_format = (
741 "%(year)04d-%(month)02d-%(day)02d "
742 "%(hour)02d:%(minute)02d:%(second)02d.%(microsecond)06d"
743 )
744
745 def __init__(self, *args, **kwargs):
746 truncate_microseconds = kwargs.pop("truncate_microseconds", False)
747 super(DATETIME, self).__init__(*args, **kwargs)
748 if truncate_microseconds:
749 assert "storage_format" not in kwargs, (
750 "You can specify only "
751 "one of truncate_microseconds or storage_format."
752 )
753 assert "regexp" not in kwargs, (
754 "You can specify only one of "
755 "truncate_microseconds or regexp."
756 )
757 self._storage_format = (
758 "%(year)04d-%(month)02d-%(day)02d "
759 "%(hour)02d:%(minute)02d:%(second)02d"
760 )
761
762 def bind_processor(self, dialect):
763 datetime_datetime = datetime.datetime
764 datetime_date = datetime.date
765 format_ = self._storage_format
766
767 def process(value):
768 if value is None:
769 return None
770 elif isinstance(value, datetime_datetime):
771 return format_ % {
772 "year": value.year,
773 "month": value.month,
774 "day": value.day,
775 "hour": value.hour,
776 "minute": value.minute,
777 "second": value.second,
778 "microsecond": value.microsecond,
779 }
780 elif isinstance(value, datetime_date):
781 return format_ % {
782 "year": value.year,
783 "month": value.month,
784 "day": value.day,
785 "hour": 0,
786 "minute": 0,
787 "second": 0,
788 "microsecond": 0,
789 }
790 else:
791 raise TypeError(
792 "SQLite DateTime type only accepts Python "
793 "datetime and date objects as input."
794 )
795
796 return process
797
798 def result_processor(self, dialect, coltype):
799 if self._reg:
800 return processors.str_to_datetime_processor_factory(
801 self._reg, datetime.datetime
802 )
803 else:
804 return processors.str_to_datetime
805
806
807class DATE(_DateTimeMixin, sqltypes.Date):
808 r"""Represent a Python date object in SQLite using a string.
809
810 The default string storage format is::
811
812 "%(year)04d-%(month)02d-%(day)02d"
813
814 e.g.::
815
816 2011-03-15
817
818 The storage format can be customized to some degree using the
819 ``storage_format`` and ``regexp`` parameters, such as::
820
821 import re
822 from sqlalchemy.dialects.sqlite import DATE
823
824 d = DATE(
825 storage_format="%(month)02d/%(day)02d/%(year)04d",
826 regexp=re.compile("(?P<month>\d+)/(?P<day>\d+)/(?P<year>\d+)")
827 )
828
829 :param storage_format: format string which will be applied to the
830 dict with keys year, month, and day.
831
832 :param regexp: regular expression which will be applied to
833 incoming result rows. If the regexp contains named groups, the
834 resulting match dict is applied to the Python date() constructor
835 as keyword arguments. Otherwise, if positional groups are used, the
836 date() constructor is called with positional arguments via
837 ``*map(int, match_obj.groups(0))``.
838 """
839
840 _storage_format = "%(year)04d-%(month)02d-%(day)02d"
841
842 def bind_processor(self, dialect):
843 datetime_date = datetime.date
844 format_ = self._storage_format
845
846 def process(value):
847 if value is None:
848 return None
849 elif isinstance(value, datetime_date):
850 return format_ % {
851 "year": value.year,
852 "month": value.month,
853 "day": value.day,
854 }
855 else:
856 raise TypeError(
857 "SQLite Date type only accepts Python "
858 "date objects as input."
859 )
860
861 return process
862
863 def result_processor(self, dialect, coltype):
864 if self._reg:
865 return processors.str_to_datetime_processor_factory(
866 self._reg, datetime.date
867 )
868 else:
869 return processors.str_to_date
870
871
872class TIME(_DateTimeMixin, sqltypes.Time):
873 r"""Represent a Python time object in SQLite using a string.
874
875 The default string storage format is::
876
877 "%(hour)02d:%(minute)02d:%(second)02d.%(microsecond)06d"
878
879 e.g.::
880
881 12:05:57.10558
882
883 The storage format can be customized to some degree using the
884 ``storage_format`` and ``regexp`` parameters, such as::
885
886 import re
887 from sqlalchemy.dialects.sqlite import TIME
888
889 t = TIME(storage_format="%(hour)02d-%(minute)02d-"
890 "%(second)02d-%(microsecond)06d",
891 regexp=re.compile("(\d+)-(\d+)-(\d+)-(?:-(\d+))?")
892 )
893
894 :param storage_format: format string which will be applied to the dict
895 with keys hour, minute, second, and microsecond.
896
897 :param regexp: regular expression which will be applied to incoming result
898 rows. If the regexp contains named groups, the resulting match dict is
899 applied to the Python time() constructor as keyword arguments. Otherwise,
900 if positional groups are used, the time() constructor is called with
901 positional arguments via ``*map(int, match_obj.groups(0))``.
902 """
903
904 _storage_format = "%(hour)02d:%(minute)02d:%(second)02d.%(microsecond)06d"
905
906 def __init__(self, *args, **kwargs):
907 truncate_microseconds = kwargs.pop("truncate_microseconds", False)
908 super(TIME, self).__init__(*args, **kwargs)
909 if truncate_microseconds:
910 assert "storage_format" not in kwargs, (
911 "You can specify only "
912 "one of truncate_microseconds or storage_format."
913 )
914 assert "regexp" not in kwargs, (
915 "You can specify only one of "
916 "truncate_microseconds or regexp."
917 )
918 self._storage_format = "%(hour)02d:%(minute)02d:%(second)02d"
919
920 def bind_processor(self, dialect):
921 datetime_time = datetime.time
922 format_ = self._storage_format
923
924 def process(value):
925 if value is None:
926 return None
927 elif isinstance(value, datetime_time):
928 return format_ % {
929 "hour": value.hour,
930 "minute": value.minute,
931 "second": value.second,
932 "microsecond": value.microsecond,
933 }
934 else:
935 raise TypeError(
936 "SQLite Time type only accepts Python "
937 "time objects as input."
938 )
939
940 return process
941
942 def result_processor(self, dialect, coltype):
943 if self._reg:
944 return processors.str_to_datetime_processor_factory(
945 self._reg, datetime.time
946 )
947 else:
948 return processors.str_to_time
949
950
951colspecs = {
952 sqltypes.Date: DATE,
953 sqltypes.DateTime: DATETIME,
954 sqltypes.JSON: _SQliteJson,
955 sqltypes.JSON.JSONIndexType: JSONIndexType,
956 sqltypes.JSON.JSONPathType: JSONPathType,
957 sqltypes.Time: TIME,
958}
959
960ischema_names = {
961 "BIGINT": sqltypes.BIGINT,
962 "BLOB": sqltypes.BLOB,
963 "BOOL": sqltypes.BOOLEAN,
964 "BOOLEAN": sqltypes.BOOLEAN,
965 "CHAR": sqltypes.CHAR,
966 "DATE": sqltypes.DATE,
967 "DATE_CHAR": sqltypes.DATE,
968 "DATETIME": sqltypes.DATETIME,
969 "DATETIME_CHAR": sqltypes.DATETIME,
970 "DOUBLE": sqltypes.FLOAT,
971 "DECIMAL": sqltypes.DECIMAL,
972 "FLOAT": sqltypes.FLOAT,
973 "INT": sqltypes.INTEGER,
974 "INTEGER": sqltypes.INTEGER,
975 "JSON": JSON,
976 "NUMERIC": sqltypes.NUMERIC,
977 "REAL": sqltypes.REAL,
978 "SMALLINT": sqltypes.SMALLINT,
979 "TEXT": sqltypes.TEXT,
980 "TIME": sqltypes.TIME,
981 "TIME_CHAR": sqltypes.TIME,
982 "TIMESTAMP": sqltypes.TIMESTAMP,
983 "VARCHAR": sqltypes.VARCHAR,
984 "NVARCHAR": sqltypes.NVARCHAR,
985 "NCHAR": sqltypes.NCHAR,
986}
987
988
989class SQLiteCompiler(compiler.SQLCompiler):
990 extract_map = util.update_copy(
991 compiler.SQLCompiler.extract_map,
992 {
993 "month": "%m",
994 "day": "%d",
995 "year": "%Y",
996 "second": "%S",
997 "hour": "%H",
998 "doy": "%j",
999 "minute": "%M",
1000 "epoch": "%s",
1001 "dow": "%w",
1002 "week": "%W",
1003 },
1004 )
1005
1006 def visit_now_func(self, fn, **kw):
1007 return "CURRENT_TIMESTAMP"
1008
1009 def visit_localtimestamp_func(self, func, **kw):
1010 return 'DATETIME(CURRENT_TIMESTAMP, "localtime")'
1011
1012 def visit_true(self, expr, **kw):
1013 return "1"
1014
1015 def visit_false(self, expr, **kw):
1016 return "0"
1017
1018 def visit_char_length_func(self, fn, **kw):
1019 return "length%s" % self.function_argspec(fn)
1020
1021 def visit_cast(self, cast, **kwargs):
1022 if self.dialect.supports_cast:
1023 return super(SQLiteCompiler, self).visit_cast(cast, **kwargs)
1024 else:
1025 return self.process(cast.clause, **kwargs)
1026
1027 def visit_extract(self, extract, **kw):
1028 try:
1029 return "CAST(STRFTIME('%s', %s) AS INTEGER)" % (
1030 self.extract_map[extract.field],
1031 self.process(extract.expr, **kw),
1032 )
1033 except KeyError as err:
1034 util.raise_(
1035 exc.CompileError(
1036 "%s is not a valid extract argument." % extract.field
1037 ),
1038 replace_context=err,
1039 )
1040
1041 def limit_clause(self, select, **kw):
1042 text = ""
1043 if select._limit_clause is not None:
1044 text += "\n LIMIT " + self.process(select._limit_clause, **kw)
1045 if select._offset_clause is not None:
1046 if select._limit_clause is None:
1047 text += "\n LIMIT " + self.process(sql.literal(-1))
1048 text += " OFFSET " + self.process(select._offset_clause, **kw)
1049 else:
1050 text += " OFFSET " + self.process(sql.literal(0), **kw)
1051 return text
1052
1053 def for_update_clause(self, select, **kw):
1054 # sqlite has no "FOR UPDATE" AFAICT
1055 return ""
1056
1057 def visit_is_distinct_from_binary(self, binary, operator, **kw):
1058 return "%s IS NOT %s" % (
1059 self.process(binary.left),
1060 self.process(binary.right),
1061 )
1062
1063 def visit_isnot_distinct_from_binary(self, binary, operator, **kw):
1064 return "%s IS %s" % (
1065 self.process(binary.left),
1066 self.process(binary.right),
1067 )
1068
1069 def visit_json_getitem_op_binary(self, binary, operator, **kw):
1070 if binary.type._type_affinity is sqltypes.JSON:
1071 expr = "JSON_QUOTE(JSON_EXTRACT(%s, %s))"
1072 else:
1073 expr = "JSON_EXTRACT(%s, %s)"
1074
1075 return expr % (
1076 self.process(binary.left, **kw),
1077 self.process(binary.right, **kw),
1078 )
1079
1080 def visit_json_path_getitem_op_binary(self, binary, operator, **kw):
1081 if binary.type._type_affinity is sqltypes.JSON:
1082 expr = "JSON_QUOTE(JSON_EXTRACT(%s, %s))"
1083 else:
1084 expr = "JSON_EXTRACT(%s, %s)"
1085
1086 return expr % (
1087 self.process(binary.left, **kw),
1088 self.process(binary.right, **kw),
1089 )
1090
1091 def visit_empty_set_expr(self, element_types):
1092 return "SELECT %s FROM (SELECT %s) WHERE 1!=1" % (
1093 ", ".join("1" for type_ in element_types or [INTEGER()]),
1094 ", ".join("1" for type_ in element_types or [INTEGER()]),
1095 )
1096
1097
1098class SQLiteDDLCompiler(compiler.DDLCompiler):
1099 def get_column_specification(self, column, **kwargs):
1100
1101 coltype = self.dialect.type_compiler.process(
1102 column.type, type_expression=column
1103 )
1104 colspec = self.preparer.format_column(column) + " " + coltype
1105 default = self.get_column_default_string(column)
1106 if default is not None:
1107 if isinstance(column.server_default.arg, ColumnElement):
1108 default = "(" + default + ")"
1109 colspec += " DEFAULT " + default
1110
1111 if not column.nullable:
1112 colspec += " NOT NULL"
1113
1114 on_conflict_clause = column.dialect_options["sqlite"][
1115 "on_conflict_not_null"
1116 ]
1117 if on_conflict_clause is not None:
1118 colspec += " ON CONFLICT " + on_conflict_clause
1119
1120 if column.primary_key:
1121 if (
1122 column.autoincrement is True
1123 and len(column.table.primary_key.columns) != 1
1124 ):
1125 raise exc.CompileError(
1126 "SQLite does not support autoincrement for "
1127 "composite primary keys"
1128 )
1129
1130 if (
1131 column.table.dialect_options["sqlite"]["autoincrement"]
1132 and len(column.table.primary_key.columns) == 1
1133 and issubclass(column.type._type_affinity, sqltypes.Integer)
1134 and not column.foreign_keys
1135 ):
1136 colspec += " PRIMARY KEY"
1137
1138 on_conflict_clause = column.dialect_options["sqlite"][
1139 "on_conflict_primary_key"
1140 ]
1141 if on_conflict_clause is not None:
1142 colspec += " ON CONFLICT " + on_conflict_clause
1143
1144 colspec += " AUTOINCREMENT"
1145
1146 if column.computed is not None:
1147 colspec += " " + self.process(column.computed)
1148
1149 return colspec
1150
1151 def visit_primary_key_constraint(self, constraint):
1152 # for columns with sqlite_autoincrement=True,
1153 # the PRIMARY KEY constraint can only be inline
1154 # with the column itself.
1155 if len(constraint.columns) == 1:
1156 c = list(constraint)[0]
1157 if (
1158 c.primary_key
1159 and c.table.dialect_options["sqlite"]["autoincrement"]
1160 and issubclass(c.type._type_affinity, sqltypes.Integer)
1161 and not c.foreign_keys
1162 ):
1163 return None
1164
1165 text = super(SQLiteDDLCompiler, self).visit_primary_key_constraint(
1166 constraint
1167 )
1168
1169 on_conflict_clause = constraint.dialect_options["sqlite"][
1170 "on_conflict"
1171 ]
1172 if on_conflict_clause is None and len(constraint.columns) == 1:
1173 on_conflict_clause = list(constraint)[0].dialect_options["sqlite"][
1174 "on_conflict_primary_key"
1175 ]
1176
1177 if on_conflict_clause is not None:
1178 text += " ON CONFLICT " + on_conflict_clause
1179
1180 return text
1181
1182 def visit_unique_constraint(self, constraint):
1183 text = super(SQLiteDDLCompiler, self).visit_unique_constraint(
1184 constraint
1185 )
1186
1187 on_conflict_clause = constraint.dialect_options["sqlite"][
1188 "on_conflict"
1189 ]
1190 if on_conflict_clause is None and len(constraint.columns) == 1:
1191 col1 = list(constraint)[0]
1192 if isinstance(col1, schema.SchemaItem):
1193 on_conflict_clause = list(constraint)[0].dialect_options[
1194 "sqlite"
1195 ]["on_conflict_unique"]
1196
1197 if on_conflict_clause is not None:
1198 text += " ON CONFLICT " + on_conflict_clause
1199
1200 return text
1201
1202 def visit_check_constraint(self, constraint):
1203 text = super(SQLiteDDLCompiler, self).visit_check_constraint(
1204 constraint
1205 )
1206
1207 on_conflict_clause = constraint.dialect_options["sqlite"][
1208 "on_conflict"
1209 ]
1210
1211 if on_conflict_clause is not None:
1212 text += " ON CONFLICT " + on_conflict_clause
1213
1214 return text
1215
1216 def visit_column_check_constraint(self, constraint):
1217 text = super(SQLiteDDLCompiler, self).visit_column_check_constraint(
1218 constraint
1219 )
1220
1221 if constraint.dialect_options["sqlite"]["on_conflict"] is not None:
1222 raise exc.CompileError(
1223 "SQLite does not support on conflict clause for "
1224 "column check constraint"
1225 )
1226
1227 return text
1228
1229 def visit_foreign_key_constraint(self, constraint):
1230
1231 local_table = constraint.elements[0].parent.table
1232 remote_table = constraint.elements[0].column.table
1233
1234 if local_table.schema != remote_table.schema:
1235 return None
1236 else:
1237 return super(SQLiteDDLCompiler, self).visit_foreign_key_constraint(
1238 constraint
1239 )
1240
1241 def define_constraint_remote_table(self, constraint, table, preparer):
1242 """Format the remote table clause of a CREATE CONSTRAINT clause."""
1243
1244 return preparer.format_table(table, use_schema=False)
1245
1246 def visit_create_index(
1247 self, create, include_schema=False, include_table_schema=True
1248 ):
1249 index = create.element
1250 self._verify_index_table(index)
1251 preparer = self.preparer
1252 text = "CREATE "
1253 if index.unique:
1254 text += "UNIQUE "
1255 text += "INDEX %s ON %s (%s)" % (
1256 self._prepared_index_name(index, include_schema=True),
1257 preparer.format_table(index.table, use_schema=False),
1258 ", ".join(
1259 self.sql_compiler.process(
1260 expr, include_table=False, literal_binds=True
1261 )
1262 for expr in index.expressions
1263 ),
1264 )
1265
1266 whereclause = index.dialect_options["sqlite"]["where"]
1267 if whereclause is not None:
1268 where_compiled = self.sql_compiler.process(
1269 whereclause, include_table=False, literal_binds=True
1270 )
1271 text += " WHERE " + where_compiled
1272
1273 return text
1274
1275 def post_create_table(self, table):
1276 if table.dialect_options["sqlite"]["with_rowid"] is False:
1277 return "\n WITHOUT ROWID"
1278 return ""
1279
1280
1281class SQLiteTypeCompiler(compiler.GenericTypeCompiler):
1282 def visit_large_binary(self, type_, **kw):
1283 return self.visit_BLOB(type_)
1284
1285 def visit_DATETIME(self, type_, **kw):
1286 if (
1287 not isinstance(type_, _DateTimeMixin)
1288 or type_.format_is_text_affinity
1289 ):
1290 return super(SQLiteTypeCompiler, self).visit_DATETIME(type_)
1291 else:
1292 return "DATETIME_CHAR"
1293
1294 def visit_DATE(self, type_, **kw):
1295 if (
1296 not isinstance(type_, _DateTimeMixin)
1297 or type_.format_is_text_affinity
1298 ):
1299 return super(SQLiteTypeCompiler, self).visit_DATE(type_)
1300 else:
1301 return "DATE_CHAR"
1302
1303 def visit_TIME(self, type_, **kw):
1304 if (
1305 not isinstance(type_, _DateTimeMixin)
1306 or type_.format_is_text_affinity
1307 ):
1308 return super(SQLiteTypeCompiler, self).visit_TIME(type_)
1309 else:
1310 return "TIME_CHAR"
1311
1312 def visit_JSON(self, type_, **kw):
1313 # note this name provides NUMERIC affinity, not TEXT.
1314 # should not be an issue unless the JSON value consists of a single
1315 # numeric value. JSONTEXT can be used if this case is required.
1316 return "JSON"
1317
1318
1319class SQLiteIdentifierPreparer(compiler.IdentifierPreparer):
1320 reserved_words = set(
1321 [
1322 "add",
1323 "after",
1324 "all",
1325 "alter",
1326 "analyze",
1327 "and",
1328 "as",
1329 "asc",
1330 "attach",
1331 "autoincrement",
1332 "before",
1333 "begin",
1334 "between",
1335 "by",
1336 "cascade",
1337 "case",
1338 "cast",
1339 "check",
1340 "collate",
1341 "column",
1342 "commit",
1343 "conflict",
1344 "constraint",
1345 "create",
1346 "cross",
1347 "current_date",
1348 "current_time",
1349 "current_timestamp",
1350 "database",
1351 "default",
1352 "deferrable",
1353 "deferred",
1354 "delete",
1355 "desc",
1356 "detach",
1357 "distinct",
1358 "drop",
1359 "each",
1360 "else",
1361 "end",
1362 "escape",
1363 "except",
1364 "exclusive",
1365 "exists",
1366 "explain",
1367 "false",
1368 "fail",
1369 "for",
1370 "foreign",
1371 "from",
1372 "full",
1373 "glob",
1374 "group",
1375 "having",
1376 "if",
1377 "ignore",
1378 "immediate",
1379 "in",
1380 "index",
1381 "indexed",
1382 "initially",
1383 "inner",
1384 "insert",
1385 "instead",
1386 "intersect",
1387 "into",
1388 "is",
1389 "isnull",
1390 "join",
1391 "key",
1392 "left",
1393 "like",
1394 "limit",
1395 "match",
1396 "natural",
1397 "not",
1398 "notnull",
1399 "null",
1400 "of",
1401 "offset",
1402 "on",
1403 "or",
1404 "order",
1405 "outer",
1406 "plan",
1407 "pragma",
1408 "primary",
1409 "query",
1410 "raise",
1411 "references",
1412 "reindex",
1413 "rename",
1414 "replace",
1415 "restrict",
1416 "right",
1417 "rollback",
1418 "row",
1419 "select",
1420 "set",
1421 "table",
1422 "temp",
1423 "temporary",
1424 "then",
1425 "to",
1426 "transaction",
1427 "trigger",
1428 "true",
1429 "union",
1430 "unique",
1431 "update",
1432 "using",
1433 "vacuum",
1434 "values",
1435 "view",
1436 "virtual",
1437 "when",
1438 "where",
1439 ]
1440 )
1441
1442
1443class SQLiteExecutionContext(default.DefaultExecutionContext):
1444 @util.memoized_property
1445 def _preserve_raw_colnames(self):
1446 return (
1447 not self.dialect._broken_dotted_colnames
1448 or self.execution_options.get("sqlite_raw_colnames", False)
1449 )
1450
1451 def _translate_colname(self, colname):
1452 # TODO: detect SQLite version 3.10.0 or greater;
1453 # see [ticket:3633]
1454
1455 # adjust for dotted column names. SQLite
1456 # in the case of UNION may store col names as
1457 # "tablename.colname", or if using an attached database,
1458 # "database.tablename.colname", in cursor.description
1459 if not self._preserve_raw_colnames and "." in colname:
1460 return colname.split(".")[-1], colname
1461 else:
1462 return colname, None
1463
1464
1465class SQLiteDialect(default.DefaultDialect):
1466 name = "sqlite"
1467 supports_alter = False
1468 supports_unicode_statements = True
1469 supports_unicode_binds = True
1470 supports_default_values = True
1471 supports_empty_insert = False
1472 supports_cast = True
1473 supports_multivalues_insert = True
1474 tuple_in_values = True
1475
1476 default_paramstyle = "qmark"
1477 execution_ctx_cls = SQLiteExecutionContext
1478 statement_compiler = SQLiteCompiler
1479 ddl_compiler = SQLiteDDLCompiler
1480 type_compiler = SQLiteTypeCompiler
1481 preparer = SQLiteIdentifierPreparer
1482 ischema_names = ischema_names
1483 colspecs = colspecs
1484 isolation_level = None
1485
1486 construct_arguments = [
1487 (
1488 sa_schema.Table,
1489 {
1490 "autoincrement": False,
1491 "with_rowid": True,
1492 },
1493 ),
1494 (sa_schema.Index, {"where": None}),
1495 (
1496 sa_schema.Column,
1497 {
1498 "on_conflict_primary_key": None,
1499 "on_conflict_not_null": None,
1500 "on_conflict_unique": None,
1501 },
1502 ),
1503 (sa_schema.Constraint, {"on_conflict": None}),
1504 ]
1505
1506 _broken_fk_pragma_quotes = False
1507 _broken_dotted_colnames = False
1508
1509 @util.deprecated_params(
1510 _json_serializer=(
1511 "1.3.7",
1512 "The _json_serializer argument to the SQLite dialect has "
1513 "been renamed to the correct name of json_serializer. The old "
1514 "argument name will be removed in a future release.",
1515 ),
1516 _json_deserializer=(
1517 "1.3.7",
1518 "The _json_deserializer argument to the SQLite dialect has "
1519 "been renamed to the correct name of json_deserializer. The old "
1520 "argument name will be removed in a future release.",
1521 ),
1522 )
1523 def __init__(
1524 self,
1525 isolation_level=None,
1526 native_datetime=False,
1527 json_serializer=None,
1528 json_deserializer=None,
1529 _json_serializer=None,
1530 _json_deserializer=None,
1531 **kwargs
1532 ):
1533 default.DefaultDialect.__init__(self, **kwargs)
1534 self.isolation_level = isolation_level
1535
1536 if _json_serializer:
1537 json_serializer = _json_serializer
1538 if _json_deserializer:
1539 json_deserializer = _json_deserializer
1540 self._json_serializer = json_serializer
1541 self._json_deserializer = json_deserializer
1542
1543 # this flag used by pysqlite dialect, and perhaps others in the
1544 # future, to indicate the driver is handling date/timestamp
1545 # conversions (and perhaps datetime/time as well on some hypothetical
1546 # driver ?)
1547 self.native_datetime = native_datetime
1548
1549 if self.dbapi is not None:
1550 self.supports_right_nested_joins = (
1551 self.dbapi.sqlite_version_info >= (3, 7, 16)
1552 )
1553 self._broken_dotted_colnames = self.dbapi.sqlite_version_info < (
1554 3,
1555 10,
1556 0,
1557 )
1558 self.supports_default_values = self.dbapi.sqlite_version_info >= (
1559 3,
1560 3,
1561 8,
1562 )
1563 self.supports_cast = self.dbapi.sqlite_version_info >= (3, 2, 3)
1564 self.supports_multivalues_insert = (
1565 # http://www.sqlite.org/releaselog/3_7_11.html
1566 self.dbapi.sqlite_version_info
1567 >= (3, 7, 11)
1568 )
1569 # see http://www.sqlalchemy.org/trac/ticket/2568
1570 # as well as http://www.sqlite.org/src/info/600482d161
1571 self._broken_fk_pragma_quotes = self.dbapi.sqlite_version_info < (
1572 3,
1573 6,
1574 14,
1575 )
1576
1577 _isolation_lookup = {"READ UNCOMMITTED": 1, "SERIALIZABLE": 0}
1578
1579 def set_isolation_level(self, connection, level):
1580 try:
1581 isolation_level = self._isolation_lookup[level.replace("_", " ")]
1582 except KeyError as err:
1583 util.raise_(
1584 exc.ArgumentError(
1585 "Invalid value '%s' for isolation_level. "
1586 "Valid isolation levels for %s are %s"
1587 % (level, self.name, ", ".join(self._isolation_lookup))
1588 ),
1589 replace_context=err,
1590 )
1591 cursor = connection.cursor()
1592 cursor.execute("PRAGMA read_uncommitted = %d" % isolation_level)
1593 cursor.close()
1594
1595 def get_isolation_level(self, connection):
1596 cursor = connection.cursor()
1597 cursor.execute("PRAGMA read_uncommitted")
1598 res = cursor.fetchone()
1599 if res:
1600 value = res[0]
1601 else:
1602 # http://www.sqlite.org/changes.html#version_3_3_3
1603 # "Optional READ UNCOMMITTED isolation (instead of the
1604 # default isolation level of SERIALIZABLE) and
1605 # table level locking when database connections
1606 # share a common cache.""
1607 # pre-SQLite 3.3.0 default to 0
1608 value = 0
1609 cursor.close()
1610 if value == 0:
1611 return "SERIALIZABLE"
1612 elif value == 1:
1613 return "READ UNCOMMITTED"
1614 else:
1615 assert False, "Unknown isolation level %s" % value
1616
1617 def on_connect(self):
1618 if self.isolation_level is not None:
1619
1620 def connect(conn):
1621 self.set_isolation_level(conn, self.isolation_level)
1622
1623 return connect
1624 else:
1625 return None
1626
1627 @reflection.cache
1628 def get_schema_names(self, connection, **kw):
1629 s = "PRAGMA database_list"
1630 dl = connection.execute(s)
1631
1632 return [db[1] for db in dl if db[1] != "temp"]
1633
1634 @reflection.cache
1635 def get_table_names(self, connection, schema=None, **kw):
1636 if schema is not None:
1637 qschema = self.identifier_preparer.quote_identifier(schema)
1638 master = "%s.sqlite_master" % qschema
1639 else:
1640 master = "sqlite_master"
1641 s = ("SELECT name FROM %s " "WHERE type='table' ORDER BY name") % (
1642 master,
1643 )
1644 rs = connection.execute(s)
1645 return [row[0] for row in rs]
1646
1647 @reflection.cache
1648 def get_temp_table_names(self, connection, **kw):
1649 s = (
1650 "SELECT name FROM sqlite_temp_master "
1651 "WHERE type='table' ORDER BY name "
1652 )
1653 rs = connection.execute(s)
1654
1655 return [row[0] for row in rs]
1656
1657 @reflection.cache
1658 def get_temp_view_names(self, connection, **kw):
1659 s = (
1660 "SELECT name FROM sqlite_temp_master "
1661 "WHERE type='view' ORDER BY name "
1662 )
1663 rs = connection.execute(s)
1664
1665 return [row[0] for row in rs]
1666
1667 def has_table(self, connection, table_name, schema=None):
1668 info = self._get_table_pragma(
1669 connection, "table_info", table_name, schema=schema
1670 )
1671 return bool(info)
1672
1673 @reflection.cache
1674 def get_view_names(self, connection, schema=None, **kw):
1675 if schema is not None:
1676 qschema = self.identifier_preparer.quote_identifier(schema)
1677 master = "%s.sqlite_master" % qschema
1678 else:
1679 master = "sqlite_master"
1680 s = ("SELECT name FROM %s " "WHERE type='view' ORDER BY name") % (
1681 master,
1682 )
1683 rs = connection.execute(s)
1684
1685 return [row[0] for row in rs]
1686
1687 @reflection.cache
1688 def get_view_definition(self, connection, view_name, schema=None, **kw):
1689 if schema is not None:
1690 qschema = self.identifier_preparer.quote_identifier(schema)
1691 master = "%s.sqlite_master" % qschema
1692 s = ("SELECT sql FROM %s WHERE name = ? AND type='view'") % (
1693 master,
1694 )
1695 rs = connection.execute(s, (view_name,))
1696 else:
1697 try:
1698 s = (
1699 "SELECT sql FROM "
1700 " (SELECT * FROM sqlite_master UNION ALL "
1701 " SELECT * FROM sqlite_temp_master) "
1702 "WHERE name = ? "
1703 "AND type='view'"
1704 )
1705 rs = connection.execute(s, (view_name,))
1706 except exc.DBAPIError:
1707 s = (
1708 "SELECT sql FROM sqlite_master WHERE name = ? "
1709 "AND type='view'"
1710 )
1711 rs = connection.execute(s, (view_name,))
1712
1713 result = rs.fetchall()
1714 if result:
1715 return result[0].sql
1716
1717 @reflection.cache
1718 def get_columns(self, connection, table_name, schema=None, **kw):
1719 pragma = "table_info"
1720 # computed columns are threaded as hidden, they require table_xinfo
1721 if self.server_version_info >= (3, 31):
1722 pragma = "table_xinfo"
1723 info = self._get_table_pragma(
1724 connection, pragma, table_name, schema=schema
1725 )
1726 columns = []
1727 tablesql = None
1728 for row in info:
1729 name = row[1]
1730 type_ = row[2].upper()
1731 nullable = not row[3]
1732 default = row[4]
1733 primary_key = row[5]
1734 hidden = row[6] if pragma == "table_xinfo" else 0
1735
1736 # hidden has value 0 for normal columns, 1 for hidden columns,
1737 # 2 for computed virtual columns and 3 for computed stored columns
1738 # https://www.sqlite.org/src/info/069351b85f9a706f60d3e98fbc8aaf40c374356b967c0464aede30ead3d9d18b
1739 if hidden == 1:
1740 continue
1741
1742 generated = bool(hidden)
1743 persisted = hidden == 3
1744
1745 if tablesql is None and generated:
1746 tablesql = self._get_table_sql(
1747 connection, table_name, schema, **kw
1748 )
1749
1750 columns.append(
1751 self._get_column_info(
1752 name,
1753 type_,
1754 nullable,
1755 default,
1756 primary_key,
1757 generated,
1758 persisted,
1759 tablesql,
1760 )
1761 )
1762 return columns
1763
1764 def _get_column_info(
1765 self,
1766 name,
1767 type_,
1768 nullable,
1769 default,
1770 primary_key,
1771 generated,
1772 persisted,
1773 tablesql,
1774 ):
1775
1776 if generated:
1777 # the type of a column "cc INTEGER GENERATED ALWAYS AS (1 + 42)"
1778 # somehow is "INTEGER GENERATED ALWAYS"
1779 type_ = re.sub("generated", "", type_, flags=re.IGNORECASE)
1780 type_ = re.sub("always", "", type_, flags=re.IGNORECASE).strip()
1781
1782 coltype = self._resolve_type_affinity(type_)
1783
1784 if default is not None:
1785 default = util.text_type(default)
1786
1787 colspec = {
1788 "name": name,
1789 "type": coltype,
1790 "nullable": nullable,
1791 "default": default,
1792 "autoincrement": "auto",
1793 "primary_key": primary_key,
1794 }
1795 if generated:
1796 sqltext = ""
1797 if tablesql:
1798 pattern = r"[^,]*\s+AS\s+\(([^,]*)\)\s*(?:virtual|stored)?"
1799 match = re.search(
1800 re.escape(name) + pattern, tablesql, re.IGNORECASE
1801 )
1802 if match:
1803 sqltext = match.group(1)
1804 colspec["computed"] = {"sqltext": sqltext, "persisted": persisted}
1805 return colspec
1806
1807 def _resolve_type_affinity(self, type_):
1808 """Return a data type from a reflected column, using affinity tules.
1809
1810 SQLite's goal for universal compatibility introduces some complexity
1811 during reflection, as a column's defined type might not actually be a
1812 type that SQLite understands - or indeed, my not be defined *at all*.
1813 Internally, SQLite handles this with a 'data type affinity' for each
1814 column definition, mapping to one of 'TEXT', 'NUMERIC', 'INTEGER',
1815 'REAL', or 'NONE' (raw bits). The algorithm that determines this is
1816 listed in http://www.sqlite.org/datatype3.html section 2.1.
1817
1818 This method allows SQLAlchemy to support that algorithm, while still
1819 providing access to smarter reflection utilities by regcognizing
1820 column definitions that SQLite only supports through affinity (like
1821 DATE and DOUBLE).
1822
1823 """
1824 match = re.match(r"([\w ]+)(\(.*?\))?", type_)
1825 if match:
1826 coltype = match.group(1)
1827 args = match.group(2)
1828 else:
1829 coltype = ""
1830 args = ""
1831
1832 if coltype in self.ischema_names:
1833 coltype = self.ischema_names[coltype]
1834 elif "INT" in coltype:
1835 coltype = sqltypes.INTEGER
1836 elif "CHAR" in coltype or "CLOB" in coltype or "TEXT" in coltype:
1837 coltype = sqltypes.TEXT
1838 elif "BLOB" in coltype or not coltype:
1839 coltype = sqltypes.NullType
1840 elif "REAL" in coltype or "FLOA" in coltype or "DOUB" in coltype:
1841 coltype = sqltypes.REAL
1842 else:
1843 coltype = sqltypes.NUMERIC
1844
1845 if args is not None:
1846 args = re.findall(r"(\d+)", args)
1847 try:
1848 coltype = coltype(*[int(a) for a in args])
1849 except TypeError:
1850 util.warn(
1851 "Could not instantiate type %s with "
1852 "reflected arguments %s; using no arguments."
1853 % (coltype, args)
1854 )
1855 coltype = coltype()
1856 else:
1857 coltype = coltype()
1858
1859 return coltype
1860
1861 @reflection.cache
1862 def get_pk_constraint(self, connection, table_name, schema=None, **kw):
1863 constraint_name = None
1864 table_data = self._get_table_sql(connection, table_name, schema=schema)
1865 if table_data:
1866 PK_PATTERN = r"CONSTRAINT (\w+) PRIMARY KEY"
1867 result = re.search(PK_PATTERN, table_data, re.I)
1868 constraint_name = result.group(1) if result else None
1869
1870 cols = self.get_columns(connection, table_name, schema, **kw)
1871 cols.sort(key=lambda col: col.get("primary_key"))
1872 pkeys = []
1873 for col in cols:
1874 if col["primary_key"]:
1875 pkeys.append(col["name"])
1876
1877 return {"constrained_columns": pkeys, "name": constraint_name}
1878
1879 @reflection.cache
1880 def get_foreign_keys(self, connection, table_name, schema=None, **kw):
1881 # sqlite makes this *extremely difficult*.
1882 # First, use the pragma to get the actual FKs.
1883 pragma_fks = self._get_table_pragma(
1884 connection, "foreign_key_list", table_name, schema=schema
1885 )
1886
1887 fks = {}
1888
1889 for row in pragma_fks:
1890 (numerical_id, rtbl, lcol, rcol) = (row[0], row[2], row[3], row[4])
1891
1892 if not rcol:
1893 # no referred column, which means it was not named in the
1894 # original DDL. The referred columns of the foreign key
1895 # constraint are therefore the primary key of the referred
1896 # table.
1897 referred_pk = self.get_pk_constraint(
1898 connection, rtbl, schema=schema, **kw
1899 )
1900 # note that if table doesnt exist, we still get back a record,
1901 # just it has no columns in it
1902 referred_columns = referred_pk["constrained_columns"]
1903 else:
1904 # note we use this list only if this is the first column
1905 # in the constraint. for subsequent columns we ignore the
1906 # list and append "rcol" if present.
1907 referred_columns = []
1908
1909 if self._broken_fk_pragma_quotes:
1910 rtbl = re.sub(r"^[\"\[`\']|[\"\]`\']$", "", rtbl)
1911
1912 if numerical_id in fks:
1913 fk = fks[numerical_id]
1914 else:
1915 fk = fks[numerical_id] = {
1916 "name": None,
1917 "constrained_columns": [],
1918 "referred_schema": schema,
1919 "referred_table": rtbl,
1920 "referred_columns": referred_columns,
1921 "options": {},
1922 }
1923 fks[numerical_id] = fk
1924
1925 fk["constrained_columns"].append(lcol)
1926
1927 if rcol:
1928 fk["referred_columns"].append(rcol)
1929
1930 def fk_sig(constrained_columns, referred_table, referred_columns):
1931 return (
1932 tuple(constrained_columns)
1933 + (referred_table,)
1934 + tuple(referred_columns)
1935 )
1936
1937 # then, parse the actual SQL and attempt to find DDL that matches
1938 # the names as well. SQLite saves the DDL in whatever format
1939 # it was typed in as, so need to be liberal here.
1940
1941 keys_by_signature = dict(
1942 (
1943 fk_sig(
1944 fk["constrained_columns"],
1945 fk["referred_table"],
1946 fk["referred_columns"],
1947 ),
1948 fk,
1949 )
1950 for fk in fks.values()
1951 )
1952
1953 table_data = self._get_table_sql(connection, table_name, schema=schema)
1954 if table_data is None:
1955 # system tables, etc.
1956 return []
1957
1958 def parse_fks():
1959 FK_PATTERN = (
1960 r"(?:CONSTRAINT (\w+) +)?"
1961 r"FOREIGN KEY *\( *(.+?) *\) +"
1962 r'REFERENCES +(?:(?:"(.+?)")|([a-z0-9_]+)) *\((.+?)\) *'
1963 r"((?:ON (?:DELETE|UPDATE) "
1964 r"(?:SET NULL|SET DEFAULT|CASCADE|RESTRICT|NO ACTION) *)*)"
1965 )
1966 for match in re.finditer(FK_PATTERN, table_data, re.I):
1967 (
1968 constraint_name,
1969 constrained_columns,
1970 referred_quoted_name,
1971 referred_name,
1972 referred_columns,
1973 onupdatedelete,
1974 ) = match.group(1, 2, 3, 4, 5, 6)
1975 constrained_columns = list(
1976 self._find_cols_in_sig(constrained_columns)
1977 )
1978 if not referred_columns:
1979 referred_columns = constrained_columns
1980 else:
1981 referred_columns = list(
1982 self._find_cols_in_sig(referred_columns)
1983 )
1984 referred_name = referred_quoted_name or referred_name
1985 options = {}
1986
1987 for token in re.split(r" *\bON\b *", onupdatedelete.upper()):
1988 if token.startswith("DELETE"):
1989 options["ondelete"] = token[6:].strip()
1990 elif token.startswith("UPDATE"):
1991 options["onupdate"] = token[6:].strip()
1992 yield (
1993 constraint_name,
1994 constrained_columns,
1995 referred_name,
1996 referred_columns,
1997 options,
1998 )
1999
2000 fkeys = []
2001
2002 for (
2003 constraint_name,
2004 constrained_columns,
2005 referred_name,
2006 referred_columns,
2007 options,
2008 ) in parse_fks():
2009 sig = fk_sig(constrained_columns, referred_name, referred_columns)
2010 if sig not in keys_by_signature:
2011 util.warn(
2012 "WARNING: SQL-parsed foreign key constraint "
2013 "'%s' could not be located in PRAGMA "
2014 "foreign_keys for table %s" % (sig, table_name)
2015 )
2016 continue
2017 key = keys_by_signature.pop(sig)
2018 key["name"] = constraint_name
2019 key["options"] = options
2020 fkeys.append(key)
2021 # assume the remainders are the unnamed, inline constraints, just
2022 # use them as is as it's extremely difficult to parse inline
2023 # constraints
2024 fkeys.extend(keys_by_signature.values())
2025 return fkeys
2026
2027 def _find_cols_in_sig(self, sig):
2028 for match in re.finditer(r'(?:"(.+?)")|([a-z0-9_]+)', sig, re.I):
2029 yield match.group(1) or match.group(2)
2030
2031 @reflection.cache
2032 def get_unique_constraints(
2033 self, connection, table_name, schema=None, **kw
2034 ):
2035
2036 auto_index_by_sig = {}
2037 for idx in self.get_indexes(
2038 connection,
2039 table_name,
2040 schema=schema,
2041 include_auto_indexes=True,
2042 **kw
2043 ):
2044 if not idx["name"].startswith("sqlite_autoindex"):
2045 continue
2046 sig = tuple(idx["column_names"])
2047 auto_index_by_sig[sig] = idx
2048
2049 table_data = self._get_table_sql(
2050 connection, table_name, schema=schema, **kw
2051 )
2052 if not table_data:
2053 return []
2054
2055 unique_constraints = []
2056
2057 def parse_uqs():
2058 UNIQUE_PATTERN = r'(?:CONSTRAINT "?(.+?)"? +)?UNIQUE *\((.+?)\)'
2059 INLINE_UNIQUE_PATTERN = (
2060 r'(?:(".+?")|([a-z0-9]+)) ' r"+[a-z0-9_ ]+? +UNIQUE"
2061 )
2062
2063 for match in re.finditer(UNIQUE_PATTERN, table_data, re.I):
2064 name, cols = match.group(1, 2)
2065 yield name, list(self._find_cols_in_sig(cols))
2066
2067 # we need to match inlines as well, as we seek to differentiate
2068 # a UNIQUE constraint from a UNIQUE INDEX, even though these
2069 # are kind of the same thing :)
2070 for match in re.finditer(INLINE_UNIQUE_PATTERN, table_data, re.I):
2071 cols = list(
2072 self._find_cols_in_sig(match.group(1) or match.group(2))
2073 )
2074 yield None, cols
2075
2076 for name, cols in parse_uqs():
2077 sig = tuple(cols)
2078 if sig in auto_index_by_sig:
2079 auto_index_by_sig.pop(sig)
2080 parsed_constraint = {"name": name, "column_names": cols}
2081 unique_constraints.append(parsed_constraint)
2082 # NOTE: auto_index_by_sig might not be empty here,
2083 # the PRIMARY KEY may have an entry.
2084 return unique_constraints
2085
2086 @reflection.cache
2087 def get_check_constraints(self, connection, table_name, schema=None, **kw):
2088 table_data = self._get_table_sql(
2089 connection, table_name, schema=schema, **kw
2090 )
2091 if not table_data:
2092 return []
2093
2094 CHECK_PATTERN = r"(?:CONSTRAINT (\w+) +)?" r"CHECK *\( *(.+) *\),? *"
2095 check_constraints = []
2096 # NOTE: we aren't using re.S here because we actually are
2097 # taking advantage of each CHECK constraint being all on one
2098 # line in the table definition in order to delineate. This
2099 # necessarily makes assumptions as to how the CREATE TABLE
2100 # was emitted.
2101 for match in re.finditer(CHECK_PATTERN, table_data, re.I):
2102 check_constraints.append(
2103 {"sqltext": match.group(2), "name": match.group(1)}
2104 )
2105
2106 return check_constraints
2107
2108 @reflection.cache
2109 def get_indexes(self, connection, table_name, schema=None, **kw):
2110 pragma_indexes = self._get_table_pragma(
2111 connection, "index_list", table_name, schema=schema
2112 )
2113 indexes = []
2114
2115 include_auto_indexes = kw.pop("include_auto_indexes", False)
2116 for row in pragma_indexes:
2117 # ignore implicit primary key index.
2118 # http://www.mail-archive.com/sqlite-users@sqlite.org/msg30517.html
2119 if not include_auto_indexes and row[1].startswith(
2120 "sqlite_autoindex"
2121 ):
2122 continue
2123 indexes.append(dict(name=row[1], column_names=[], unique=row[2]))
2124
2125 # loop thru unique indexes to get the column names.
2126 for idx in list(indexes):
2127 pragma_index = self._get_table_pragma(
2128 connection, "index_info", idx["name"]
2129 )
2130
2131 for row in pragma_index:
2132 if row[2] is None:
2133 util.warn(
2134 "Skipped unsupported reflection of "
2135 "expression-based index %s" % idx["name"]
2136 )
2137 indexes.remove(idx)
2138 break
2139 else:
2140 idx["column_names"].append(row[2])
2141 return indexes
2142
2143 @reflection.cache
2144 def _get_table_sql(self, connection, table_name, schema=None, **kw):
2145 if schema:
2146 schema_expr = "%s." % (
2147 self.identifier_preparer.quote_identifier(schema)
2148 )
2149 else:
2150 schema_expr = ""
2151 try:
2152 s = (
2153 "SELECT sql FROM "
2154 " (SELECT * FROM %(schema)ssqlite_master UNION ALL "
2155 " SELECT * FROM %(schema)ssqlite_temp_master) "
2156 "WHERE name = ? "
2157 "AND type = 'table'" % {"schema": schema_expr}
2158 )
2159 rs = connection.execute(s, (table_name,))
2160 except exc.DBAPIError:
2161 s = (
2162 "SELECT sql FROM %(schema)ssqlite_master "
2163 "WHERE name = ? "
2164 "AND type = 'table'" % {"schema": schema_expr}
2165 )
2166 rs = connection.execute(s, (table_name,))
2167 return rs.scalar()
2168
2169 def _get_table_pragma(self, connection, pragma, table_name, schema=None):
2170 quote = self.identifier_preparer.quote_identifier
2171 if schema is not None:
2172 statements = ["PRAGMA %s." % quote(schema)]
2173 else:
2174 # because PRAGMA looks in all attached databases if no schema
2175 # given, need to specify "main" schema, however since we want
2176 # 'temp' tables in the same namespace as 'main', need to run
2177 # the PRAGMA twice
2178 statements = ["PRAGMA main.", "PRAGMA temp."]
2179
2180 qtable = quote(table_name)
2181 for statement in statements:
2182 statement = "%s%s(%s)" % (statement, pragma, qtable)
2183 cursor = connection.execute(statement)
2184 if not cursor._soft_closed:
2185 # work around SQLite issue whereby cursor.description
2186 # is blank when PRAGMA returns no rows:
2187 # http://www.sqlite.org/cvstrac/tktview?tn=1884
2188 result = cursor.fetchall()
2189 else:
2190 result = []
2191 if result:
2192 return result
2193 else:
2194 return []