Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
test_select.py1889 linesDownload Raw Back to suite
1# testing/suite/test_select.py
2# Copyright (C) 2005-2024 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: https://www.opensource.org/licenses/mit-license.php
7# mypy: ignore-errors
8
9import collections.abc as collections_abc
10import itertools
11
12from .. import AssertsCompiledSQL
13from .. import AssertsExecutionResults
14from .. import config
15from .. import fixtures
16from ..assertions import assert_raises
17from ..assertions import eq_
18from ..assertions import in_
19from ..assertsql import CursorSQL
20from ..schema import Column
21from ..schema import Table
22from ... import bindparam
23from ... import case
24from ... import column
25from ... import Computed
26from ... import exists
27from ... import false
28from ... import ForeignKey
29from ... import func
30from ... import Identity
31from ... import Integer
32from ... import literal
33from ... import literal_column
34from ... import null
35from ... import select
36from ... import String
37from ... import table
38from ... import testing
39from ... import text
40from ... import true
41from ... import tuple_
42from ... import TupleType
43from ... import union
44from ... import values
45from ...exc import DatabaseError
46from ...exc import ProgrammingError
47
48
49class CollateTest(fixtures.TablesTest):
50    __backend__ = True
51
52    @classmethod
53    def define_tables(cls, metadata):
54        Table(
55            "some_table",
56            metadata,
57            Column("id", Integer, primary_key=True),
58            Column("data", String(100)),
59        )
60
61    @classmethod
62    def insert_data(cls, connection):
63        connection.execute(
64            cls.tables.some_table.insert(),
65            [
66                {"id": 1, "data": "collate data1"},
67                {"id": 2, "data": "collate data2"},
68            ],
69        )
70
71    def _assert_result(self, select, result):
72        with config.db.connect() as conn:
73            eq_(conn.execute(select).fetchall(), result)
74
75    @testing.requires.order_by_collation
76    def test_collate_order_by(self):
77        collation = testing.requires.get_order_by_collation(testing.config)
78
79        self._assert_result(
80            select(self.tables.some_table).order_by(
81                self.tables.some_table.c.data.collate(collation).asc()
82            ),
83            [(1, "collate data1"), (2, "collate data2")],
84        )
85
86
87class OrderByLabelTest(fixtures.TablesTest):
88    """Test the dialect sends appropriate ORDER BY expressions when
89    labels are used.
90
91    This essentially exercises the "supports_simple_order_by_label"
92    setting.
93
94    """
95
96    __backend__ = True
97
98    @classmethod
99    def define_tables(cls, metadata):
100        Table(
101            "some_table",
102            metadata,
103            Column("id", Integer, primary_key=True),
104            Column("x", Integer),
105            Column("y", Integer),
106            Column("q", String(50)),
107            Column("p", String(50)),
108        )
109
110    @classmethod
111    def insert_data(cls, connection):
112        connection.execute(
113            cls.tables.some_table.insert(),
114            [
115                {"id": 1, "x": 1, "y": 2, "q": "q1", "p": "p3"},
116                {"id": 2, "x": 2, "y": 3, "q": "q2", "p": "p2"},
117                {"id": 3, "x": 3, "y": 4, "q": "q3", "p": "p1"},
118            ],
119        )
120
121    def _assert_result(self, select, result):
122        with config.db.connect() as conn:
123            eq_(conn.execute(select).fetchall(), result)
124
125    def test_plain(self):
126        table = self.tables.some_table
127        lx = table.c.x.label("lx")
128        self._assert_result(select(lx).order_by(lx), [(1,), (2,), (3,)])
129
130    def test_composed_int(self):
131        table = self.tables.some_table
132        lx = (table.c.x + table.c.y).label("lx")
133        self._assert_result(select(lx).order_by(lx), [(3,), (5,), (7,)])
134
135    def test_composed_multiple(self):
136        table = self.tables.some_table
137        lx = (table.c.x + table.c.y).label("lx")
138        ly = (func.lower(table.c.q) + table.c.p).label("ly")
139        self._assert_result(
140            select(lx, ly).order_by(lx, ly.desc()),
141            [(3, "q1p3"), (5, "q2p2"), (7, "q3p1")],
142        )
143
144    def test_plain_desc(self):
145        table = self.tables.some_table
146        lx = table.c.x.label("lx")
147        self._assert_result(select(lx).order_by(lx.desc()), [(3,), (2,), (1,)])
148
149    def test_composed_int_desc(self):
150        table = self.tables.some_table
151        lx = (table.c.x + table.c.y).label("lx")
152        self._assert_result(select(lx).order_by(lx.desc()), [(7,), (5,), (3,)])
153
154    @testing.requires.group_by_complex_expression
155    def test_group_by_composed(self):
156        table = self.tables.some_table
157        expr = (table.c.x + table.c.y).label("lx")
158        stmt = (
159            select(func.count(table.c.id), expr).group_by(expr).order_by(expr)
160        )
161        self._assert_result(stmt, [(1, 3), (1, 5), (1, 7)])
162
163
164class ValuesExpressionTest(fixtures.TestBase):
165    __requires__ = ("table_value_constructor",)
166
167    __backend__ = True
168
169    def test_tuples(self, connection):
170        value_expr = values(
171            column("id", Integer), column("name", String), name="my_values"
172        ).data([(1, "name1"), (2, "name2"), (3, "name3")])
173
174        eq_(
175            connection.execute(select(value_expr)).all(),
176            [(1, "name1"), (2, "name2"), (3, "name3")],
177        )
178
179
180class FetchLimitOffsetTest(fixtures.TablesTest):
181    __backend__ = True
182
183    @classmethod
184    def define_tables(cls, metadata):
185        Table(
186            "some_table",
187            metadata,
188            Column("id", Integer, primary_key=True),
189            Column("x", Integer),
190            Column("y", Integer),
191        )
192
193    @classmethod
194    def insert_data(cls, connection):
195        connection.execute(
196            cls.tables.some_table.insert(),
197            [
198                {"id": 1, "x": 1, "y": 2},
199                {"id": 2, "x": 2, "y": 3},
200                {"id": 3, "x": 3, "y": 4},
201                {"id": 4, "x": 4, "y": 5},
202                {"id": 5, "x": 4, "y": 6},
203            ],
204        )
205
206    def _assert_result(
207        self, connection, select, result, params=(), set_=False
208    ):
209        if set_:
210            query_res = connection.execute(select, params).fetchall()
211            eq_(len(query_res), len(result))
212            eq_(set(query_res), set(result))
213
214        else:
215            eq_(connection.execute(select, params).fetchall(), result)
216
217    def _assert_result_str(self, select, result, params=()):
218        with config.db.connect() as conn:
219            eq_(conn.exec_driver_sql(select, params).fetchall(), result)
220
221    def test_simple_limit(self, connection):
222        table = self.tables.some_table
223        stmt = select(table).order_by(table.c.id)
224        self._assert_result(
225            connection,
226            stmt.limit(2),
227            [(1, 1, 2), (2, 2, 3)],
228        )
229        self._assert_result(
230            connection,
231            stmt.limit(3),
232            [(1, 1, 2), (2, 2, 3), (3, 3, 4)],
233        )
234
235    def test_limit_render_multiple_times(self, connection):
236        table = self.tables.some_table
237        stmt = select(table.c.id).limit(1).scalar_subquery()
238
239        u = union(select(stmt), select(stmt)).subquery().select()
240
241        self._assert_result(
242            connection,
243            u,
244            [
245                (1,),
246            ],
247        )
248
249    @testing.requires.fetch_first
250    def test_simple_fetch(self, connection):
251        table = self.tables.some_table
252        self._assert_result(
253            connection,
254            select(table).order_by(table.c.id).fetch(2),
255            [(1, 1, 2), (2, 2, 3)],
256        )
257        self._assert_result(
258            connection,
259            select(table).order_by(table.c.id).fetch(3),
260            [(1, 1, 2), (2, 2, 3), (3, 3, 4)],
261        )
262
263    @testing.requires.offset
264    def test_simple_offset(self, connection):
265        table = self.tables.some_table
266        self._assert_result(
267            connection,
268            select(table).order_by(table.c.id).offset(2),
269            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
270        )
271        self._assert_result(
272            connection,
273            select(table).order_by(table.c.id).offset(3),
274            [(4, 4, 5), (5, 4, 6)],
275        )
276
277    @testing.combinations(
278        ([(2, 0), (2, 1), (3, 2)]),
279        ([(2, 1), (2, 0), (3, 2)]),
280        ([(3, 1), (2, 1), (3, 1)]),
281        argnames="cases",
282    )
283    @testing.requires.offset
284    def test_simple_limit_offset(self, connection, cases):
285        table = self.tables.some_table
286        connection = connection.execution_options(compiled_cache={})
287
288        assert_data = [(1, 1, 2), (2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)]
289
290        for limit, offset in cases:
291            expected = assert_data[offset : offset + limit]
292            self._assert_result(
293                connection,
294                select(table).order_by(table.c.id).limit(limit).offset(offset),
295                expected,
296            )
297
298    @testing.requires.fetch_first
299    def test_simple_fetch_offset(self, connection):
300        table = self.tables.some_table
301        self._assert_result(
302            connection,
303            select(table).order_by(table.c.id).fetch(2).offset(1),
304            [(2, 2, 3), (3, 3, 4)],
305        )
306
307        self._assert_result(
308            connection,
309            select(table).order_by(table.c.id).fetch(3).offset(2),
310            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
311        )
312
313    @testing.requires.fetch_no_order_by
314    def test_fetch_offset_no_order(self, connection):
315        table = self.tables.some_table
316        self._assert_result(
317            connection,
318            select(table).fetch(10),
319            [(1, 1, 2), (2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
320            set_=True,
321        )
322
323    @testing.requires.offset
324    def test_simple_offset_zero(self, connection):
325        table = self.tables.some_table
326        self._assert_result(
327            connection,
328            select(table).order_by(table.c.id).offset(0),
329            [(1, 1, 2), (2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
330        )
331
332        self._assert_result(
333            connection,
334            select(table).order_by(table.c.id).offset(1),
335            [(2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
336        )
337
338    @testing.requires.offset
339    def test_limit_offset_nobinds(self):
340        """test that 'literal binds' mode works - no bound params."""
341
342        table = self.tables.some_table
343        stmt = select(table).order_by(table.c.id).limit(2).offset(1)
344        sql = stmt.compile(
345            dialect=config.db.dialect, compile_kwargs={"literal_binds": True}
346        )
347        sql = str(sql)
348
349        self._assert_result_str(sql, [(2, 2, 3), (3, 3, 4)])
350
351    @testing.requires.fetch_first
352    def test_fetch_offset_nobinds(self):
353        """test that 'literal binds' mode works - no bound params."""
354
355        table = self.tables.some_table
356        stmt = select(table).order_by(table.c.id).fetch(2).offset(1)
357        sql = stmt.compile(
358            dialect=config.db.dialect, compile_kwargs={"literal_binds": True}
359        )
360        sql = str(sql)
361
362        self._assert_result_str(sql, [(2, 2, 3), (3, 3, 4)])
363
364    @testing.requires.bound_limit_offset
365    def test_bound_limit(self, connection):
366        table = self.tables.some_table
367        self._assert_result(
368            connection,
369            select(table).order_by(table.c.id).limit(bindparam("l")),
370            [(1, 1, 2), (2, 2, 3)],
371            params={"l": 2},
372        )
373
374        self._assert_result(
375            connection,
376            select(table).order_by(table.c.id).limit(bindparam("l")),
377            [(1, 1, 2), (2, 2, 3), (3, 3, 4)],
378            params={"l": 3},
379        )
380
381    @testing.requires.bound_limit_offset
382    def test_bound_offset(self, connection):
383        table = self.tables.some_table
384        self._assert_result(
385            connection,
386            select(table).order_by(table.c.id).offset(bindparam("o")),
387            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
388            params={"o": 2},
389        )
390
391        self._assert_result(
392            connection,
393            select(table).order_by(table.c.id).offset(bindparam("o")),
394            [(2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
395            params={"o": 1},
396        )
397
398    @testing.requires.bound_limit_offset
399    def test_bound_limit_offset(self, connection):
400        table = self.tables.some_table
401        self._assert_result(
402            connection,
403            select(table)
404            .order_by(table.c.id)
405            .limit(bindparam("l"))
406            .offset(bindparam("o")),
407            [(2, 2, 3), (3, 3, 4)],
408            params={"l": 2, "o": 1},
409        )
410
411        self._assert_result(
412            connection,
413            select(table)
414            .order_by(table.c.id)
415            .limit(bindparam("l"))
416            .offset(bindparam("o")),
417            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
418            params={"l": 3, "o": 2},
419        )
420
421    @testing.requires.fetch_first
422    def test_bound_fetch_offset(self, connection):
423        table = self.tables.some_table
424        self._assert_result(
425            connection,
426            select(table)
427            .order_by(table.c.id)
428            .fetch(bindparam("f"))
429            .offset(bindparam("o")),
430            [(2, 2, 3), (3, 3, 4)],
431            params={"f": 2, "o": 1},
432        )
433
434        self._assert_result(
435            connection,
436            select(table)
437            .order_by(table.c.id)
438            .fetch(bindparam("f"))
439            .offset(bindparam("o")),
440            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
441            params={"f": 3, "o": 2},
442        )
443
444    @testing.requires.sql_expression_limit_offset
445    def test_expr_offset(self, connection):
446        table = self.tables.some_table
447        self._assert_result(
448            connection,
449            select(table)
450            .order_by(table.c.id)
451            .offset(literal_column("1") + literal_column("2")),
452            [(4, 4, 5), (5, 4, 6)],
453        )
454
455    @testing.requires.sql_expression_limit_offset
456    def test_expr_limit(self, connection):
457        table = self.tables.some_table
458        self._assert_result(
459            connection,
460            select(table)
461            .order_by(table.c.id)
462            .limit(literal_column("1") + literal_column("2")),
463            [(1, 1, 2), (2, 2, 3), (3, 3, 4)],
464        )
465
466    @testing.requires.sql_expression_limit_offset
467    def test_expr_limit_offset(self, connection):
468        table = self.tables.some_table
469        self._assert_result(
470            connection,
471            select(table)
472            .order_by(table.c.id)
473            .limit(literal_column("1") + literal_column("1"))
474            .offset(literal_column("1") + literal_column("1")),
475            [(3, 3, 4), (4, 4, 5)],
476        )
477
478    @testing.requires.fetch_first
479    @testing.requires.fetch_expression
480    def test_expr_fetch_offset(self, connection):
481        table = self.tables.some_table
482        self._assert_result(
483            connection,
484            select(table)
485            .order_by(table.c.id)
486            .fetch(literal_column("1") + literal_column("1"))
487            .offset(literal_column("1") + literal_column("1")),
488            [(3, 3, 4), (4, 4, 5)],
489        )
490
491    @testing.requires.sql_expression_limit_offset
492    def test_simple_limit_expr_offset(self, connection):
493        table = self.tables.some_table
494        self._assert_result(
495            connection,
496            select(table)
497            .order_by(table.c.id)
498            .limit(2)
499            .offset(literal_column("1") + literal_column("1")),
500            [(3, 3, 4), (4, 4, 5)],
501        )
502
503        self._assert_result(
504            connection,
505            select(table)
506            .order_by(table.c.id)
507            .limit(3)
508            .offset(literal_column("1") + literal_column("1")),
509            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
510        )
511
512    @testing.requires.sql_expression_limit_offset
513    def test_expr_limit_simple_offset(self, connection):
514        table = self.tables.some_table
515        self._assert_result(
516            connection,
517            select(table)
518            .order_by(table.c.id)
519            .limit(literal_column("1") + literal_column("1"))
520            .offset(2),
521            [(3, 3, 4), (4, 4, 5)],
522        )
523
524        self._assert_result(
525            connection,
526            select(table)
527            .order_by(table.c.id)
528            .limit(literal_column("1") + literal_column("1"))
529            .offset(1),
530            [(2, 2, 3), (3, 3, 4)],
531        )
532
533    @testing.requires.fetch_ties
534    def test_simple_fetch_ties(self, connection):
535        table = self.tables.some_table
536        self._assert_result(
537            connection,
538            select(table).order_by(table.c.x.desc()).fetch(1, with_ties=True),
539            [(4, 4, 5), (5, 4, 6)],
540            set_=True,
541        )
542
543        self._assert_result(
544            connection,
545            select(table).order_by(table.c.x.desc()).fetch(3, with_ties=True),
546            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
547            set_=True,
548        )
549
550    @testing.requires.fetch_ties
551    @testing.requires.fetch_offset_with_options
552    def test_fetch_offset_ties(self, connection):
553        table = self.tables.some_table
554        fa = connection.execute(
555            select(table)
556            .order_by(table.c.x)
557            .fetch(2, with_ties=True)
558            .offset(2)
559        ).fetchall()
560        eq_(fa[0], (3, 3, 4))
561        eq_(set(fa), {(3, 3, 4), (4, 4, 5), (5, 4, 6)})
562
563    @testing.requires.fetch_ties
564    @testing.requires.fetch_offset_with_options
565    def test_fetch_offset_ties_exact_number(self, connection):
566        table = self.tables.some_table
567        self._assert_result(
568            connection,
569            select(table)
570            .order_by(table.c.x)
571            .fetch(2, with_ties=True)
572            .offset(1),
573            [(2, 2, 3), (3, 3, 4)],
574        )
575
576        self._assert_result(
577            connection,
578            select(table)
579            .order_by(table.c.x)
580            .fetch(3, with_ties=True)
581            .offset(3),
582            [(4, 4, 5), (5, 4, 6)],
583        )
584
585    @testing.requires.fetch_percent
586    def test_simple_fetch_percent(self, connection):
587        table = self.tables.some_table
588        self._assert_result(
589            connection,
590            select(table).order_by(table.c.id).fetch(20, percent=True),
591            [(1, 1, 2)],
592        )
593
594    @testing.requires.fetch_percent
595    @testing.requires.fetch_offset_with_options
596    def test_fetch_offset_percent(self, connection):
597        table = self.tables.some_table
598        self._assert_result(
599            connection,
600            select(table)
601            .order_by(table.c.id)
602            .fetch(40, percent=True)
603            .offset(1),
604            [(2, 2, 3), (3, 3, 4)],
605        )
606
607    @testing.requires.fetch_ties
608    @testing.requires.fetch_percent
609    def test_simple_fetch_percent_ties(self, connection):
610        table = self.tables.some_table
611        self._assert_result(
612            connection,
613            select(table)
614            .order_by(table.c.x.desc())
615            .fetch(20, percent=True, with_ties=True),
616            [(4, 4, 5), (5, 4, 6)],
617            set_=True,
618        )
619
620    @testing.requires.fetch_ties
621    @testing.requires.fetch_percent
622    @testing.requires.fetch_offset_with_options
623    def test_fetch_offset_percent_ties(self, connection):
624        table = self.tables.some_table
625        fa = connection.execute(
626            select(table)
627            .order_by(table.c.x)
628            .fetch(40, percent=True, with_ties=True)
629            .offset(2)
630        ).fetchall()
631        eq_(fa[0], (3, 3, 4))
632        eq_(set(fa), {(3, 3, 4), (4, 4, 5), (5, 4, 6)})
633
634
635class SameNamedSchemaTableTest(fixtures.TablesTest):
636    """tests for #7471"""
637
638    __backend__ = True
639
640    __requires__ = ("schemas",)
641
642    @classmethod
643    def define_tables(cls, metadata):
644        Table(
645            "some_table",
646            metadata,
647            Column("id", Integer, primary_key=True),
648            schema=config.test_schema,
649        )
650        Table(
651            "some_table",
652            metadata,
653            Column("id", Integer, primary_key=True),
654            Column(
655                "some_table_id",
656                Integer,
657                # ForeignKey("%s.some_table.id" % config.test_schema),
658                nullable=False,
659            ),
660        )
661
662    @classmethod
663    def insert_data(cls, connection):
664        some_table, some_table_schema = cls.tables(
665            "some_table", "%s.some_table" % config.test_schema
666        )
667        connection.execute(some_table_schema.insert(), {"id": 1})
668        connection.execute(some_table.insert(), {"id": 1, "some_table_id": 1})
669
670    def test_simple_join_both_tables(self, connection):
671        some_table, some_table_schema = self.tables(
672            "some_table", "%s.some_table" % config.test_schema
673        )
674
675        eq_(
676            connection.execute(
677                select(some_table, some_table_schema).join_from(
678                    some_table,
679                    some_table_schema,
680                    some_table.c.some_table_id == some_table_schema.c.id,
681                )
682            ).first(),
683            (1, 1, 1),
684        )
685
686    def test_simple_join_whereclause_only(self, connection):
687        some_table, some_table_schema = self.tables(
688            "some_table", "%s.some_table" % config.test_schema
689        )
690
691        eq_(
692            connection.execute(
693                select(some_table)
694                .join_from(
695                    some_table,
696                    some_table_schema,
697                    some_table.c.some_table_id == some_table_schema.c.id,
698                )
699                .where(some_table.c.id == 1)
700            ).first(),
701            (1, 1),
702        )
703
704    def test_subquery(self, connection):
705        some_table, some_table_schema = self.tables(
706            "some_table", "%s.some_table" % config.test_schema
707        )
708
709        subq = (
710            select(some_table)
711            .join_from(
712                some_table,
713                some_table_schema,
714                some_table.c.some_table_id == some_table_schema.c.id,
715            )
716            .where(some_table.c.id == 1)
717            .subquery()
718        )
719
720        eq_(
721            connection.execute(
722                select(some_table, subq.c.id)
723                .join_from(
724                    some_table,
725                    subq,
726                    some_table.c.some_table_id == subq.c.id,
727                )
728                .where(some_table.c.id == 1)
729            ).first(),
730            (1, 1, 1),
731        )
732
733
734class JoinTest(fixtures.TablesTest):
735    __backend__ = True
736
737    def _assert_result(self, select, result, params=()):
738        with config.db.connect() as conn:
739            eq_(conn.execute(select, params).fetchall(), result)
740
741    @classmethod
742    def define_tables(cls, metadata):
743        Table("a", metadata, Column("id", Integer, primary_key=True))
744        Table(
745            "b",
746            metadata,
747            Column("id", Integer, primary_key=True),
748            Column("a_id", ForeignKey("a.id"), nullable=False),
749        )
750
751    @classmethod
752    def insert_data(cls, connection):
753        connection.execute(
754            cls.tables.a.insert(),
755            [{"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}],
756        )
757
758        connection.execute(
759            cls.tables.b.insert(),
760            [
761                {"id": 1, "a_id": 1},
762                {"id": 2, "a_id": 1},
763                {"id": 4, "a_id": 2},
764                {"id": 5, "a_id": 3},
765            ],
766        )
767
768    def test_inner_join_fk(self):
769        a, b = self.tables("a", "b")
770
771        stmt = select(a, b).select_from(a.join(b)).order_by(a.c.id, b.c.id)
772
773        self._assert_result(stmt, [(1, 1, 1), (1, 2, 1), (2, 4, 2), (3, 5, 3)])
774
775    def test_inner_join_true(self):
776        a, b = self.tables("a", "b")
777
778        stmt = (
779            select(a, b)
780            .select_from(a.join(b, true()))
781            .order_by(a.c.id, b.c.id)
782        )
783
784        self._assert_result(
785            stmt,
786            [
787                (a, b, c)
788                for (a,), (b, c) in itertools.product(
789                    [(1,), (2,), (3,), (4,), (5,)],
790                    [(1, 1), (2, 1), (4, 2), (5, 3)],
791                )
792            ],
793        )
794
795    def test_inner_join_false(self):
796        a, b = self.tables("a", "b")
797
798        stmt = (
799            select(a, b)
800            .select_from(a.join(b, false()))
801            .order_by(a.c.id, b.c.id)
802        )
803
804        self._assert_result(stmt, [])
805
806    def test_outer_join_false(self):
807        a, b = self.tables("a", "b")
808
809        stmt = (
810            select(a, b)
811            .select_from(a.outerjoin(b, false()))
812            .order_by(a.c.id, b.c.id)
813        )
814
815        self._assert_result(
816            stmt,
817            [
818                (1, None, None),
819                (2, None, None),
820                (3, None, None),
821                (4, None, None),
822                (5, None, None),
823            ],
824        )
825
826    def test_outer_join_fk(self):
827        a, b = self.tables("a", "b")
828
829        stmt = select(a, b).select_from(a.join(b)).order_by(a.c.id, b.c.id)
830
831        self._assert_result(stmt, [(1, 1, 1), (1, 2, 1), (2, 4, 2), (3, 5, 3)])
832
833
834class CompoundSelectTest(fixtures.TablesTest):
835    __backend__ = True
836
837    @classmethod
838    def define_tables(cls, metadata):
839        Table(
840            "some_table",
841            metadata,
842            Column("id", Integer, primary_key=True),
843            Column("x", Integer),
844            Column("y", Integer),
845        )
846
847    @classmethod
848    def insert_data(cls, connection):
849        connection.execute(
850            cls.tables.some_table.insert(),
851            [
852                {"id": 1, "x": 1, "y": 2},
853                {"id": 2, "x": 2, "y": 3},
854                {"id": 3, "x": 3, "y": 4},
855                {"id": 4, "x": 4, "y": 5},
856            ],
857        )
858
859    def _assert_result(self, select, result, params=()):
860        with config.db.connect() as conn:
861            eq_(conn.execute(select, params).fetchall(), result)
862
863    def test_plain_union(self):
864        table = self.tables.some_table
865        s1 = select(table).where(table.c.id == 2)
866        s2 = select(table).where(table.c.id == 3)
867
868        u1 = union(s1, s2)
869        self._assert_result(
870            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
871        )
872
873    def test_select_from_plain_union(self):
874        table = self.tables.some_table
875        s1 = select(table).where(table.c.id == 2)
876        s2 = select(table).where(table.c.id == 3)
877
878        u1 = union(s1, s2).alias().select()
879        self._assert_result(
880            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
881        )
882
883    @testing.requires.order_by_col_from_union
884    @testing.requires.parens_in_union_contained_select_w_limit_offset
885    def test_limit_offset_selectable_in_unions(self):
886        table = self.tables.some_table
887        s1 = select(table).where(table.c.id == 2).limit(1).order_by(table.c.id)
888        s2 = select(table).where(table.c.id == 3).limit(1).order_by(table.c.id)
889
890        u1 = union(s1, s2).limit(2)
891        self._assert_result(
892            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
893        )
894
895    @testing.requires.parens_in_union_contained_select_wo_limit_offset
896    def test_order_by_selectable_in_unions(self):
897        table = self.tables.some_table
898        s1 = select(table).where(table.c.id == 2).order_by(table.c.id)
899        s2 = select(table).where(table.c.id == 3).order_by(table.c.id)
900
901        u1 = union(s1, s2).limit(2)
902        self._assert_result(
903            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
904        )
905
906    def test_distinct_selectable_in_unions(self):
907        table = self.tables.some_table
908        s1 = select(table).where(table.c.id == 2).distinct()
909        s2 = select(table).where(table.c.id == 3).distinct()
910
911        u1 = union(s1, s2).limit(2)
912        self._assert_result(
913            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
914        )
915
916    @testing.requires.parens_in_union_contained_select_w_limit_offset
917    def test_limit_offset_in_unions_from_alias(self):
918        table = self.tables.some_table
919        s1 = select(table).where(table.c.id == 2).limit(1).order_by(table.c.id)
920        s2 = select(table).where(table.c.id == 3).limit(1).order_by(table.c.id)
921
922        # this necessarily has double parens
923        u1 = union(s1, s2).alias()
924        self._assert_result(
925            u1.select().limit(2).order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
926        )
927
928    def test_limit_offset_aliased_selectable_in_unions(self):
929        table = self.tables.some_table
930        s1 = (
931            select(table)
932            .where(table.c.id == 2)
933            .limit(1)
934            .order_by(table.c.id)
935            .alias()
936            .select()
937        )
938        s2 = (
939            select(table)
940            .where(table.c.id == 3)
941            .limit(1)
942            .order_by(table.c.id)
943            .alias()
944            .select()
945        )
946
947        u1 = union(s1, s2).limit(2)
948        self._assert_result(
949            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
950        )
951
952
953class PostCompileParamsTest(
954    AssertsExecutionResults, AssertsCompiledSQL, fixtures.TablesTest
955):
956    __backend__ = True
957
958    __requires__ = ("standard_cursor_sql",)
959
960    @classmethod
961    def define_tables(cls, metadata):
962        Table(
963            "some_table",
964            metadata,
965            Column("id", Integer, primary_key=True),
966            Column("x", Integer),
967            Column("y", Integer),
968            Column("z", String(50)),
969        )
970
971    @classmethod
972    def insert_data(cls, connection):
973        connection.execute(
974            cls.tables.some_table.insert(),
975            [
976                {"id": 1, "x": 1, "y": 2, "z": "z1"},
977                {"id": 2, "x": 2, "y": 3, "z": "z2"},
978                {"id": 3, "x": 3, "y": 4, "z": "z3"},
979                {"id": 4, "x": 4, "y": 5, "z": "z4"},
980            ],
981        )
982
983    def test_compile(self):
984        table = self.tables.some_table
985
986        stmt = select(table.c.id).where(
987            table.c.x == bindparam("q", literal_execute=True)
988        )
989
990        self.assert_compile(
991            stmt,
992            "SELECT some_table.id FROM some_table "
993            "WHERE some_table.x = __[POSTCOMPILE_q]",
994            {},
995        )
996
997    def test_compile_literal_binds(self):
998        table = self.tables.some_table
999
1000        stmt = select(table.c.id).where(
1001            table.c.x == bindparam("q", 10, literal_execute=True)
1002        )
1003
1004        self.assert_compile(
1005            stmt,
1006            "SELECT some_table.id FROM some_table WHERE some_table.x = 10",
1007            {},
1008            literal_binds=True,
1009        )
1010
1011    def test_execute(self):
1012        table = self.tables.some_table
1013
1014        stmt = select(table.c.id).where(
1015            table.c.x == bindparam("q", literal_execute=True)
1016        )
1017
1018        with self.sql_execution_asserter() as asserter:
1019            with config.db.connect() as conn:
1020                conn.execute(stmt, dict(q=10))
1021
1022        asserter.assert_(
1023            CursorSQL(
1024                "SELECT some_table.id \nFROM some_table "
1025                "\nWHERE some_table.x = 10",
1026                () if config.db.dialect.positional else {},
1027            )
1028        )
1029
1030    def test_execute_expanding_plus_literal_execute(self):
1031        table = self.tables.some_table
1032
1033        stmt = select(table.c.id).where(
1034            table.c.x.in_(bindparam("q", expanding=True, literal_execute=True))
1035        )
1036
1037        with self.sql_execution_asserter() as asserter:
1038            with config.db.connect() as conn:
1039                conn.execute(stmt, dict(q=[5, 6, 7]))
1040
1041        asserter.assert_(
1042            CursorSQL(
1043                "SELECT some_table.id \nFROM some_table "
1044                "\nWHERE some_table.x IN (5, 6, 7)",
1045                () if config.db.dialect.positional else {},
1046            )
1047        )
1048
1049    @testing.requires.tuple_in
1050    def test_execute_tuple_expanding_plus_literal_execute(self):
1051        table = self.tables.some_table
1052
1053        stmt = select(table.c.id).where(
1054            tuple_(table.c.x, table.c.y).in_(
1055                bindparam("q", expanding=True, literal_execute=True)
1056            )
1057        )
1058
1059        with self.sql_execution_asserter() as asserter:
1060            with config.db.connect() as conn:
1061                conn.execute(stmt, dict(q=[(5, 10), (12, 18)]))
1062
1063        asserter.assert_(
1064            CursorSQL(
1065                "SELECT some_table.id \nFROM some_table "
1066                "\nWHERE (some_table.x, some_table.y) "
1067                "IN (%s(5, 10), (12, 18))"
1068                % ("VALUES " if config.db.dialect.tuple_in_values else ""),
1069                () if config.db.dialect.positional else {},
1070            )
1071        )
1072
1073    @testing.requires.tuple_in
1074    def test_execute_tuple_expanding_plus_literal_heterogeneous_execute(self):
1075        table = self.tables.some_table
1076
1077        stmt = select(table.c.id).where(
1078            tuple_(table.c.x, table.c.z).in_(
1079                bindparam("q", expanding=True, literal_execute=True)
1080            )
1081        )
1082
1083        with self.sql_execution_asserter() as asserter:
1084            with config.db.connect() as conn:
1085                conn.execute(stmt, dict(q=[(5, "z1"), (12, "z3")]))
1086
1087        asserter.assert_(
1088            CursorSQL(
1089                "SELECT some_table.id \nFROM some_table "
1090                "\nWHERE (some_table.x, some_table.z) "
1091                "IN (%s(5, 'z1'), (12, 'z3'))"
1092                % ("VALUES " if config.db.dialect.tuple_in_values else ""),
1093                () if config.db.dialect.positional else {},
1094            )
1095        )
1096
1097
1098class ExpandingBoundInTest(fixtures.TablesTest):
1099    __backend__ = True
1100
1101    @classmethod
1102    def define_tables(cls, metadata):
1103        Table(
1104            "some_table",
1105            metadata,
1106            Column("id", Integer, primary_key=True),
1107            Column("x", Integer),
1108            Column("y", Integer),
1109            Column("z", String(50)),
1110        )
1111
1112    @classmethod
1113    def insert_data(cls, connection):
1114        connection.execute(
1115            cls.tables.some_table.insert(),
1116            [
1117                {"id": 1, "x": 1, "y": 2, "z": "z1"},
1118                {"id": 2, "x": 2, "y": 3, "z": "z2"},
1119                {"id": 3, "x": 3, "y": 4, "z": "z3"},
1120                {"id": 4, "x": 4, "y": 5, "z": "z4"},
1121            ],
1122        )
1123
1124    def _assert_result(self, select, result, params=()):
1125        with config.db.connect() as conn:
1126            eq_(conn.execute(select, params).fetchall(), result)
1127
1128    def test_multiple_empty_sets_bindparam(self):
1129        # test that any anonymous aliasing used by the dialect
1130        # is fine with duplicates
1131        table = self.tables.some_table
1132        stmt = (
1133            select(table.c.id)
1134            .where(table.c.x.in_(bindparam("q")))
1135            .where(table.c.y.in_(bindparam("p")))
1136            .order_by(table.c.id)
1137        )
1138        self._assert_result(stmt, [], params={"q": [], "p": []})
1139
1140    def test_multiple_empty_sets_direct(self):
1141        # test that any anonymous aliasing used by the dialect
1142        # is fine with duplicates
1143        table = self.tables.some_table
1144        stmt = (
1145            select(table.c.id)
1146            .where(table.c.x.in_([]))
1147            .where(table.c.y.in_([]))
1148            .order_by(table.c.id)
1149        )
1150        self._assert_result(stmt, [])
1151
1152    @testing.requires.tuple_in_w_empty
1153    def test_empty_heterogeneous_tuples_bindparam(self):
1154        table = self.tables.some_table
1155        stmt = (
1156            select(table.c.id)
1157            .where(tuple_(table.c.x, table.c.z).in_(bindparam("q")))
1158            .order_by(table.c.id)
1159        )
1160        self._assert_result(stmt, [], params={"q": []})
1161
1162    @testing.requires.tuple_in_w_empty
1163    def test_empty_heterogeneous_tuples_direct(self):
1164        table = self.tables.some_table
1165
1166        def go(val, expected):
1167            stmt = (
1168                select(table.c.id)
1169                .where(tuple_(table.c.x, table.c.z).in_(val))
1170                .order_by(table.c.id)
1171            )
1172            self._assert_result(stmt, expected)
1173
1174        go([], [])
1175        go([(2, "z2"), (3, "z3"), (4, "z4")], [(2,), (3,), (4,)])
1176        go([], [])
1177
1178    @testing.requires.tuple_in_w_empty
1179    def test_empty_homogeneous_tuples_bindparam(self):
1180        table = self.tables.some_table
1181        stmt = (
1182            select(table.c.id)
1183            .where(tuple_(table.c.x, table.c.y).in_(bindparam("q")))
1184            .order_by(table.c.id)
1185        )
1186        self._assert_result(stmt, [], params={"q": []})
1187
1188    @testing.requires.tuple_in_w_empty
1189    def test_empty_homogeneous_tuples_direct(self):
1190        table = self.tables.some_table
1191
1192        def go(val, expected):
1193            stmt = (
1194                select(table.c.id)
1195                .where(tuple_(table.c.x, table.c.y).in_(val))
1196                .order_by(table.c.id)
1197            )
1198            self._assert_result(stmt, expected)
1199
1200        go([], [])

Showing the first 1,200 of 1889 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai