Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
test_select.py2011 linesDownload Raw Back to suite
1# testing/suite/test_select.py
2# Copyright (C) 2005-2026 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    __sparse_driver_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    __sparse_driver_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    __sparse_driver_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 = (
238            select(table.c.id).order_by(table.c.id).limit(1).scalar_subquery()
239        )
240
241        u = union(select(stmt), select(stmt)).subquery().select()
242
243        self._assert_result(
244            connection,
245            u,
246            [
247                (1,),
248            ],
249        )
250
251    @testing.requires.fetch_first
252    def test_simple_fetch(self, connection):
253        table = self.tables.some_table
254        self._assert_result(
255            connection,
256            select(table).order_by(table.c.id).fetch(2),
257            [(1, 1, 2), (2, 2, 3)],
258        )
259        self._assert_result(
260            connection,
261            select(table).order_by(table.c.id).fetch(3),
262            [(1, 1, 2), (2, 2, 3), (3, 3, 4)],
263        )
264
265    @testing.requires.offset
266    def test_simple_offset(self, connection):
267        table = self.tables.some_table
268        self._assert_result(
269            connection,
270            select(table).order_by(table.c.id).offset(2),
271            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
272        )
273        self._assert_result(
274            connection,
275            select(table).order_by(table.c.id).offset(3),
276            [(4, 4, 5), (5, 4, 6)],
277        )
278
279    @testing.combinations(
280        ([(2, 0), (2, 1), (3, 2)]),
281        ([(2, 1), (2, 0), (3, 2)]),
282        ([(3, 1), (2, 1), (3, 1)]),
283        argnames="cases",
284    )
285    @testing.requires.offset
286    def test_simple_limit_offset(self, connection, cases):
287        table = self.tables.some_table
288        connection = connection.execution_options(compiled_cache={})
289
290        assert_data = [(1, 1, 2), (2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)]
291
292        for limit, offset in cases:
293            expected = assert_data[offset : offset + limit]
294            self._assert_result(
295                connection,
296                select(table).order_by(table.c.id).limit(limit).offset(offset),
297                expected,
298            )
299
300    @testing.requires.fetch_first
301    def test_simple_fetch_offset(self, connection):
302        table = self.tables.some_table
303        self._assert_result(
304            connection,
305            select(table).order_by(table.c.id).fetch(2).offset(1),
306            [(2, 2, 3), (3, 3, 4)],
307        )
308
309        self._assert_result(
310            connection,
311            select(table).order_by(table.c.id).fetch(3).offset(2),
312            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
313        )
314
315    @testing.requires.fetch_no_order_by
316    def test_fetch_offset_no_order(self, connection):
317        table = self.tables.some_table
318        self._assert_result(
319            connection,
320            select(table).fetch(10),
321            [(1, 1, 2), (2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
322            set_=True,
323        )
324
325    @testing.requires.offset
326    def test_simple_offset_zero(self, connection):
327        table = self.tables.some_table
328        self._assert_result(
329            connection,
330            select(table).order_by(table.c.id).offset(0),
331            [(1, 1, 2), (2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
332        )
333
334        self._assert_result(
335            connection,
336            select(table).order_by(table.c.id).offset(1),
337            [(2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
338        )
339
340    @testing.requires.offset
341    def test_limit_offset_nobinds(self):
342        """test that 'literal binds' mode works - no bound params."""
343
344        table = self.tables.some_table
345        stmt = select(table).order_by(table.c.id).limit(2).offset(1)
346        sql = stmt.compile(
347            dialect=config.db.dialect, compile_kwargs={"literal_binds": True}
348        )
349        sql = str(sql)
350
351        self._assert_result_str(sql, [(2, 2, 3), (3, 3, 4)])
352
353    @testing.requires.fetch_first
354    def test_fetch_offset_nobinds(self):
355        """test that 'literal binds' mode works - no bound params."""
356
357        table = self.tables.some_table
358        stmt = select(table).order_by(table.c.id).fetch(2).offset(1)
359        sql = stmt.compile(
360            dialect=config.db.dialect, compile_kwargs={"literal_binds": True}
361        )
362        sql = str(sql)
363
364        self._assert_result_str(sql, [(2, 2, 3), (3, 3, 4)])
365
366    @testing.requires.bound_limit_offset
367    def test_bound_limit(self, connection):
368        table = self.tables.some_table
369        self._assert_result(
370            connection,
371            select(table).order_by(table.c.id).limit(bindparam("l")),
372            [(1, 1, 2), (2, 2, 3)],
373            params={"l": 2},
374        )
375
376        self._assert_result(
377            connection,
378            select(table).order_by(table.c.id).limit(bindparam("l")),
379            [(1, 1, 2), (2, 2, 3), (3, 3, 4)],
380            params={"l": 3},
381        )
382
383    @testing.requires.bound_limit_offset
384    def test_bound_offset(self, connection):
385        table = self.tables.some_table
386        self._assert_result(
387            connection,
388            select(table).order_by(table.c.id).offset(bindparam("o")),
389            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
390            params={"o": 2},
391        )
392
393        self._assert_result(
394            connection,
395            select(table).order_by(table.c.id).offset(bindparam("o")),
396            [(2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
397            params={"o": 1},
398        )
399
400    @testing.requires.bound_limit_offset
401    def test_bound_limit_offset(self, connection):
402        table = self.tables.some_table
403        self._assert_result(
404            connection,
405            select(table)
406            .order_by(table.c.id)
407            .limit(bindparam("l"))
408            .offset(bindparam("o")),
409            [(2, 2, 3), (3, 3, 4)],
410            params={"l": 2, "o": 1},
411        )
412
413        self._assert_result(
414            connection,
415            select(table)
416            .order_by(table.c.id)
417            .limit(bindparam("l"))
418            .offset(bindparam("o")),
419            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
420            params={"l": 3, "o": 2},
421        )
422
423    @testing.requires.fetch_first
424    def test_bound_fetch_offset(self, connection):
425        table = self.tables.some_table
426        self._assert_result(
427            connection,
428            select(table)
429            .order_by(table.c.id)
430            .fetch(bindparam("f"))
431            .offset(bindparam("o")),
432            [(2, 2, 3), (3, 3, 4)],
433            params={"f": 2, "o": 1},
434        )
435
436        self._assert_result(
437            connection,
438            select(table)
439            .order_by(table.c.id)
440            .fetch(bindparam("f"))
441            .offset(bindparam("o")),
442            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
443            params={"f": 3, "o": 2},
444        )
445
446    @testing.requires.sql_expression_limit_offset
447    def test_expr_offset(self, connection):
448        table = self.tables.some_table
449        self._assert_result(
450            connection,
451            select(table)
452            .order_by(table.c.id)
453            .offset(literal_column("1") + literal_column("2")),
454            [(4, 4, 5), (5, 4, 6)],
455        )
456
457    @testing.requires.sql_expression_limit_offset
458    def test_expr_limit(self, connection):
459        table = self.tables.some_table
460        self._assert_result(
461            connection,
462            select(table)
463            .order_by(table.c.id)
464            .limit(literal_column("1") + literal_column("2")),
465            [(1, 1, 2), (2, 2, 3), (3, 3, 4)],
466        )
467
468    @testing.requires.sql_expression_limit_offset
469    def test_expr_limit_offset(self, connection):
470        table = self.tables.some_table
471        self._assert_result(
472            connection,
473            select(table)
474            .order_by(table.c.id)
475            .limit(literal_column("1") + literal_column("1"))
476            .offset(literal_column("1") + literal_column("1")),
477            [(3, 3, 4), (4, 4, 5)],
478        )
479
480    @testing.requires.fetch_first
481    @testing.requires.fetch_expression
482    def test_expr_fetch_offset(self, connection):
483        table = self.tables.some_table
484        self._assert_result(
485            connection,
486            select(table)
487            .order_by(table.c.id)
488            .fetch(literal_column("1") + literal_column("1"))
489            .offset(literal_column("1") + literal_column("1")),
490            [(3, 3, 4), (4, 4, 5)],
491        )
492
493    @testing.requires.sql_expression_limit_offset
494    def test_simple_limit_expr_offset(self, connection):
495        table = self.tables.some_table
496        self._assert_result(
497            connection,
498            select(table)
499            .order_by(table.c.id)
500            .limit(2)
501            .offset(literal_column("1") + literal_column("1")),
502            [(3, 3, 4), (4, 4, 5)],
503        )
504
505        self._assert_result(
506            connection,
507            select(table)
508            .order_by(table.c.id)
509            .limit(3)
510            .offset(literal_column("1") + literal_column("1")),
511            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
512        )
513
514    @testing.requires.sql_expression_limit_offset
515    def test_expr_limit_simple_offset(self, connection):
516        table = self.tables.some_table
517        self._assert_result(
518            connection,
519            select(table)
520            .order_by(table.c.id)
521            .limit(literal_column("1") + literal_column("1"))
522            .offset(2),
523            [(3, 3, 4), (4, 4, 5)],
524        )
525
526        self._assert_result(
527            connection,
528            select(table)
529            .order_by(table.c.id)
530            .limit(literal_column("1") + literal_column("1"))
531            .offset(1),
532            [(2, 2, 3), (3, 3, 4)],
533        )
534
535    @testing.requires.fetch_ties
536    def test_simple_fetch_ties(self, connection):
537        table = self.tables.some_table
538        self._assert_result(
539            connection,
540            select(table).order_by(table.c.x.desc()).fetch(1, with_ties=True),
541            [(4, 4, 5), (5, 4, 6)],
542            set_=True,
543        )
544
545        self._assert_result(
546            connection,
547            select(table).order_by(table.c.x.desc()).fetch(3, with_ties=True),
548            [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
549            set_=True,
550        )
551
552    @testing.requires.fetch_ties
553    @testing.requires.fetch_offset_with_options
554    def test_fetch_offset_ties(self, connection):
555        table = self.tables.some_table
556        fa = connection.execute(
557            select(table)
558            .order_by(table.c.x)
559            .fetch(2, with_ties=True)
560            .offset(2)
561        ).fetchall()
562        eq_(fa[0], (3, 3, 4))
563        eq_(set(fa), {(3, 3, 4), (4, 4, 5), (5, 4, 6)})
564
565    @testing.requires.fetch_ties
566    @testing.requires.fetch_offset_with_options
567    def test_fetch_offset_ties_exact_number(self, connection):
568        table = self.tables.some_table
569        self._assert_result(
570            connection,
571            select(table)
572            .order_by(table.c.x)
573            .fetch(2, with_ties=True)
574            .offset(1),
575            [(2, 2, 3), (3, 3, 4)],
576        )
577
578        self._assert_result(
579            connection,
580            select(table)
581            .order_by(table.c.x)
582            .fetch(3, with_ties=True)
583            .offset(3),
584            [(4, 4, 5), (5, 4, 6)],
585        )
586
587    @testing.requires.fetch_percent
588    def test_simple_fetch_percent(self, connection):
589        table = self.tables.some_table
590        self._assert_result(
591            connection,
592            select(table).order_by(table.c.id).fetch(20, percent=True),
593            [(1, 1, 2)],
594        )
595
596    @testing.requires.fetch_percent
597    @testing.requires.fetch_offset_with_options
598    def test_fetch_offset_percent(self, connection):
599        table = self.tables.some_table
600        self._assert_result(
601            connection,
602            select(table)
603            .order_by(table.c.id)
604            .fetch(40, percent=True)
605            .offset(1),
606            [(2, 2, 3), (3, 3, 4)],
607        )
608
609    @testing.requires.fetch_ties
610    @testing.requires.fetch_percent
611    def test_simple_fetch_percent_ties(self, connection):
612        table = self.tables.some_table
613        self._assert_result(
614            connection,
615            select(table)
616            .order_by(table.c.x.desc())
617            .fetch(20, percent=True, with_ties=True),
618            [(4, 4, 5), (5, 4, 6)],
619            set_=True,
620        )
621
622    @testing.requires.fetch_ties
623    @testing.requires.fetch_percent
624    @testing.requires.fetch_offset_with_options
625    def test_fetch_offset_percent_ties(self, connection):
626        table = self.tables.some_table
627        fa = connection.execute(
628            select(table)
629            .order_by(table.c.x)
630            .fetch(40, percent=True, with_ties=True)
631            .offset(2)
632        ).fetchall()
633        eq_(fa[0], (3, 3, 4))
634        eq_(set(fa), {(3, 3, 4), (4, 4, 5), (5, 4, 6)})
635
636
637class SameNamedSchemaTableTest(fixtures.TablesTest):
638    """tests for #7471"""
639
640    __sparse_driver_backend__ = True
641
642    __requires__ = ("schemas",)
643
644    @classmethod
645    def define_tables(cls, metadata):
646        Table(
647            "some_table",
648            metadata,
649            Column("id", Integer, primary_key=True),
650            schema=config.test_schema,
651        )
652        Table(
653            "some_table",
654            metadata,
655            Column("id", Integer, primary_key=True),
656            Column(
657                "some_table_id",
658                Integer,
659                # ForeignKey("%s.some_table.id" % config.test_schema),
660                nullable=False,
661            ),
662        )
663
664    @classmethod
665    def insert_data(cls, connection):
666        some_table, some_table_schema = cls.tables(
667            "some_table", "%s.some_table" % config.test_schema
668        )
669        connection.execute(some_table_schema.insert(), {"id": 1})
670        connection.execute(some_table.insert(), {"id": 1, "some_table_id": 1})
671
672    def test_simple_join_both_tables(self, connection):
673        some_table, some_table_schema = self.tables(
674            "some_table", "%s.some_table" % config.test_schema
675        )
676
677        eq_(
678            connection.execute(
679                select(some_table, some_table_schema).join_from(
680                    some_table,
681                    some_table_schema,
682                    some_table.c.some_table_id == some_table_schema.c.id,
683                )
684            ).first(),
685            (1, 1, 1),
686        )
687
688    def test_simple_join_whereclause_only(self, connection):
689        some_table, some_table_schema = self.tables(
690            "some_table", "%s.some_table" % config.test_schema
691        )
692
693        eq_(
694            connection.execute(
695                select(some_table)
696                .join_from(
697                    some_table,
698                    some_table_schema,
699                    some_table.c.some_table_id == some_table_schema.c.id,
700                )
701                .where(some_table.c.id == 1)
702            ).first(),
703            (1, 1),
704        )
705
706    def test_subquery(self, connection):
707        some_table, some_table_schema = self.tables(
708            "some_table", "%s.some_table" % config.test_schema
709        )
710
711        subq = (
712            select(some_table)
713            .join_from(
714                some_table,
715                some_table_schema,
716                some_table.c.some_table_id == some_table_schema.c.id,
717            )
718            .where(some_table.c.id == 1)
719            .subquery()
720        )
721
722        eq_(
723            connection.execute(
724                select(some_table, subq.c.id)
725                .join_from(
726                    some_table,
727                    subq,
728                    some_table.c.some_table_id == subq.c.id,
729                )
730                .where(some_table.c.id == 1)
731            ).first(),
732            (1, 1, 1),
733        )
734
735
736class JoinTest(fixtures.TablesTest):
737    __sparse_driver_backend__ = True
738
739    def _assert_result(self, select, result, params=()):
740        with config.db.connect() as conn:
741            eq_(conn.execute(select, params).fetchall(), result)
742
743    @classmethod
744    def define_tables(cls, metadata):
745        Table("a", metadata, Column("id", Integer, primary_key=True))
746        Table(
747            "b",
748            metadata,
749            Column("id", Integer, primary_key=True),
750            Column("a_id", ForeignKey("a.id"), nullable=False),
751        )
752
753    @classmethod
754    def insert_data(cls, connection):
755        connection.execute(
756            cls.tables.a.insert(),
757            [{"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}],
758        )
759
760        connection.execute(
761            cls.tables.b.insert(),
762            [
763                {"id": 1, "a_id": 1},
764                {"id": 2, "a_id": 1},
765                {"id": 4, "a_id": 2},
766                {"id": 5, "a_id": 3},
767            ],
768        )
769
770    def test_inner_join_fk(self):
771        a, b = self.tables("a", "b")
772
773        stmt = select(a, b).select_from(a.join(b)).order_by(a.c.id, b.c.id)
774
775        self._assert_result(stmt, [(1, 1, 1), (1, 2, 1), (2, 4, 2), (3, 5, 3)])
776
777    def test_inner_join_true(self):
778        a, b = self.tables("a", "b")
779
780        stmt = (
781            select(a, b)
782            .select_from(a.join(b, true()))
783            .order_by(a.c.id, b.c.id)
784        )
785
786        self._assert_result(
787            stmt,
788            [
789                (a, b, c)
790                for (a,), (b, c) in itertools.product(
791                    [(1,), (2,), (3,), (4,), (5,)],
792                    [(1, 1), (2, 1), (4, 2), (5, 3)],
793                )
794            ],
795        )
796
797    def test_inner_join_false(self):
798        a, b = self.tables("a", "b")
799
800        stmt = (
801            select(a, b)
802            .select_from(a.join(b, false()))
803            .order_by(a.c.id, b.c.id)
804        )
805
806        self._assert_result(stmt, [])
807
808    def test_outer_join_false(self):
809        a, b = self.tables("a", "b")
810
811        stmt = (
812            select(a, b)
813            .select_from(a.outerjoin(b, false()))
814            .order_by(a.c.id, b.c.id)
815        )
816
817        self._assert_result(
818            stmt,
819            [
820                (1, None, None),
821                (2, None, None),
822                (3, None, None),
823                (4, None, None),
824                (5, None, None),
825            ],
826        )
827
828    def test_outer_join_fk(self):
829        a, b = self.tables("a", "b")
830
831        stmt = select(a, b).select_from(a.join(b)).order_by(a.c.id, b.c.id)
832
833        self._assert_result(stmt, [(1, 1, 1), (1, 2, 1), (2, 4, 2), (3, 5, 3)])
834
835
836class CompoundSelectTest(fixtures.TablesTest):
837    __sparse_driver_backend__ = True
838
839    @classmethod
840    def define_tables(cls, metadata):
841        Table(
842            "some_table",
843            metadata,
844            Column("id", Integer, primary_key=True),
845            Column("x", Integer),
846            Column("y", Integer),
847        )
848
849    @classmethod
850    def insert_data(cls, connection):
851        connection.execute(
852            cls.tables.some_table.insert(),
853            [
854                {"id": 1, "x": 1, "y": 2},
855                {"id": 2, "x": 2, "y": 3},
856                {"id": 3, "x": 3, "y": 4},
857                {"id": 4, "x": 4, "y": 5},
858            ],
859        )
860
861    def _assert_result(self, select, result, params=()):
862        with config.db.connect() as conn:
863            eq_(conn.execute(select, params).fetchall(), result)
864
865    def test_plain_union(self):
866        table = self.tables.some_table
867        s1 = select(table).where(table.c.id == 2)
868        s2 = select(table).where(table.c.id == 3)
869
870        u1 = union(s1, s2)
871        self._assert_result(
872            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
873        )
874
875    def test_select_from_plain_union(self):
876        table = self.tables.some_table
877        s1 = select(table).where(table.c.id == 2)
878        s2 = select(table).where(table.c.id == 3)
879
880        u1 = union(s1, s2).alias().select()
881        self._assert_result(
882            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
883        )
884
885    @testing.requires.order_by_col_from_union
886    @testing.requires.parens_in_union_contained_select_w_limit_offset
887    def test_limit_offset_selectable_in_unions(self):
888        table = self.tables.some_table
889        s1 = select(table).where(table.c.id == 2).limit(1).order_by(table.c.id)
890        s2 = select(table).where(table.c.id == 3).limit(1).order_by(table.c.id)
891
892        u1 = union(s1, s2).limit(2)
893        self._assert_result(
894            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
895        )
896
897    @testing.requires.parens_in_union_contained_select_wo_limit_offset
898    def test_order_by_selectable_in_unions(self):
899        table = self.tables.some_table
900        s1 = select(table).where(table.c.id == 2).order_by(table.c.id)
901        s2 = select(table).where(table.c.id == 3).order_by(table.c.id)
902
903        u1 = union(s1, s2).limit(2)
904        self._assert_result(
905            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
906        )
907
908    def test_distinct_selectable_in_unions(self):
909        table = self.tables.some_table
910        s1 = select(table).where(table.c.id == 2).distinct()
911        s2 = select(table).where(table.c.id == 3).distinct()
912
913        u1 = union(s1, s2).limit(2)
914        self._assert_result(
915            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
916        )
917
918    @testing.requires.parens_in_union_contained_select_w_limit_offset
919    def test_limit_offset_in_unions_from_alias(self):
920        table = self.tables.some_table
921        s1 = select(table).where(table.c.id == 2).limit(1).order_by(table.c.id)
922        s2 = select(table).where(table.c.id == 3).limit(1).order_by(table.c.id)
923
924        # this necessarily has double parens
925        u1 = union(s1, s2).alias()
926        self._assert_result(
927            u1.select().limit(2).order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
928        )
929
930    def test_limit_offset_aliased_selectable_in_unions(self):
931        table = self.tables.some_table
932        s1 = (
933            select(table)
934            .where(table.c.id == 2)
935            .limit(1)
936            .order_by(table.c.id)
937            .alias()
938            .select()
939        )
940        s2 = (
941            select(table)
942            .where(table.c.id == 3)
943            .limit(1)
944            .order_by(table.c.id)
945            .alias()
946            .select()
947        )
948
949        u1 = union(s1, s2).limit(2)
950        self._assert_result(
951            u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
952        )
953
954
955class PostCompileParamsTest(
956    AssertsExecutionResults, AssertsCompiledSQL, fixtures.TablesTest
957):
958    __backend__ = True
959
960    __requires__ = ("standard_cursor_sql",)
961
962    @classmethod
963    def define_tables(cls, metadata):
964        Table(
965            "some_table",
966            metadata,
967            Column("id", Integer, primary_key=True),
968            Column("x", Integer),
969            Column("y", Integer),
970            Column("z", String(50)),
971        )
972
973    @classmethod
974    def insert_data(cls, connection):
975        connection.execute(
976            cls.tables.some_table.insert(),
977            [
978                {"id": 1, "x": 1, "y": 2, "z": "z1"},
979                {"id": 2, "x": 2, "y": 3, "z": "z2"},
980                {"id": 3, "x": 3, "y": 4, "z": "z3"},
981                {"id": 4, "x": 4, "y": 5, "z": "z4"},
982            ],
983        )
984
985    def test_compile(self):
986        table = self.tables.some_table
987
988        stmt = select(table.c.id).where(
989            table.c.x == bindparam("q", literal_execute=True)
990        )
991
992        self.assert_compile(
993            stmt,
994            "SELECT some_table.id FROM some_table "
995            "WHERE some_table.x = __[POSTCOMPILE_q]",
996            {},
997        )
998
999    def test_compile_literal_binds(self):
1000        table = self.tables.some_table
1001
1002        stmt = select(table.c.id).where(
1003            table.c.x == bindparam("q", 10, literal_execute=True)
1004        )
1005
1006        self.assert_compile(
1007            stmt,
1008            "SELECT some_table.id FROM some_table WHERE some_table.x = 10",
1009            {},
1010            literal_binds=True,
1011        )
1012
1013    def test_execute(self):
1014        table = self.tables.some_table
1015
1016        stmt = select(table.c.id).where(
1017            table.c.x == bindparam("q", literal_execute=True)
1018        )
1019
1020        with self.sql_execution_asserter() as asserter:
1021            with config.db.connect() as conn:
1022                conn.execute(stmt, dict(q=10))
1023
1024        asserter.assert_(
1025            CursorSQL(
1026                "SELECT some_table.id \nFROM some_table "
1027                "\nWHERE some_table.x = 10",
1028                () if config.db.dialect.positional else {},
1029            )
1030        )
1031
1032    def test_execute_expanding_plus_literal_execute(self):
1033        table = self.tables.some_table
1034
1035        stmt = select(table.c.id).where(
1036            table.c.x.in_(bindparam("q", expanding=True, literal_execute=True))
1037        )
1038
1039        with self.sql_execution_asserter() as asserter:
1040            with config.db.connect() as conn:
1041                conn.execute(stmt, dict(q=[5, 6, 7]))
1042
1043        asserter.assert_(
1044            CursorSQL(
1045                "SELECT some_table.id \nFROM some_table "
1046                "\nWHERE some_table.x IN (5, 6, 7)",
1047                () if config.db.dialect.positional else {},
1048            )
1049        )
1050
1051    @testing.requires.tuple_in
1052    def test_execute_tuple_expanding_plus_literal_execute(self):
1053        table = self.tables.some_table
1054
1055        stmt = select(table.c.id).where(
1056            tuple_(table.c.x, table.c.y).in_(
1057                bindparam("q", expanding=True, literal_execute=True)
1058            )
1059        )
1060
1061        with self.sql_execution_asserter() as asserter:
1062            with config.db.connect() as conn:
1063                conn.execute(stmt, dict(q=[(5, 10), (12, 18)]))
1064
1065        asserter.assert_(
1066            CursorSQL(
1067                "SELECT some_table.id \nFROM some_table "
1068                "\nWHERE (some_table.x, some_table.y) "
1069                "IN (%s(5, 10), (12, 18))"
1070                % ("VALUES " if config.db.dialect.tuple_in_values else ""),
1071                () if config.db.dialect.positional else {},
1072            )
1073        )
1074
1075    @testing.requires.tuple_in
1076    def test_execute_tuple_expanding_plus_literal_heterogeneous_execute(self):
1077        table = self.tables.some_table
1078
1079        stmt = select(table.c.id).where(
1080            tuple_(table.c.x, table.c.z).in_(
1081                bindparam("q", expanding=True, literal_execute=True)
1082            )
1083        )
1084
1085        with self.sql_execution_asserter() as asserter:
1086            with config.db.connect() as conn:
1087                conn.execute(stmt, dict(q=[(5, "z1"), (12, "z3")]))
1088
1089        asserter.assert_(
1090            CursorSQL(
1091                "SELECT some_table.id \nFROM some_table "
1092                "\nWHERE (some_table.x, some_table.z) "
1093                "IN (%s(5, 'z1'), (12, 'z3'))"
1094                % ("VALUES " if config.db.dialect.tuple_in_values else ""),
1095                () if config.db.dialect.positional else {},
1096            )
1097        )
1098
1099
1100class ExpandingBoundInTest(fixtures.TablesTest):
1101    __backend__ = True
1102
1103    @classmethod
1104    def define_tables(cls, metadata):
1105        Table(
1106            "some_table",
1107            metadata,
1108            Column("id", Integer, primary_key=True),
1109            Column("x", Integer),
1110            Column("y", Integer),
1111            Column("z", String(50)),
1112        )
1113
1114    @classmethod
1115    def insert_data(cls, connection):
1116        connection.execute(
1117            cls.tables.some_table.insert(),
1118            [
1119                {"id": 1, "x": 1, "y": 2, "z": "z1"},
1120                {"id": 2, "x": 2, "y": 3, "z": "z2"},
1121                {"id": 3, "x": 3, "y": 4, "z": "z3"},
1122                {"id": 4, "x": 4, "y": 5, "z": "z4"},
1123            ],
1124        )
1125
1126    def _assert_result(self, select, result, params=()):
1127        with config.db.connect() as conn:
1128            eq_(conn.execute(select, params).fetchall(), result)
1129
1130    def test_multiple_empty_sets_bindparam(self):
1131        # test that any anonymous aliasing used by the dialect
1132        # is fine with duplicates
1133        table = self.tables.some_table
1134        stmt = (
1135            select(table.c.id)
1136            .where(table.c.x.in_(bindparam("q")))
1137            .where(table.c.y.in_(bindparam("p")))
1138            .order_by(table.c.id)
1139        )
1140        self._assert_result(stmt, [], params={"q": [], "p": []})
1141
1142    def test_multiple_empty_sets_direct(self):
1143        # test that any anonymous aliasing used by the dialect
1144        # is fine with duplicates
1145        table = self.tables.some_table
1146        stmt = (
1147            select(table.c.id)
1148            .where(table.c.x.in_([]))
1149            .where(table.c.y.in_([]))
1150            .order_by(table.c.id)
1151        )
1152        self._assert_result(stmt, [])
1153
1154    @testing.requires.tuple_in_w_empty
1155    def test_empty_heterogeneous_tuples_bindparam(self):
1156        table = self.tables.some_table
1157        stmt = (
1158            select(table.c.id)
1159            .where(tuple_(table.c.x, table.c.z).in_(bindparam("q")))
1160            .order_by(table.c.id)
1161        )
1162        self._assert_result(stmt, [], params={"q": []})
1163
1164    @testing.requires.tuple_in_w_empty
1165    def test_empty_heterogeneous_tuples_direct(self):
1166        table = self.tables.some_table
1167
1168        def go(val, expected):
1169            stmt = (
1170                select(table.c.id)
1171                .where(tuple_(table.c.x, table.c.z).in_(val))
1172                .order_by(table.c.id)
1173            )
1174            self._assert_result(stmt, expected)
1175
1176        go([], [])
1177        go([(2, "z2"), (3, "z3"), (4, "z4")], [(2,), (3,), (4,)])
1178        go([], [])
1179
1180    @testing.requires.tuple_in_w_empty
1181    def test_empty_homogeneous_tuples_bindparam(self):
1182        table = self.tables.some_table
1183        stmt = (
1184            select(table.c.id)
1185            .where(tuple_(table.c.x, table.c.y).in_(bindparam("q")))
1186            .order_by(table.c.id)
1187        )
1188        self._assert_result(stmt, [], params={"q": []})
1189
1190    @testing.requires.tuple_in_w_empty
1191    def test_empty_homogeneous_tuples_direct(self):
1192        table = self.tables.some_table
1193
1194        def go(val, expected):
1195            stmt = (
1196                select(table.c.id)
1197                .where(tuple_(table.c.x, table.c.y).in_(val))
1198                .order_by(table.c.id)
1199            )
1200            self._assert_result(stmt, expected)

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

codekingpro/portable-devtools · Team Ai