test_select.py 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783
  1. import itertools
  2. from .. import AssertsCompiledSQL
  3. from .. import AssertsExecutionResults
  4. from .. import config
  5. from .. import fixtures
  6. from ..assertions import assert_raises
  7. from ..assertions import eq_
  8. from ..assertions import in_
  9. from ..assertsql import CursorSQL
  10. from ..schema import Column
  11. from ..schema import Table
  12. from ... import bindparam
  13. from ... import case
  14. from ... import column
  15. from ... import Computed
  16. from ... import exists
  17. from ... import false
  18. from ... import ForeignKey
  19. from ... import func
  20. from ... import Identity
  21. from ... import Integer
  22. from ... import literal
  23. from ... import literal_column
  24. from ... import null
  25. from ... import select
  26. from ... import String
  27. from ... import table
  28. from ... import testing
  29. from ... import text
  30. from ... import true
  31. from ... import tuple_
  32. from ... import TupleType
  33. from ... import union
  34. from ... import util
  35. from ... import values
  36. from ...exc import DatabaseError
  37. from ...exc import ProgrammingError
  38. from ...util import collections_abc
  39. class CollateTest(fixtures.TablesTest):
  40. __backend__ = True
  41. @classmethod
  42. def define_tables(cls, metadata):
  43. Table(
  44. "some_table",
  45. metadata,
  46. Column("id", Integer, primary_key=True),
  47. Column("data", String(100)),
  48. )
  49. @classmethod
  50. def insert_data(cls, connection):
  51. connection.execute(
  52. cls.tables.some_table.insert(),
  53. [
  54. {"id": 1, "data": "collate data1"},
  55. {"id": 2, "data": "collate data2"},
  56. ],
  57. )
  58. def _assert_result(self, select, result):
  59. with config.db.connect() as conn:
  60. eq_(conn.execute(select).fetchall(), result)
  61. @testing.requires.order_by_collation
  62. def test_collate_order_by(self):
  63. collation = testing.requires.get_order_by_collation(testing.config)
  64. self._assert_result(
  65. select(self.tables.some_table).order_by(
  66. self.tables.some_table.c.data.collate(collation).asc()
  67. ),
  68. [(1, "collate data1"), (2, "collate data2")],
  69. )
  70. class OrderByLabelTest(fixtures.TablesTest):
  71. """Test the dialect sends appropriate ORDER BY expressions when
  72. labels are used.
  73. This essentially exercises the "supports_simple_order_by_label"
  74. setting.
  75. """
  76. __backend__ = True
  77. @classmethod
  78. def define_tables(cls, metadata):
  79. Table(
  80. "some_table",
  81. metadata,
  82. Column("id", Integer, primary_key=True),
  83. Column("x", Integer),
  84. Column("y", Integer),
  85. Column("q", String(50)),
  86. Column("p", String(50)),
  87. )
  88. @classmethod
  89. def insert_data(cls, connection):
  90. connection.execute(
  91. cls.tables.some_table.insert(),
  92. [
  93. {"id": 1, "x": 1, "y": 2, "q": "q1", "p": "p3"},
  94. {"id": 2, "x": 2, "y": 3, "q": "q2", "p": "p2"},
  95. {"id": 3, "x": 3, "y": 4, "q": "q3", "p": "p1"},
  96. ],
  97. )
  98. def _assert_result(self, select, result):
  99. with config.db.connect() as conn:
  100. eq_(conn.execute(select).fetchall(), result)
  101. def test_plain(self):
  102. table = self.tables.some_table
  103. lx = table.c.x.label("lx")
  104. self._assert_result(select(lx).order_by(lx), [(1,), (2,), (3,)])
  105. def test_composed_int(self):
  106. table = self.tables.some_table
  107. lx = (table.c.x + table.c.y).label("lx")
  108. self._assert_result(select(lx).order_by(lx), [(3,), (5,), (7,)])
  109. def test_composed_multiple(self):
  110. table = self.tables.some_table
  111. lx = (table.c.x + table.c.y).label("lx")
  112. ly = (func.lower(table.c.q) + table.c.p).label("ly")
  113. self._assert_result(
  114. select(lx, ly).order_by(lx, ly.desc()),
  115. [(3, util.u("q1p3")), (5, util.u("q2p2")), (7, util.u("q3p1"))],
  116. )
  117. def test_plain_desc(self):
  118. table = self.tables.some_table
  119. lx = table.c.x.label("lx")
  120. self._assert_result(select(lx).order_by(lx.desc()), [(3,), (2,), (1,)])
  121. def test_composed_int_desc(self):
  122. table = self.tables.some_table
  123. lx = (table.c.x + table.c.y).label("lx")
  124. self._assert_result(select(lx).order_by(lx.desc()), [(7,), (5,), (3,)])
  125. @testing.requires.group_by_complex_expression
  126. def test_group_by_composed(self):
  127. table = self.tables.some_table
  128. expr = (table.c.x + table.c.y).label("lx")
  129. stmt = (
  130. select(func.count(table.c.id), expr).group_by(expr).order_by(expr)
  131. )
  132. self._assert_result(stmt, [(1, 3), (1, 5), (1, 7)])
  133. class ValuesExpressionTest(fixtures.TestBase):
  134. __requires__ = ("table_value_constructor",)
  135. __backend__ = True
  136. def test_tuples(self, connection):
  137. value_expr = values(
  138. column("id", Integer), column("name", String), name="my_values"
  139. ).data([(1, "name1"), (2, "name2"), (3, "name3")])
  140. eq_(
  141. connection.execute(select(value_expr)).all(),
  142. [(1, "name1"), (2, "name2"), (3, "name3")],
  143. )
  144. class FetchLimitOffsetTest(fixtures.TablesTest):
  145. __backend__ = True
  146. @classmethod
  147. def define_tables(cls, metadata):
  148. Table(
  149. "some_table",
  150. metadata,
  151. Column("id", Integer, primary_key=True),
  152. Column("x", Integer),
  153. Column("y", Integer),
  154. )
  155. @classmethod
  156. def insert_data(cls, connection):
  157. connection.execute(
  158. cls.tables.some_table.insert(),
  159. [
  160. {"id": 1, "x": 1, "y": 2},
  161. {"id": 2, "x": 2, "y": 3},
  162. {"id": 3, "x": 3, "y": 4},
  163. {"id": 4, "x": 4, "y": 5},
  164. {"id": 5, "x": 4, "y": 6},
  165. ],
  166. )
  167. def _assert_result(
  168. self, connection, select, result, params=(), set_=False
  169. ):
  170. if set_:
  171. query_res = connection.execute(select, params).fetchall()
  172. eq_(len(query_res), len(result))
  173. eq_(set(query_res), set(result))
  174. else:
  175. eq_(connection.execute(select, params).fetchall(), result)
  176. def _assert_result_str(self, select, result, params=()):
  177. conn = config.db.connect(close_with_result=True)
  178. eq_(conn.exec_driver_sql(select, params).fetchall(), result)
  179. def test_simple_limit(self, connection):
  180. table = self.tables.some_table
  181. stmt = select(table).order_by(table.c.id)
  182. self._assert_result(
  183. connection,
  184. stmt.limit(2),
  185. [(1, 1, 2), (2, 2, 3)],
  186. )
  187. self._assert_result(
  188. connection,
  189. stmt.limit(3),
  190. [(1, 1, 2), (2, 2, 3), (3, 3, 4)],
  191. )
  192. def test_limit_render_multiple_times(self, connection):
  193. table = self.tables.some_table
  194. stmt = select(table.c.id).limit(1).scalar_subquery()
  195. u = union(select(stmt), select(stmt)).subquery().select()
  196. self._assert_result(
  197. connection,
  198. u,
  199. [
  200. (1,),
  201. ],
  202. )
  203. @testing.requires.fetch_first
  204. def test_simple_fetch(self, connection):
  205. table = self.tables.some_table
  206. self._assert_result(
  207. connection,
  208. select(table).order_by(table.c.id).fetch(2),
  209. [(1, 1, 2), (2, 2, 3)],
  210. )
  211. self._assert_result(
  212. connection,
  213. select(table).order_by(table.c.id).fetch(3),
  214. [(1, 1, 2), (2, 2, 3), (3, 3, 4)],
  215. )
  216. @testing.requires.offset
  217. def test_simple_offset(self, connection):
  218. table = self.tables.some_table
  219. self._assert_result(
  220. connection,
  221. select(table).order_by(table.c.id).offset(2),
  222. [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
  223. )
  224. self._assert_result(
  225. connection,
  226. select(table).order_by(table.c.id).offset(3),
  227. [(4, 4, 5), (5, 4, 6)],
  228. )
  229. @testing.combinations(
  230. ([(2, 0), (2, 1), (3, 2)]),
  231. ([(2, 1), (2, 0), (3, 2)]),
  232. ([(3, 1), (2, 1), (3, 1)]),
  233. argnames="cases",
  234. )
  235. @testing.requires.offset
  236. def test_simple_limit_offset(self, connection, cases):
  237. table = self.tables.some_table
  238. connection = connection.execution_options(compiled_cache={})
  239. assert_data = [(1, 1, 2), (2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)]
  240. for limit, offset in cases:
  241. expected = assert_data[offset : offset + limit]
  242. self._assert_result(
  243. connection,
  244. select(table).order_by(table.c.id).limit(limit).offset(offset),
  245. expected,
  246. )
  247. @testing.requires.fetch_first
  248. def test_simple_fetch_offset(self, connection):
  249. table = self.tables.some_table
  250. self._assert_result(
  251. connection,
  252. select(table).order_by(table.c.id).fetch(2).offset(1),
  253. [(2, 2, 3), (3, 3, 4)],
  254. )
  255. self._assert_result(
  256. connection,
  257. select(table).order_by(table.c.id).fetch(3).offset(2),
  258. [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
  259. )
  260. @testing.requires.fetch_no_order_by
  261. def test_fetch_offset_no_order(self, connection):
  262. table = self.tables.some_table
  263. self._assert_result(
  264. connection,
  265. select(table).fetch(10),
  266. [(1, 1, 2), (2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
  267. set_=True,
  268. )
  269. @testing.requires.offset
  270. def test_simple_offset_zero(self, connection):
  271. table = self.tables.some_table
  272. self._assert_result(
  273. connection,
  274. select(table).order_by(table.c.id).offset(0),
  275. [(1, 1, 2), (2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
  276. )
  277. self._assert_result(
  278. connection,
  279. select(table).order_by(table.c.id).offset(1),
  280. [(2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
  281. )
  282. @testing.requires.offset
  283. def test_limit_offset_nobinds(self):
  284. """test that 'literal binds' mode works - no bound params."""
  285. table = self.tables.some_table
  286. stmt = select(table).order_by(table.c.id).limit(2).offset(1)
  287. sql = stmt.compile(
  288. dialect=config.db.dialect, compile_kwargs={"literal_binds": True}
  289. )
  290. sql = str(sql)
  291. self._assert_result_str(sql, [(2, 2, 3), (3, 3, 4)])
  292. @testing.requires.fetch_first
  293. def test_fetch_offset_nobinds(self):
  294. """test that 'literal binds' mode works - no bound params."""
  295. table = self.tables.some_table
  296. stmt = select(table).order_by(table.c.id).fetch(2).offset(1)
  297. sql = stmt.compile(
  298. dialect=config.db.dialect, compile_kwargs={"literal_binds": True}
  299. )
  300. sql = str(sql)
  301. self._assert_result_str(sql, [(2, 2, 3), (3, 3, 4)])
  302. @testing.requires.bound_limit_offset
  303. def test_bound_limit(self, connection):
  304. table = self.tables.some_table
  305. self._assert_result(
  306. connection,
  307. select(table).order_by(table.c.id).limit(bindparam("l")),
  308. [(1, 1, 2), (2, 2, 3)],
  309. params={"l": 2},
  310. )
  311. self._assert_result(
  312. connection,
  313. select(table).order_by(table.c.id).limit(bindparam("l")),
  314. [(1, 1, 2), (2, 2, 3), (3, 3, 4)],
  315. params={"l": 3},
  316. )
  317. @testing.requires.bound_limit_offset
  318. def test_bound_offset(self, connection):
  319. table = self.tables.some_table
  320. self._assert_result(
  321. connection,
  322. select(table).order_by(table.c.id).offset(bindparam("o")),
  323. [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
  324. params={"o": 2},
  325. )
  326. self._assert_result(
  327. connection,
  328. select(table).order_by(table.c.id).offset(bindparam("o")),
  329. [(2, 2, 3), (3, 3, 4), (4, 4, 5), (5, 4, 6)],
  330. params={"o": 1},
  331. )
  332. @testing.requires.bound_limit_offset
  333. def test_bound_limit_offset(self, connection):
  334. table = self.tables.some_table
  335. self._assert_result(
  336. connection,
  337. select(table)
  338. .order_by(table.c.id)
  339. .limit(bindparam("l"))
  340. .offset(bindparam("o")),
  341. [(2, 2, 3), (3, 3, 4)],
  342. params={"l": 2, "o": 1},
  343. )
  344. self._assert_result(
  345. connection,
  346. select(table)
  347. .order_by(table.c.id)
  348. .limit(bindparam("l"))
  349. .offset(bindparam("o")),
  350. [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
  351. params={"l": 3, "o": 2},
  352. )
  353. @testing.requires.fetch_first
  354. def test_bound_fetch_offset(self, connection):
  355. table = self.tables.some_table
  356. self._assert_result(
  357. connection,
  358. select(table)
  359. .order_by(table.c.id)
  360. .fetch(bindparam("f"))
  361. .offset(bindparam("o")),
  362. [(2, 2, 3), (3, 3, 4)],
  363. params={"f": 2, "o": 1},
  364. )
  365. self._assert_result(
  366. connection,
  367. select(table)
  368. .order_by(table.c.id)
  369. .fetch(bindparam("f"))
  370. .offset(bindparam("o")),
  371. [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
  372. params={"f": 3, "o": 2},
  373. )
  374. @testing.requires.sql_expression_limit_offset
  375. def test_expr_offset(self, connection):
  376. table = self.tables.some_table
  377. self._assert_result(
  378. connection,
  379. select(table)
  380. .order_by(table.c.id)
  381. .offset(literal_column("1") + literal_column("2")),
  382. [(4, 4, 5), (5, 4, 6)],
  383. )
  384. @testing.requires.sql_expression_limit_offset
  385. def test_expr_limit(self, connection):
  386. table = self.tables.some_table
  387. self._assert_result(
  388. connection,
  389. select(table)
  390. .order_by(table.c.id)
  391. .limit(literal_column("1") + literal_column("2")),
  392. [(1, 1, 2), (2, 2, 3), (3, 3, 4)],
  393. )
  394. @testing.requires.sql_expression_limit_offset
  395. def test_expr_limit_offset(self, connection):
  396. table = self.tables.some_table
  397. self._assert_result(
  398. connection,
  399. select(table)
  400. .order_by(table.c.id)
  401. .limit(literal_column("1") + literal_column("1"))
  402. .offset(literal_column("1") + literal_column("1")),
  403. [(3, 3, 4), (4, 4, 5)],
  404. )
  405. @testing.requires.fetch_first
  406. @testing.requires.fetch_expression
  407. def test_expr_fetch_offset(self, connection):
  408. table = self.tables.some_table
  409. self._assert_result(
  410. connection,
  411. select(table)
  412. .order_by(table.c.id)
  413. .fetch(literal_column("1") + literal_column("1"))
  414. .offset(literal_column("1") + literal_column("1")),
  415. [(3, 3, 4), (4, 4, 5)],
  416. )
  417. @testing.requires.sql_expression_limit_offset
  418. def test_simple_limit_expr_offset(self, connection):
  419. table = self.tables.some_table
  420. self._assert_result(
  421. connection,
  422. select(table)
  423. .order_by(table.c.id)
  424. .limit(2)
  425. .offset(literal_column("1") + literal_column("1")),
  426. [(3, 3, 4), (4, 4, 5)],
  427. )
  428. self._assert_result(
  429. connection,
  430. select(table)
  431. .order_by(table.c.id)
  432. .limit(3)
  433. .offset(literal_column("1") + literal_column("1")),
  434. [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
  435. )
  436. @testing.requires.sql_expression_limit_offset
  437. def test_expr_limit_simple_offset(self, connection):
  438. table = self.tables.some_table
  439. self._assert_result(
  440. connection,
  441. select(table)
  442. .order_by(table.c.id)
  443. .limit(literal_column("1") + literal_column("1"))
  444. .offset(2),
  445. [(3, 3, 4), (4, 4, 5)],
  446. )
  447. self._assert_result(
  448. connection,
  449. select(table)
  450. .order_by(table.c.id)
  451. .limit(literal_column("1") + literal_column("1"))
  452. .offset(1),
  453. [(2, 2, 3), (3, 3, 4)],
  454. )
  455. @testing.requires.fetch_ties
  456. def test_simple_fetch_ties(self, connection):
  457. table = self.tables.some_table
  458. self._assert_result(
  459. connection,
  460. select(table).order_by(table.c.x.desc()).fetch(1, with_ties=True),
  461. [(4, 4, 5), (5, 4, 6)],
  462. set_=True,
  463. )
  464. self._assert_result(
  465. connection,
  466. select(table).order_by(table.c.x.desc()).fetch(3, with_ties=True),
  467. [(3, 3, 4), (4, 4, 5), (5, 4, 6)],
  468. set_=True,
  469. )
  470. @testing.requires.fetch_ties
  471. @testing.requires.fetch_offset_with_options
  472. def test_fetch_offset_ties(self, connection):
  473. table = self.tables.some_table
  474. fa = connection.execute(
  475. select(table)
  476. .order_by(table.c.x)
  477. .fetch(2, with_ties=True)
  478. .offset(2)
  479. ).fetchall()
  480. eq_(fa[0], (3, 3, 4))
  481. eq_(set(fa), set([(3, 3, 4), (4, 4, 5), (5, 4, 6)]))
  482. @testing.requires.fetch_ties
  483. @testing.requires.fetch_offset_with_options
  484. def test_fetch_offset_ties_exact_number(self, connection):
  485. table = self.tables.some_table
  486. self._assert_result(
  487. connection,
  488. select(table)
  489. .order_by(table.c.x)
  490. .fetch(2, with_ties=True)
  491. .offset(1),
  492. [(2, 2, 3), (3, 3, 4)],
  493. )
  494. self._assert_result(
  495. connection,
  496. select(table)
  497. .order_by(table.c.x)
  498. .fetch(3, with_ties=True)
  499. .offset(3),
  500. [(4, 4, 5), (5, 4, 6)],
  501. )
  502. @testing.requires.fetch_percent
  503. def test_simple_fetch_percent(self, connection):
  504. table = self.tables.some_table
  505. self._assert_result(
  506. connection,
  507. select(table).order_by(table.c.id).fetch(20, percent=True),
  508. [(1, 1, 2)],
  509. )
  510. @testing.requires.fetch_percent
  511. @testing.requires.fetch_offset_with_options
  512. def test_fetch_offset_percent(self, connection):
  513. table = self.tables.some_table
  514. self._assert_result(
  515. connection,
  516. select(table)
  517. .order_by(table.c.id)
  518. .fetch(40, percent=True)
  519. .offset(1),
  520. [(2, 2, 3), (3, 3, 4)],
  521. )
  522. @testing.requires.fetch_ties
  523. @testing.requires.fetch_percent
  524. def test_simple_fetch_percent_ties(self, connection):
  525. table = self.tables.some_table
  526. self._assert_result(
  527. connection,
  528. select(table)
  529. .order_by(table.c.x.desc())
  530. .fetch(20, percent=True, with_ties=True),
  531. [(4, 4, 5), (5, 4, 6)],
  532. set_=True,
  533. )
  534. @testing.requires.fetch_ties
  535. @testing.requires.fetch_percent
  536. @testing.requires.fetch_offset_with_options
  537. def test_fetch_offset_percent_ties(self, connection):
  538. table = self.tables.some_table
  539. fa = connection.execute(
  540. select(table)
  541. .order_by(table.c.x)
  542. .fetch(40, percent=True, with_ties=True)
  543. .offset(2)
  544. ).fetchall()
  545. eq_(fa[0], (3, 3, 4))
  546. eq_(set(fa), set([(3, 3, 4), (4, 4, 5), (5, 4, 6)]))
  547. class JoinTest(fixtures.TablesTest):
  548. __backend__ = True
  549. def _assert_result(self, select, result, params=()):
  550. with config.db.connect() as conn:
  551. eq_(conn.execute(select, params).fetchall(), result)
  552. @classmethod
  553. def define_tables(cls, metadata):
  554. Table("a", metadata, Column("id", Integer, primary_key=True))
  555. Table(
  556. "b",
  557. metadata,
  558. Column("id", Integer, primary_key=True),
  559. Column("a_id", ForeignKey("a.id"), nullable=False),
  560. )
  561. @classmethod
  562. def insert_data(cls, connection):
  563. connection.execute(
  564. cls.tables.a.insert(),
  565. [{"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}],
  566. )
  567. connection.execute(
  568. cls.tables.b.insert(),
  569. [
  570. {"id": 1, "a_id": 1},
  571. {"id": 2, "a_id": 1},
  572. {"id": 4, "a_id": 2},
  573. {"id": 5, "a_id": 3},
  574. ],
  575. )
  576. def test_inner_join_fk(self):
  577. a, b = self.tables("a", "b")
  578. stmt = select(a, b).select_from(a.join(b)).order_by(a.c.id, b.c.id)
  579. self._assert_result(stmt, [(1, 1, 1), (1, 2, 1), (2, 4, 2), (3, 5, 3)])
  580. def test_inner_join_true(self):
  581. a, b = self.tables("a", "b")
  582. stmt = (
  583. select(a, b)
  584. .select_from(a.join(b, true()))
  585. .order_by(a.c.id, b.c.id)
  586. )
  587. self._assert_result(
  588. stmt,
  589. [
  590. (a, b, c)
  591. for (a,), (b, c) in itertools.product(
  592. [(1,), (2,), (3,), (4,), (5,)],
  593. [(1, 1), (2, 1), (4, 2), (5, 3)],
  594. )
  595. ],
  596. )
  597. def test_inner_join_false(self):
  598. a, b = self.tables("a", "b")
  599. stmt = (
  600. select(a, b)
  601. .select_from(a.join(b, false()))
  602. .order_by(a.c.id, b.c.id)
  603. )
  604. self._assert_result(stmt, [])
  605. def test_outer_join_false(self):
  606. a, b = self.tables("a", "b")
  607. stmt = (
  608. select(a, b)
  609. .select_from(a.outerjoin(b, false()))
  610. .order_by(a.c.id, b.c.id)
  611. )
  612. self._assert_result(
  613. stmt,
  614. [
  615. (1, None, None),
  616. (2, None, None),
  617. (3, None, None),
  618. (4, None, None),
  619. (5, None, None),
  620. ],
  621. )
  622. def test_outer_join_fk(self):
  623. a, b = self.tables("a", "b")
  624. stmt = select(a, b).select_from(a.join(b)).order_by(a.c.id, b.c.id)
  625. self._assert_result(stmt, [(1, 1, 1), (1, 2, 1), (2, 4, 2), (3, 5, 3)])
  626. class CompoundSelectTest(fixtures.TablesTest):
  627. __backend__ = True
  628. @classmethod
  629. def define_tables(cls, metadata):
  630. Table(
  631. "some_table",
  632. metadata,
  633. Column("id", Integer, primary_key=True),
  634. Column("x", Integer),
  635. Column("y", Integer),
  636. )
  637. @classmethod
  638. def insert_data(cls, connection):
  639. connection.execute(
  640. cls.tables.some_table.insert(),
  641. [
  642. {"id": 1, "x": 1, "y": 2},
  643. {"id": 2, "x": 2, "y": 3},
  644. {"id": 3, "x": 3, "y": 4},
  645. {"id": 4, "x": 4, "y": 5},
  646. ],
  647. )
  648. def _assert_result(self, select, result, params=()):
  649. with config.db.connect() as conn:
  650. eq_(conn.execute(select, params).fetchall(), result)
  651. def test_plain_union(self):
  652. table = self.tables.some_table
  653. s1 = select(table).where(table.c.id == 2)
  654. s2 = select(table).where(table.c.id == 3)
  655. u1 = union(s1, s2)
  656. self._assert_result(
  657. u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
  658. )
  659. def test_select_from_plain_union(self):
  660. table = self.tables.some_table
  661. s1 = select(table).where(table.c.id == 2)
  662. s2 = select(table).where(table.c.id == 3)
  663. u1 = union(s1, s2).alias().select()
  664. self._assert_result(
  665. u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
  666. )
  667. @testing.requires.order_by_col_from_union
  668. @testing.requires.parens_in_union_contained_select_w_limit_offset
  669. def test_limit_offset_selectable_in_unions(self):
  670. table = self.tables.some_table
  671. s1 = select(table).where(table.c.id == 2).limit(1).order_by(table.c.id)
  672. s2 = select(table).where(table.c.id == 3).limit(1).order_by(table.c.id)
  673. u1 = union(s1, s2).limit(2)
  674. self._assert_result(
  675. u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
  676. )
  677. @testing.requires.parens_in_union_contained_select_wo_limit_offset
  678. def test_order_by_selectable_in_unions(self):
  679. table = self.tables.some_table
  680. s1 = select(table).where(table.c.id == 2).order_by(table.c.id)
  681. s2 = select(table).where(table.c.id == 3).order_by(table.c.id)
  682. u1 = union(s1, s2).limit(2)
  683. self._assert_result(
  684. u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
  685. )
  686. def test_distinct_selectable_in_unions(self):
  687. table = self.tables.some_table
  688. s1 = select(table).where(table.c.id == 2).distinct()
  689. s2 = select(table).where(table.c.id == 3).distinct()
  690. u1 = union(s1, s2).limit(2)
  691. self._assert_result(
  692. u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
  693. )
  694. @testing.requires.parens_in_union_contained_select_w_limit_offset
  695. def test_limit_offset_in_unions_from_alias(self):
  696. table = self.tables.some_table
  697. s1 = select(table).where(table.c.id == 2).limit(1).order_by(table.c.id)
  698. s2 = select(table).where(table.c.id == 3).limit(1).order_by(table.c.id)
  699. # this necessarily has double parens
  700. u1 = union(s1, s2).alias()
  701. self._assert_result(
  702. u1.select().limit(2).order_by(u1.c.id), [(2, 2, 3), (3, 3, 4)]
  703. )
  704. def test_limit_offset_aliased_selectable_in_unions(self):
  705. table = self.tables.some_table
  706. s1 = (
  707. select(table)
  708. .where(table.c.id == 2)
  709. .limit(1)
  710. .order_by(table.c.id)
  711. .alias()
  712. .select()
  713. )
  714. s2 = (
  715. select(table)
  716. .where(table.c.id == 3)
  717. .limit(1)
  718. .order_by(table.c.id)
  719. .alias()
  720. .select()
  721. )
  722. u1 = union(s1, s2).limit(2)
  723. self._assert_result(
  724. u1.order_by(u1.selected_columns.id), [(2, 2, 3), (3, 3, 4)]
  725. )
  726. class PostCompileParamsTest(
  727. AssertsExecutionResults, AssertsCompiledSQL, fixtures.TablesTest
  728. ):
  729. __backend__ = True
  730. __requires__ = ("standard_cursor_sql",)
  731. @classmethod
  732. def define_tables(cls, metadata):
  733. Table(
  734. "some_table",
  735. metadata,
  736. Column("id", Integer, primary_key=True),
  737. Column("x", Integer),
  738. Column("y", Integer),
  739. Column("z", String(50)),
  740. )
  741. @classmethod
  742. def insert_data(cls, connection):
  743. connection.execute(
  744. cls.tables.some_table.insert(),
  745. [
  746. {"id": 1, "x": 1, "y": 2, "z": "z1"},
  747. {"id": 2, "x": 2, "y": 3, "z": "z2"},
  748. {"id": 3, "x": 3, "y": 4, "z": "z3"},
  749. {"id": 4, "x": 4, "y": 5, "z": "z4"},
  750. ],
  751. )
  752. def test_compile(self):
  753. table = self.tables.some_table
  754. stmt = select(table.c.id).where(
  755. table.c.x == bindparam("q", literal_execute=True)
  756. )
  757. self.assert_compile(
  758. stmt,
  759. "SELECT some_table.id FROM some_table "
  760. "WHERE some_table.x = __[POSTCOMPILE_q]",
  761. {},
  762. )
  763. def test_compile_literal_binds(self):
  764. table = self.tables.some_table
  765. stmt = select(table.c.id).where(
  766. table.c.x == bindparam("q", 10, literal_execute=True)
  767. )
  768. self.assert_compile(
  769. stmt,
  770. "SELECT some_table.id FROM some_table WHERE some_table.x = 10",
  771. {},
  772. literal_binds=True,
  773. )
  774. def test_execute(self):
  775. table = self.tables.some_table
  776. stmt = select(table.c.id).where(
  777. table.c.x == bindparam("q", literal_execute=True)
  778. )
  779. with self.sql_execution_asserter() as asserter:
  780. with config.db.connect() as conn:
  781. conn.execute(stmt, dict(q=10))
  782. asserter.assert_(
  783. CursorSQL(
  784. "SELECT some_table.id \nFROM some_table "
  785. "\nWHERE some_table.x = 10",
  786. () if config.db.dialect.positional else {},
  787. )
  788. )
  789. def test_execute_expanding_plus_literal_execute(self):
  790. table = self.tables.some_table
  791. stmt = select(table.c.id).where(
  792. table.c.x.in_(bindparam("q", expanding=True, literal_execute=True))
  793. )
  794. with self.sql_execution_asserter() as asserter:
  795. with config.db.connect() as conn:
  796. conn.execute(stmt, dict(q=[5, 6, 7]))
  797. asserter.assert_(
  798. CursorSQL(
  799. "SELECT some_table.id \nFROM some_table "
  800. "\nWHERE some_table.x IN (5, 6, 7)",
  801. () if config.db.dialect.positional else {},
  802. )
  803. )
  804. @testing.requires.tuple_in
  805. def test_execute_tuple_expanding_plus_literal_execute(self):
  806. table = self.tables.some_table
  807. stmt = select(table.c.id).where(
  808. tuple_(table.c.x, table.c.y).in_(
  809. bindparam("q", expanding=True, literal_execute=True)
  810. )
  811. )
  812. with self.sql_execution_asserter() as asserter:
  813. with config.db.connect() as conn:
  814. conn.execute(stmt, dict(q=[(5, 10), (12, 18)]))
  815. asserter.assert_(
  816. CursorSQL(
  817. "SELECT some_table.id \nFROM some_table "
  818. "\nWHERE (some_table.x, some_table.y) "
  819. "IN (%s(5, 10), (12, 18))"
  820. % ("VALUES " if config.db.dialect.tuple_in_values else ""),
  821. () if config.db.dialect.positional else {},
  822. )
  823. )
  824. @testing.requires.tuple_in
  825. def test_execute_tuple_expanding_plus_literal_heterogeneous_execute(self):
  826. table = self.tables.some_table
  827. stmt = select(table.c.id).where(
  828. tuple_(table.c.x, table.c.z).in_(
  829. bindparam("q", expanding=True, literal_execute=True)
  830. )
  831. )
  832. with self.sql_execution_asserter() as asserter:
  833. with config.db.connect() as conn:
  834. conn.execute(stmt, dict(q=[(5, "z1"), (12, "z3")]))
  835. asserter.assert_(
  836. CursorSQL(
  837. "SELECT some_table.id \nFROM some_table "
  838. "\nWHERE (some_table.x, some_table.z) "
  839. "IN (%s(5, 'z1'), (12, 'z3'))"
  840. % ("VALUES " if config.db.dialect.tuple_in_values else ""),
  841. () if config.db.dialect.positional else {},
  842. )
  843. )
  844. class ExpandingBoundInTest(fixtures.TablesTest):
  845. __backend__ = True
  846. @classmethod
  847. def define_tables(cls, metadata):
  848. Table(
  849. "some_table",
  850. metadata,
  851. Column("id", Integer, primary_key=True),
  852. Column("x", Integer),
  853. Column("y", Integer),
  854. Column("z", String(50)),
  855. )
  856. @classmethod
  857. def insert_data(cls, connection):
  858. connection.execute(
  859. cls.tables.some_table.insert(),
  860. [
  861. {"id": 1, "x": 1, "y": 2, "z": "z1"},
  862. {"id": 2, "x": 2, "y": 3, "z": "z2"},
  863. {"id": 3, "x": 3, "y": 4, "z": "z3"},
  864. {"id": 4, "x": 4, "y": 5, "z": "z4"},
  865. ],
  866. )
  867. def _assert_result(self, select, result, params=()):
  868. with config.db.connect() as conn:
  869. eq_(conn.execute(select, params).fetchall(), result)
  870. def test_multiple_empty_sets_bindparam(self):
  871. # test that any anonymous aliasing used by the dialect
  872. # is fine with duplicates
  873. table = self.tables.some_table
  874. stmt = (
  875. select(table.c.id)
  876. .where(table.c.x.in_(bindparam("q")))
  877. .where(table.c.y.in_(bindparam("p")))
  878. .order_by(table.c.id)
  879. )
  880. self._assert_result(stmt, [], params={"q": [], "p": []})
  881. def test_multiple_empty_sets_direct(self):
  882. # test that any anonymous aliasing used by the dialect
  883. # is fine with duplicates
  884. table = self.tables.some_table
  885. stmt = (
  886. select(table.c.id)
  887. .where(table.c.x.in_([]))
  888. .where(table.c.y.in_([]))
  889. .order_by(table.c.id)
  890. )
  891. self._assert_result(stmt, [])
  892. @testing.requires.tuple_in_w_empty
  893. def test_empty_heterogeneous_tuples_bindparam(self):
  894. table = self.tables.some_table
  895. stmt = (
  896. select(table.c.id)
  897. .where(tuple_(table.c.x, table.c.z).in_(bindparam("q")))
  898. .order_by(table.c.id)
  899. )
  900. self._assert_result(stmt, [], params={"q": []})
  901. @testing.requires.tuple_in_w_empty
  902. def test_empty_heterogeneous_tuples_direct(self):
  903. table = self.tables.some_table
  904. def go(val, expected):
  905. stmt = (
  906. select(table.c.id)
  907. .where(tuple_(table.c.x, table.c.z).in_(val))
  908. .order_by(table.c.id)
  909. )
  910. self._assert_result(stmt, expected)
  911. go([], [])
  912. go([(2, "z2"), (3, "z3"), (4, "z4")], [(2,), (3,), (4,)])
  913. go([], [])
  914. @testing.requires.tuple_in_w_empty
  915. def test_empty_homogeneous_tuples_bindparam(self):
  916. table = self.tables.some_table
  917. stmt = (
  918. select(table.c.id)
  919. .where(tuple_(table.c.x, table.c.y).in_(bindparam("q")))
  920. .order_by(table.c.id)
  921. )
  922. self._assert_result(stmt, [], params={"q": []})
  923. @testing.requires.tuple_in_w_empty
  924. def test_empty_homogeneous_tuples_direct(self):
  925. table = self.tables.some_table
  926. def go(val, expected):
  927. stmt = (
  928. select(table.c.id)
  929. .where(tuple_(table.c.x, table.c.y).in_(val))
  930. .order_by(table.c.id)
  931. )
  932. self._assert_result(stmt, expected)
  933. go([], [])
  934. go([(1, 2), (2, 3), (3, 4)], [(1,), (2,), (3,)])
  935. go([], [])
  936. def test_bound_in_scalar_bindparam(self):
  937. table = self.tables.some_table
  938. stmt = (
  939. select(table.c.id)
  940. .where(table.c.x.in_(bindparam("q")))
  941. .order_by(table.c.id)
  942. )
  943. self._assert_result(stmt, [(2,), (3,), (4,)], params={"q": [2, 3, 4]})
  944. def test_bound_in_scalar_direct(self):
  945. table = self.tables.some_table
  946. stmt = (
  947. select(table.c.id)
  948. .where(table.c.x.in_([2, 3, 4]))
  949. .order_by(table.c.id)
  950. )
  951. self._assert_result(stmt, [(2,), (3,), (4,)])
  952. def test_nonempty_in_plus_empty_notin(self):
  953. table = self.tables.some_table
  954. stmt = (
  955. select(table.c.id)
  956. .where(table.c.x.in_([2, 3]))
  957. .where(table.c.id.not_in([]))
  958. .order_by(table.c.id)
  959. )
  960. self._assert_result(stmt, [(2,), (3,)])
  961. def test_empty_in_plus_notempty_notin(self):
  962. table = self.tables.some_table
  963. stmt = (
  964. select(table.c.id)
  965. .where(table.c.x.in_([]))
  966. .where(table.c.id.not_in([2, 3]))
  967. .order_by(table.c.id)
  968. )
  969. self._assert_result(stmt, [])
  970. def test_typed_str_in(self):
  971. """test related to #7292.
  972. as a type is given to the bound param, there is no ambiguity
  973. to the type of element.
  974. """
  975. stmt = text(
  976. "select id FROM some_table WHERE z IN :q ORDER BY id"
  977. ).bindparams(bindparam("q", type_=String, expanding=True))
  978. self._assert_result(
  979. stmt,
  980. [(2,), (3,), (4,)],
  981. params={"q": ["z2", "z3", "z4"]},
  982. )
  983. def test_untyped_str_in(self):
  984. """test related to #7292.
  985. for untyped expression, we look at the types of elements.
  986. Test for Sequence to detect tuple in. but not strings or bytes!
  987. as always....
  988. """
  989. stmt = text(
  990. "select id FROM some_table WHERE z IN :q ORDER BY id"
  991. ).bindparams(bindparam("q", expanding=True))
  992. self._assert_result(
  993. stmt,
  994. [(2,), (3,), (4,)],
  995. params={"q": ["z2", "z3", "z4"]},
  996. )
  997. @testing.requires.tuple_in
  998. def test_bound_in_two_tuple_bindparam(self):
  999. table = self.tables.some_table
  1000. stmt = (
  1001. select(table.c.id)
  1002. .where(tuple_(table.c.x, table.c.y).in_(bindparam("q")))
  1003. .order_by(table.c.id)
  1004. )
  1005. self._assert_result(
  1006. stmt, [(2,), (3,), (4,)], params={"q": [(2, 3), (3, 4), (4, 5)]}
  1007. )
  1008. @testing.requires.tuple_in
  1009. def test_bound_in_two_tuple_direct(self):
  1010. table = self.tables.some_table
  1011. stmt = (
  1012. select(table.c.id)
  1013. .where(tuple_(table.c.x, table.c.y).in_([(2, 3), (3, 4), (4, 5)]))
  1014. .order_by(table.c.id)
  1015. )
  1016. self._assert_result(stmt, [(2,), (3,), (4,)])
  1017. @testing.requires.tuple_in
  1018. def test_bound_in_heterogeneous_two_tuple_bindparam(self):
  1019. table = self.tables.some_table
  1020. stmt = (
  1021. select(table.c.id)
  1022. .where(tuple_(table.c.x, table.c.z).in_(bindparam("q")))
  1023. .order_by(table.c.id)
  1024. )
  1025. self._assert_result(
  1026. stmt,
  1027. [(2,), (3,), (4,)],
  1028. params={"q": [(2, "z2"), (3, "z3"), (4, "z4")]},
  1029. )
  1030. @testing.requires.tuple_in
  1031. def test_bound_in_heterogeneous_two_tuple_direct(self):
  1032. table = self.tables.some_table
  1033. stmt = (
  1034. select(table.c.id)
  1035. .where(
  1036. tuple_(table.c.x, table.c.z).in_(
  1037. [(2, "z2"), (3, "z3"), (4, "z4")]
  1038. )
  1039. )
  1040. .order_by(table.c.id)
  1041. )
  1042. self._assert_result(
  1043. stmt,
  1044. [(2,), (3,), (4,)],
  1045. )
  1046. @testing.requires.tuple_in
  1047. def test_bound_in_heterogeneous_two_tuple_text_bindparam(self):
  1048. # note this becomes ARRAY if we dont use expanding
  1049. # explicitly right now
  1050. stmt = text(
  1051. "select id FROM some_table WHERE (x, z) IN :q ORDER BY id"
  1052. ).bindparams(bindparam("q", expanding=True))
  1053. self._assert_result(
  1054. stmt,
  1055. [(2,), (3,), (4,)],
  1056. params={"q": [(2, "z2"), (3, "z3"), (4, "z4")]},
  1057. )
  1058. @testing.requires.tuple_in
  1059. def test_bound_in_heterogeneous_two_tuple_typed_bindparam_non_tuple(self):
  1060. class LikeATuple(collections_abc.Sequence):
  1061. def __init__(self, *data):
  1062. self._data = data
  1063. def __iter__(self):
  1064. return iter(self._data)
  1065. def __getitem__(self, idx):
  1066. return self._data[idx]
  1067. def __len__(self):
  1068. return len(self._data)
  1069. stmt = text(
  1070. "select id FROM some_table WHERE (x, z) IN :q ORDER BY id"
  1071. ).bindparams(
  1072. bindparam(
  1073. "q", type_=TupleType(Integer(), String()), expanding=True
  1074. )
  1075. )
  1076. self._assert_result(
  1077. stmt,
  1078. [(2,), (3,), (4,)],
  1079. params={
  1080. "q": [
  1081. LikeATuple(2, "z2"),
  1082. LikeATuple(3, "z3"),
  1083. LikeATuple(4, "z4"),
  1084. ]
  1085. },
  1086. )
  1087. @testing.requires.tuple_in
  1088. def test_bound_in_heterogeneous_two_tuple_text_bindparam_non_tuple(self):
  1089. # note this becomes ARRAY if we dont use expanding
  1090. # explicitly right now
  1091. class LikeATuple(collections_abc.Sequence):
  1092. def __init__(self, *data):
  1093. self._data = data
  1094. def __iter__(self):
  1095. return iter(self._data)
  1096. def __getitem__(self, idx):
  1097. return self._data[idx]
  1098. def __len__(self):
  1099. return len(self._data)
  1100. stmt = text(
  1101. "select id FROM some_table WHERE (x, z) IN :q ORDER BY id"
  1102. ).bindparams(bindparam("q", expanding=True))
  1103. self._assert_result(
  1104. stmt,
  1105. [(2,), (3,), (4,)],
  1106. params={
  1107. "q": [
  1108. LikeATuple(2, "z2"),
  1109. LikeATuple(3, "z3"),
  1110. LikeATuple(4, "z4"),
  1111. ]
  1112. },
  1113. )
  1114. def test_empty_set_against_integer_bindparam(self):
  1115. table = self.tables.some_table
  1116. stmt = (
  1117. select(table.c.id)
  1118. .where(table.c.x.in_(bindparam("q")))
  1119. .order_by(table.c.id)
  1120. )
  1121. self._assert_result(stmt, [], params={"q": []})
  1122. def test_empty_set_against_integer_direct(self):
  1123. table = self.tables.some_table
  1124. stmt = select(table.c.id).where(table.c.x.in_([])).order_by(table.c.id)
  1125. self._assert_result(stmt, [])
  1126. def test_empty_set_against_integer_negation_bindparam(self):
  1127. table = self.tables.some_table
  1128. stmt = (
  1129. select(table.c.id)
  1130. .where(table.c.x.not_in(bindparam("q")))
  1131. .order_by(table.c.id)
  1132. )
  1133. self._assert_result(stmt, [(1,), (2,), (3,), (4,)], params={"q": []})
  1134. def test_empty_set_against_integer_negation_direct(self):
  1135. table = self.tables.some_table
  1136. stmt = (
  1137. select(table.c.id).where(table.c.x.not_in([])).order_by(table.c.id)
  1138. )
  1139. self._assert_result(stmt, [(1,), (2,), (3,), (4,)])
  1140. def test_empty_set_against_string_bindparam(self):
  1141. table = self.tables.some_table
  1142. stmt = (
  1143. select(table.c.id)
  1144. .where(table.c.z.in_(bindparam("q")))
  1145. .order_by(table.c.id)
  1146. )
  1147. self._assert_result(stmt, [], params={"q": []})
  1148. def test_empty_set_against_string_direct(self):
  1149. table = self.tables.some_table
  1150. stmt = select(table.c.id).where(table.c.z.in_([])).order_by(table.c.id)
  1151. self._assert_result(stmt, [])
  1152. def test_empty_set_against_string_negation_bindparam(self):
  1153. table = self.tables.some_table
  1154. stmt = (
  1155. select(table.c.id)
  1156. .where(table.c.z.not_in(bindparam("q")))
  1157. .order_by(table.c.id)
  1158. )
  1159. self._assert_result(stmt, [(1,), (2,), (3,), (4,)], params={"q": []})
  1160. def test_empty_set_against_string_negation_direct(self):
  1161. table = self.tables.some_table
  1162. stmt = (
  1163. select(table.c.id).where(table.c.z.not_in([])).order_by(table.c.id)
  1164. )
  1165. self._assert_result(stmt, [(1,), (2,), (3,), (4,)])
  1166. def test_null_in_empty_set_is_false_bindparam(self, connection):
  1167. stmt = select(
  1168. case(
  1169. (
  1170. null().in_(bindparam("foo", value=())),
  1171. true(),
  1172. ),
  1173. else_=false(),
  1174. )
  1175. )
  1176. in_(connection.execute(stmt).fetchone()[0], (False, 0))
  1177. def test_null_in_empty_set_is_false_direct(self, connection):
  1178. stmt = select(
  1179. case(
  1180. (
  1181. null().in_([]),
  1182. true(),
  1183. ),
  1184. else_=false(),
  1185. )
  1186. )
  1187. in_(connection.execute(stmt).fetchone()[0], (False, 0))
  1188. class LikeFunctionsTest(fixtures.TablesTest):
  1189. __backend__ = True
  1190. run_inserts = "once"
  1191. run_deletes = None
  1192. @classmethod
  1193. def define_tables(cls, metadata):
  1194. Table(
  1195. "some_table",
  1196. metadata,
  1197. Column("id", Integer, primary_key=True),
  1198. Column("data", String(50)),
  1199. )
  1200. @classmethod
  1201. def insert_data(cls, connection):
  1202. connection.execute(
  1203. cls.tables.some_table.insert(),
  1204. [
  1205. {"id": 1, "data": "abcdefg"},
  1206. {"id": 2, "data": "ab/cdefg"},
  1207. {"id": 3, "data": "ab%cdefg"},
  1208. {"id": 4, "data": "ab_cdefg"},
  1209. {"id": 5, "data": "abcde/fg"},
  1210. {"id": 6, "data": "abcde%fg"},
  1211. {"id": 7, "data": "ab#cdefg"},
  1212. {"id": 8, "data": "ab9cdefg"},
  1213. {"id": 9, "data": "abcde#fg"},
  1214. {"id": 10, "data": "abcd9fg"},
  1215. {"id": 11, "data": None},
  1216. ],
  1217. )
  1218. def _test(self, expr, expected):
  1219. some_table = self.tables.some_table
  1220. with config.db.connect() as conn:
  1221. rows = {
  1222. value
  1223. for value, in conn.execute(select(some_table.c.id).where(expr))
  1224. }
  1225. eq_(rows, expected)
  1226. def test_startswith_unescaped(self):
  1227. col = self.tables.some_table.c.data
  1228. self._test(col.startswith("ab%c"), {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
  1229. def test_startswith_autoescape(self):
  1230. col = self.tables.some_table.c.data
  1231. self._test(col.startswith("ab%c", autoescape=True), {3})
  1232. def test_startswith_sqlexpr(self):
  1233. col = self.tables.some_table.c.data
  1234. self._test(
  1235. col.startswith(literal_column("'ab%c'")),
  1236. {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
  1237. )
  1238. def test_startswith_escape(self):
  1239. col = self.tables.some_table.c.data
  1240. self._test(col.startswith("ab##c", escape="#"), {7})
  1241. def test_startswith_autoescape_escape(self):
  1242. col = self.tables.some_table.c.data
  1243. self._test(col.startswith("ab%c", autoescape=True, escape="#"), {3})
  1244. self._test(col.startswith("ab#c", autoescape=True, escape="#"), {7})
  1245. def test_endswith_unescaped(self):
  1246. col = self.tables.some_table.c.data
  1247. self._test(col.endswith("e%fg"), {1, 2, 3, 4, 5, 6, 7, 8, 9})
  1248. def test_endswith_sqlexpr(self):
  1249. col = self.tables.some_table.c.data
  1250. self._test(
  1251. col.endswith(literal_column("'e%fg'")), {1, 2, 3, 4, 5, 6, 7, 8, 9}
  1252. )
  1253. def test_endswith_autoescape(self):
  1254. col = self.tables.some_table.c.data
  1255. self._test(col.endswith("e%fg", autoescape=True), {6})
  1256. def test_endswith_escape(self):
  1257. col = self.tables.some_table.c.data
  1258. self._test(col.endswith("e##fg", escape="#"), {9})
  1259. def test_endswith_autoescape_escape(self):
  1260. col = self.tables.some_table.c.data
  1261. self._test(col.endswith("e%fg", autoescape=True, escape="#"), {6})
  1262. self._test(col.endswith("e#fg", autoescape=True, escape="#"), {9})
  1263. def test_contains_unescaped(self):
  1264. col = self.tables.some_table.c.data
  1265. self._test(col.contains("b%cde"), {1, 2, 3, 4, 5, 6, 7, 8, 9})
  1266. def test_contains_autoescape(self):
  1267. col = self.tables.some_table.c.data
  1268. self._test(col.contains("b%cde", autoescape=True), {3})
  1269. def test_contains_escape(self):
  1270. col = self.tables.some_table.c.data
  1271. self._test(col.contains("b##cde", escape="#"), {7})
  1272. def test_contains_autoescape_escape(self):
  1273. col = self.tables.some_table.c.data
  1274. self._test(col.contains("b%cd", autoescape=True, escape="#"), {3})
  1275. self._test(col.contains("b#cd", autoescape=True, escape="#"), {7})
  1276. @testing.requires.regexp_match
  1277. def test_not_regexp_match(self):
  1278. col = self.tables.some_table.c.data
  1279. self._test(~col.regexp_match("a.cde"), {2, 3, 4, 7, 8, 10})
  1280. @testing.requires.regexp_replace
  1281. def test_regexp_replace(self):
  1282. col = self.tables.some_table.c.data
  1283. self._test(
  1284. col.regexp_replace("a.cde", "FOO").contains("FOO"), {1, 5, 6, 9}
  1285. )
  1286. @testing.requires.regexp_match
  1287. @testing.combinations(
  1288. ("a.cde", {1, 5, 6, 9}),
  1289. ("abc", {1, 5, 6, 9, 10}),
  1290. ("^abc", {1, 5, 6, 9, 10}),
  1291. ("9cde", {8}),
  1292. ("^a", set(range(1, 11))),
  1293. ("(b|c)", set(range(1, 11))),
  1294. ("^(b|c)", set()),
  1295. )
  1296. def test_regexp_match(self, text, expected):
  1297. col = self.tables.some_table.c.data
  1298. self._test(col.regexp_match(text), expected)
  1299. class ComputedColumnTest(fixtures.TablesTest):
  1300. __backend__ = True
  1301. __requires__ = ("computed_columns",)
  1302. @classmethod
  1303. def define_tables(cls, metadata):
  1304. Table(
  1305. "square",
  1306. metadata,
  1307. Column("id", Integer, primary_key=True),
  1308. Column("side", Integer),
  1309. Column("area", Integer, Computed("side * side")),
  1310. Column("perimeter", Integer, Computed("4 * side")),
  1311. )
  1312. @classmethod
  1313. def insert_data(cls, connection):
  1314. connection.execute(
  1315. cls.tables.square.insert(),
  1316. [{"id": 1, "side": 10}, {"id": 10, "side": 42}],
  1317. )
  1318. def test_select_all(self):
  1319. with config.db.connect() as conn:
  1320. res = conn.execute(
  1321. select(text("*"))
  1322. .select_from(self.tables.square)
  1323. .order_by(self.tables.square.c.id)
  1324. ).fetchall()
  1325. eq_(res, [(1, 10, 100, 40), (10, 42, 1764, 168)])
  1326. def test_select_columns(self):
  1327. with config.db.connect() as conn:
  1328. res = conn.execute(
  1329. select(
  1330. self.tables.square.c.area, self.tables.square.c.perimeter
  1331. )
  1332. .select_from(self.tables.square)
  1333. .order_by(self.tables.square.c.id)
  1334. ).fetchall()
  1335. eq_(res, [(100, 40), (1764, 168)])
  1336. class IdentityColumnTest(fixtures.TablesTest):
  1337. __backend__ = True
  1338. __requires__ = ("identity_columns",)
  1339. run_inserts = "once"
  1340. run_deletes = "once"
  1341. @classmethod
  1342. def define_tables(cls, metadata):
  1343. Table(
  1344. "tbl_a",
  1345. metadata,
  1346. Column(
  1347. "id",
  1348. Integer,
  1349. Identity(
  1350. always=True, start=42, nominvalue=True, nomaxvalue=True
  1351. ),
  1352. primary_key=True,
  1353. ),
  1354. Column("desc", String(100)),
  1355. )
  1356. Table(
  1357. "tbl_b",
  1358. metadata,
  1359. Column(
  1360. "id",
  1361. Integer,
  1362. Identity(increment=-5, start=0, minvalue=-1000, maxvalue=0),
  1363. primary_key=True,
  1364. ),
  1365. Column("desc", String(100)),
  1366. )
  1367. @classmethod
  1368. def insert_data(cls, connection):
  1369. connection.execute(
  1370. cls.tables.tbl_a.insert(),
  1371. [{"desc": "a"}, {"desc": "b"}],
  1372. )
  1373. connection.execute(
  1374. cls.tables.tbl_b.insert(),
  1375. [{"desc": "a"}, {"desc": "b"}],
  1376. )
  1377. connection.execute(
  1378. cls.tables.tbl_b.insert(),
  1379. [{"id": 42, "desc": "c"}],
  1380. )
  1381. def test_select_all(self, connection):
  1382. res = connection.execute(
  1383. select(text("*"))
  1384. .select_from(self.tables.tbl_a)
  1385. .order_by(self.tables.tbl_a.c.id)
  1386. ).fetchall()
  1387. eq_(res, [(42, "a"), (43, "b")])
  1388. res = connection.execute(
  1389. select(text("*"))
  1390. .select_from(self.tables.tbl_b)
  1391. .order_by(self.tables.tbl_b.c.id)
  1392. ).fetchall()
  1393. eq_(res, [(-5, "b"), (0, "a"), (42, "c")])
  1394. def test_select_columns(self, connection):
  1395. res = connection.execute(
  1396. select(self.tables.tbl_a.c.id).order_by(self.tables.tbl_a.c.id)
  1397. ).fetchall()
  1398. eq_(res, [(42,), (43,)])
  1399. @testing.requires.identity_columns_standard
  1400. def test_insert_always_error(self, connection):
  1401. def fn():
  1402. connection.execute(
  1403. self.tables.tbl_a.insert(),
  1404. [{"id": 200, "desc": "a"}],
  1405. )
  1406. assert_raises((DatabaseError, ProgrammingError), fn)
  1407. class IdentityAutoincrementTest(fixtures.TablesTest):
  1408. __backend__ = True
  1409. __requires__ = ("autoincrement_without_sequence",)
  1410. @classmethod
  1411. def define_tables(cls, metadata):
  1412. Table(
  1413. "tbl",
  1414. metadata,
  1415. Column(
  1416. "id",
  1417. Integer,
  1418. Identity(),
  1419. primary_key=True,
  1420. autoincrement=True,
  1421. ),
  1422. Column("desc", String(100)),
  1423. )
  1424. def test_autoincrement_with_identity(self, connection):
  1425. res = connection.execute(self.tables.tbl.insert(), {"desc": "row"})
  1426. res = connection.execute(self.tables.tbl.select()).first()
  1427. eq_(res, (1, "row"))
  1428. class ExistsTest(fixtures.TablesTest):
  1429. __backend__ = True
  1430. @classmethod
  1431. def define_tables(cls, metadata):
  1432. Table(
  1433. "stuff",
  1434. metadata,
  1435. Column("id", Integer, primary_key=True),
  1436. Column("data", String(50)),
  1437. )
  1438. @classmethod
  1439. def insert_data(cls, connection):
  1440. connection.execute(
  1441. cls.tables.stuff.insert(),
  1442. [
  1443. {"id": 1, "data": "some data"},
  1444. {"id": 2, "data": "some data"},
  1445. {"id": 3, "data": "some data"},
  1446. {"id": 4, "data": "some other data"},
  1447. ],
  1448. )
  1449. def test_select_exists(self, connection):
  1450. stuff = self.tables.stuff
  1451. eq_(
  1452. connection.execute(
  1453. select(literal(1)).where(
  1454. exists().where(stuff.c.data == "some data")
  1455. )
  1456. ).fetchall(),
  1457. [(1,)],
  1458. )
  1459. def test_select_exists_false(self, connection):
  1460. stuff = self.tables.stuff
  1461. eq_(
  1462. connection.execute(
  1463. select(literal(1)).where(
  1464. exists().where(stuff.c.data == "no data")
  1465. )
  1466. ).fetchall(),
  1467. [],
  1468. )
  1469. class DistinctOnTest(AssertsCompiledSQL, fixtures.TablesTest):
  1470. __backend__ = True
  1471. @testing.fails_if(testing.requires.supports_distinct_on)
  1472. def test_distinct_on(self):
  1473. stm = select("*").distinct(column("q")).select_from(table("foo"))
  1474. with testing.expect_deprecated(
  1475. "DISTINCT ON is currently supported only by the PostgreSQL "
  1476. ):
  1477. self.assert_compile(stm, "SELECT DISTINCT * FROM foo")
  1478. class IsOrIsNotDistinctFromTest(fixtures.TablesTest):
  1479. __backend__ = True
  1480. __requires__ = ("supports_is_distinct_from",)
  1481. @classmethod
  1482. def define_tables(cls, metadata):
  1483. Table(
  1484. "is_distinct_test",
  1485. metadata,
  1486. Column("id", Integer, primary_key=True),
  1487. Column("col_a", Integer, nullable=True),
  1488. Column("col_b", Integer, nullable=True),
  1489. )
  1490. @testing.combinations(
  1491. ("both_int_different", 0, 1, 1),
  1492. ("both_int_same", 1, 1, 0),
  1493. ("one_null_first", None, 1, 1),
  1494. ("one_null_second", 0, None, 1),
  1495. ("both_null", None, None, 0),
  1496. id_="iaaa",
  1497. argnames="col_a_value, col_b_value, expected_row_count_for_is",
  1498. )
  1499. def test_is_or_is_not_distinct_from(
  1500. self, col_a_value, col_b_value, expected_row_count_for_is, connection
  1501. ):
  1502. tbl = self.tables.is_distinct_test
  1503. connection.execute(
  1504. tbl.insert(),
  1505. [{"id": 1, "col_a": col_a_value, "col_b": col_b_value}],
  1506. )
  1507. result = connection.execute(
  1508. tbl.select().where(tbl.c.col_a.is_distinct_from(tbl.c.col_b))
  1509. ).fetchall()
  1510. eq_(
  1511. len(result),
  1512. expected_row_count_for_is,
  1513. )
  1514. expected_row_count_for_is_not = (
  1515. 1 if expected_row_count_for_is == 0 else 0
  1516. )
  1517. result = connection.execute(
  1518. tbl.select().where(tbl.c.col_a.is_not_distinct_from(tbl.c.col_b))
  1519. ).fetchall()
  1520. eq_(
  1521. len(result),
  1522. expected_row_count_for_is_not,
  1523. )