diff options
| author | mike bayer <mike_mp@zzzcomputing.com> | 2019-10-07 20:27:19 +0000 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2019-10-07 20:27:19 +0000 |
| commit | a6ba1662565c5e63e8a63a4020c594fa6f97befb (patch) | |
| tree | a65799dc666c78583e2c63044a818049e88755e2 /lib | |
| parent | c4dcf3dda63bfd9254ac5864cc3d7003093c9a54 (diff) | |
| parent | a0d94763f8369939ae6b731d6b599b5edb05d37e (diff) | |
| download | sqlalchemy-a6ba1662565c5e63e8a63a4020c594fa6f97befb.tar.gz | |
Merge "Drop right-nested join rewriting"
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/dialects/sqlite/base.py | 12 | ||||
| -rw-r--r-- | lib/sqlalchemy/dialects/sqlite/pysqlite.py | 45 | ||||
| -rw-r--r-- | lib/sqlalchemy/engine/default.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 158 |
4 files changed, 20 insertions, 199 deletions
diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py index defb64ec0..1bb7bd4fc 100644 --- a/lib/sqlalchemy/dialects/sqlite/base.py +++ b/lib/sqlalchemy/dialects/sqlite/base.py @@ -1467,9 +1467,15 @@ class SQLiteDialect(default.DefaultDialect): self.native_datetime = native_datetime if self.dbapi is not None: - self.supports_right_nested_joins = ( - self.dbapi.sqlite_version_info >= (3, 7, 16) - ) + if self.dbapi.sqlite_version_info < (3, 7, 16): + util.warn( + "SQLite version %s is older than 3.7.16, and will not " + "support right nested joins, as are sometimes used in " + "more complex ORM scenarios. SQLAlchemy 1.4 and above " + "no longer tries to rewrite these joins." + % (self.dbapi.sqlite_version_info,) + ) + self._broken_dotted_colnames = self.dbapi.sqlite_version_info < ( 3, 10, diff --git a/lib/sqlalchemy/dialects/sqlite/pysqlite.py b/lib/sqlalchemy/dialects/sqlite/pysqlite.py index 4eca7ae31..89254eef1 100644 --- a/lib/sqlalchemy/dialects/sqlite/pysqlite.py +++ b/lib/sqlalchemy/dialects/sqlite/pysqlite.py @@ -18,19 +18,8 @@ r""" Driver ------ -When using Python 2.5 and above, the built in ``sqlite3`` driver is -already installed and no additional installation is needed. Otherwise, -the ``pysqlite2`` driver needs to be present. This is the same driver as -``sqlite3``, just with a different name. - -The ``pysqlite2`` driver will be loaded first, and if not found, ``sqlite3`` -is loaded. This allows an explicitly installed pysqlite driver to take -precedence over the built in one. As with all dialects, a specific -DBAPI module may be provided to :func:`~sqlalchemy.create_engine()` to control -this explicitly:: - - from sqlite3 import dbapi2 as sqlite - e = create_engine('sqlite+pysqlite:///file.db', module=sqlite) +The ``sqlite3`` Python DBAPI is standard on all modern Python versions; +for cPython and Pypy, no additional installation is necessary. Connect Strings @@ -379,30 +368,18 @@ class SQLiteDialect_pysqlite(SQLiteDialect): driver = "pysqlite" - def __init__(self, uri=False, **kwargs): - SQLiteDialect.__init__(self, **kwargs) - - if self.dbapi is not None: - sqlite_ver = self.dbapi.version_info - if sqlite_ver < (2, 1, 3): - util.warn( - ( - "The installed version of pysqlite2 (%s) is out-dated " - "and will cause errors in some cases. Version 2.1.3 " - "or greater is recommended." - ) - % ".".join([str(subver) for subver in sqlite_ver]) - ) - @classmethod def dbapi(cls): - try: - from pysqlite2 import dbapi2 as sqlite - except ImportError: + if util.py2k: try: - from sqlite3 import dbapi2 as sqlite # try 2.5+ stdlib name. - except ImportError as e: - raise e + from pysqlite2 import dbapi2 as sqlite + except ImportError: + try: + from sqlite3 import dbapi2 as sqlite + except ImportError as e: + raise e + else: + from sqlite3 import dbapi2 as sqlite return sqlite @classmethod diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index f66f06415..79b8622d5 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -65,7 +65,6 @@ class DefaultDialect(interfaces.Dialect): postfetch_lastrowid = True implicit_returning = False - supports_right_nested_joins = True cte_follows_insert = False supports_native_enum = False @@ -201,7 +200,6 @@ class DefaultDialect(interfaces.Dialect): paramstyle=None, dbapi=None, implicit_returning=None, - supports_right_nested_joins=None, case_sensitive=True, supports_native_boolean=None, empty_in_strategy="static", @@ -232,8 +230,6 @@ class DefaultDialect(interfaces.Dialect): self.positional = self.paramstyle in ("qmark", "format", "numeric") self.identifier_preparer = self.preparer(self) self.type_compiler = self.type_compiler(self) - if supports_right_nested_joins is not None: - self.supports_right_nested_joins = supports_right_nested_joins if supports_native_boolean is not None: self.supports_native_boolean = supports_native_boolean self.case_sensitive = case_sensitive diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 1381e734c..320c7b782 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -2049,136 +2049,6 @@ class SQLCompiler(Compiled): def get_statement_hint_text(self, hint_texts): return " ".join(hint_texts) - def _transform_select_for_nested_joins(self, select): - """Rewrite any "a JOIN (b JOIN c)" expression as - "a JOIN (select * from b JOIN c) AS anon", to support - databases that can't parse a parenthesized join correctly - (i.e. sqlite < 3.7.16). - - """ - cloned = {} - column_translate = [{}] - created = set() - - def visit(element, **kw): - if element in column_translate[-1]: - return column_translate[-1][element] - - elif element in cloned: - return cloned[element] - - newelem = cloned[element] = element._clone() - if ( - newelem._is_from_clause - and newelem._is_join - and isinstance(newelem.right, selectable.FromGrouping) - ): - - newelem._reset_exported() - newelem.left = visit(newelem.left, **kw) - - right = visit(newelem.right, **kw) - - selectable_ = selectable.Select( - [right.element], use_labels=True - ).alias() - created.add(selectable_) - created.update(selectable_.c) - - for c in selectable_.c: - c._key_label = c.key - c._label = c.name - - translate_dict = dict( - zip(newelem.right.element.c, selectable_.c) - ) - - # translating from both the old and the new - # because different select() structures will lead us - # to traverse differently - translate_dict[right.element.left] = selectable_ - translate_dict[right.element.right] = selectable_ - translate_dict[newelem.right.element.left] = selectable_ - translate_dict[newelem.right.element.right] = selectable_ - - # propagate translations that we've gained - # from nested visit(newelem.right) outwards - # to the enclosing select here. this happens - # only when we have more than one level of right - # join nesting, i.e. "a JOIN (b JOIN (c JOIN d))" - for k, v in list(column_translate[-1].items()): - if v in translate_dict: - # remarkably, no current ORM tests (May 2013) - # hit this condition, only test_join_rewriting - # does. - column_translate[-1][k] = translate_dict[v] - - column_translate[-1].update(translate_dict) - - newelem.right = selectable_ - - newelem.onclause = visit(newelem.onclause, **kw) - - elif newelem._is_from_container: - # if we hit an Alias, CompoundSelect or ScalarSelect, put a - # marker in the stack. - kw["transform_clue"] = "select_container" - newelem._copy_internals(clone=visit, **kw) - elif newelem._is_returns_rows and newelem._is_select_statement: - barrier_select = ( - kw.get("transform_clue", None) == "select_container" - ) - # if we're still descended from an - # Alias/CompoundSelect/ScalarSelect, we're - # in a FROM clause, so start with a new translate collection - if barrier_select: - column_translate.append({}) - kw["transform_clue"] = "inside_select" - if not newelem._is_select_container: - froms = newelem.froms - newelem._raw_columns = list(newelem.selected_columns) - newelem._from_obj.update(froms) - newelem._reset_memoizations() - newelem._copy_internals(clone=visit, **kw) - if barrier_select: - del column_translate[-1] - else: - newelem._copy_internals(clone=visit, **kw) - - return newelem - - return visit(select) - - def _transform_result_map_for_nested_joins( - self, select, transformed_select - ): - self._result_columns[:] = [ - result_rec - if col is tcol - else ( - result_rec[0], - name, - tuple([col if obj is tcol else obj for obj in result_rec[2]]), - result_rec[3], - ) - for result_rec, (name, col), (tname, tcol) in zip( - self._result_columns, - select._columns_plus_names, - transformed_select._columns_plus_names, - ) - ] - - # TODO: it's not anticipated that we need to correct anon_map - # however if we do, this is what it looks like: - # for (name, col), (tname, tcol) in zip( - # select._columns_plus_names, - # transformed_select._columns_plus_names, - # ): - # if isinstance(name, elements._anonymous_label) and name != tname: - # m1 = re.match(r"^%\((\d+ .+?)\)s$", name) - # m2 = re.match(r"^%\((\d+ .+?)\)s$", tname) - # self.anon_map[m1.group(1)] = self.anon_map[m2.group(1)] - _default_stack_entry = util.immutabledict( [("correlate_froms", frozenset()), ("asfrom_froms", frozenset())] ) @@ -2214,32 +2084,11 @@ class SQLCompiler(Compiled): asfrom=False, fromhints=None, compound_index=0, - nested_join_translation=False, select_wraps_for=None, lateral=False, **kwargs ): - needs_nested_translation = ( - select.use_labels - and not nested_join_translation - and not self.stack - and not self.dialect.supports_right_nested_joins - ) - - if needs_nested_translation: - transformed_select = self._transform_select_for_nested_joins( - select - ) - text = self.visit_select( - transformed_select, - asfrom=asfrom, - fromhints=fromhints, - compound_index=compound_index, - nested_join_translation=True, - **kwargs - ) - toplevel = not self.stack entry = self._default_stack_entry if toplevel else self.stack[-1] @@ -2258,13 +2107,6 @@ class SQLCompiler(Compiled): if not populate_result_map and "add_to_result_map" in kwargs: del kwargs["add_to_result_map"] - if needs_nested_translation: - if populate_result_map: - self._transform_result_map_for_nested_joins( - select, transformed_select - ) - return text - froms = self._setup_select_stack(select, entry, asfrom, lateral) column_clause_args = kwargs.copy() |
