sqlspec 0.47.0__cp314-cp314-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (621) hide show
  1. f68e0789eb443ecb1c2c__mypyc.cp314-win_amd64.pyd +0 -0
  2. sqlspec/__init__.py +167 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_typing.py +714 -0
  6. sqlspec/adapters/__init__.py +0 -0
  7. sqlspec/adapters/adbc/__init__.py +13 -0
  8. sqlspec/adapters/adbc/_typing.py +106 -0
  9. sqlspec/adapters/adbc/adk/__init__.py +5 -0
  10. sqlspec/adapters/adbc/adk/store.py +1280 -0
  11. sqlspec/adapters/adbc/config.py +378 -0
  12. sqlspec/adapters/adbc/core.cp314-win_amd64.pyd +0 -0
  13. sqlspec/adapters/adbc/core.py +922 -0
  14. sqlspec/adapters/adbc/data_dictionary.py +339 -0
  15. sqlspec/adapters/adbc/driver.py +534 -0
  16. sqlspec/adapters/adbc/events/__init__.py +5 -0
  17. sqlspec/adapters/adbc/events/store.py +285 -0
  18. sqlspec/adapters/adbc/litestar/__init__.py +5 -0
  19. sqlspec/adapters/adbc/litestar/store.py +534 -0
  20. sqlspec/adapters/adbc/type_converter.cp314-win_amd64.pyd +0 -0
  21. sqlspec/adapters/adbc/type_converter.py +142 -0
  22. sqlspec/adapters/aiomysql/__init__.py +21 -0
  23. sqlspec/adapters/aiomysql/_typing.py +137 -0
  24. sqlspec/adapters/aiomysql/adk/__init__.py +5 -0
  25. sqlspec/adapters/aiomysql/adk/store.py +678 -0
  26. sqlspec/adapters/aiomysql/config.py +305 -0
  27. sqlspec/adapters/aiomysql/core.cp314-win_amd64.pyd +0 -0
  28. sqlspec/adapters/aiomysql/core.py +536 -0
  29. sqlspec/adapters/aiomysql/data_dictionary.py +121 -0
  30. sqlspec/adapters/aiomysql/driver.py +386 -0
  31. sqlspec/adapters/aiomysql/events/__init__.py +5 -0
  32. sqlspec/adapters/aiomysql/events/store.py +104 -0
  33. sqlspec/adapters/aiomysql/litestar/__init__.py +5 -0
  34. sqlspec/adapters/aiomysql/litestar/store.py +314 -0
  35. sqlspec/adapters/aiosqlite/__init__.py +26 -0
  36. sqlspec/adapters/aiosqlite/_typing.py +109 -0
  37. sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
  38. sqlspec/adapters/aiosqlite/adk/store.py +829 -0
  39. sqlspec/adapters/aiosqlite/config.py +315 -0
  40. sqlspec/adapters/aiosqlite/core.cp314-win_amd64.pyd +0 -0
  41. sqlspec/adapters/aiosqlite/core.py +315 -0
  42. sqlspec/adapters/aiosqlite/data_dictionary.py +202 -0
  43. sqlspec/adapters/aiosqlite/driver.py +311 -0
  44. sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
  45. sqlspec/adapters/aiosqlite/events/store.py +20 -0
  46. sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
  47. sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
  48. sqlspec/adapters/aiosqlite/pool.cp314-win_amd64.pyd +0 -0
  49. sqlspec/adapters/aiosqlite/pool.py +734 -0
  50. sqlspec/adapters/asyncmy/__init__.py +21 -0
  51. sqlspec/adapters/asyncmy/_typing.py +113 -0
  52. sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
  53. sqlspec/adapters/asyncmy/adk/store.py +644 -0
  54. sqlspec/adapters/asyncmy/config.py +307 -0
  55. sqlspec/adapters/asyncmy/core.cp314-win_amd64.pyd +0 -0
  56. sqlspec/adapters/asyncmy/core.py +538 -0
  57. sqlspec/adapters/asyncmy/data_dictionary.py +122 -0
  58. sqlspec/adapters/asyncmy/driver.py +391 -0
  59. sqlspec/adapters/asyncmy/events/__init__.py +5 -0
  60. sqlspec/adapters/asyncmy/events/store.py +104 -0
  61. sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
  62. sqlspec/adapters/asyncmy/litestar/store.py +296 -0
  63. sqlspec/adapters/asyncpg/__init__.py +26 -0
  64. sqlspec/adapters/asyncpg/_typing.py +103 -0
  65. sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
  66. sqlspec/adapters/asyncpg/adk/store.py +483 -0
  67. sqlspec/adapters/asyncpg/config.py +575 -0
  68. sqlspec/adapters/asyncpg/core.cp314-win_amd64.pyd +0 -0
  69. sqlspec/adapters/asyncpg/core.py +480 -0
  70. sqlspec/adapters/asyncpg/data_dictionary.py +157 -0
  71. sqlspec/adapters/asyncpg/driver.py +487 -0
  72. sqlspec/adapters/asyncpg/events/__init__.py +6 -0
  73. sqlspec/adapters/asyncpg/events/_hub.py +181 -0
  74. sqlspec/adapters/asyncpg/events/backend.py +210 -0
  75. sqlspec/adapters/asyncpg/events/store.py +40 -0
  76. sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
  77. sqlspec/adapters/asyncpg/litestar/store.py +251 -0
  78. sqlspec/adapters/bigquery/__init__.py +15 -0
  79. sqlspec/adapters/bigquery/_typing.py +108 -0
  80. sqlspec/adapters/bigquery/config.py +362 -0
  81. sqlspec/adapters/bigquery/core.cp314-win_amd64.pyd +0 -0
  82. sqlspec/adapters/bigquery/core.py +768 -0
  83. sqlspec/adapters/bigquery/data_dictionary.py +120 -0
  84. sqlspec/adapters/bigquery/driver.py +542 -0
  85. sqlspec/adapters/bigquery/events/__init__.py +5 -0
  86. sqlspec/adapters/bigquery/events/store.py +139 -0
  87. sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
  88. sqlspec/adapters/bigquery/litestar/store.py +325 -0
  89. sqlspec/adapters/bigquery/type_converter.cp314-win_amd64.pyd +0 -0
  90. sqlspec/adapters/bigquery/type_converter.py +107 -0
  91. sqlspec/adapters/cockroach_asyncpg/__init__.py +26 -0
  92. sqlspec/adapters/cockroach_asyncpg/_typing.py +73 -0
  93. sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
  94. sqlspec/adapters/cockroach_asyncpg/adk/store.py +465 -0
  95. sqlspec/adapters/cockroach_asyncpg/config.py +248 -0
  96. sqlspec/adapters/cockroach_asyncpg/core.cp314-win_amd64.pyd +0 -0
  97. sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
  98. sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +110 -0
  99. sqlspec/adapters/cockroach_asyncpg/driver.py +142 -0
  100. sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
  101. sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
  102. sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
  103. sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
  104. sqlspec/adapters/cockroach_psycopg/__init__.py +39 -0
  105. sqlspec/adapters/cockroach_psycopg/_typing.py +137 -0
  106. sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
  107. sqlspec/adapters/cockroach_psycopg/adk/store.py +1039 -0
  108. sqlspec/adapters/cockroach_psycopg/config.py +511 -0
  109. sqlspec/adapters/cockroach_psycopg/core.cp314-win_amd64.pyd +0 -0
  110. sqlspec/adapters/cockroach_psycopg/core.py +63 -0
  111. sqlspec/adapters/cockroach_psycopg/data_dictionary.py +220 -0
  112. sqlspec/adapters/cockroach_psycopg/driver.py +273 -0
  113. sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
  114. sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
  115. sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
  116. sqlspec/adapters/cockroach_psycopg/litestar/store.py +327 -0
  117. sqlspec/adapters/duckdb/__init__.py +29 -0
  118. sqlspec/adapters/duckdb/_typing.py +104 -0
  119. sqlspec/adapters/duckdb/adk/__init__.py +14 -0
  120. sqlspec/adapters/duckdb/adk/store.py +935 -0
  121. sqlspec/adapters/duckdb/config.py +386 -0
  122. sqlspec/adapters/duckdb/core.cp314-win_amd64.pyd +0 -0
  123. sqlspec/adapters/duckdb/core.py +332 -0
  124. sqlspec/adapters/duckdb/data_dictionary.py +140 -0
  125. sqlspec/adapters/duckdb/driver.py +426 -0
  126. sqlspec/adapters/duckdb/events/__init__.py +5 -0
  127. sqlspec/adapters/duckdb/events/store.py +57 -0
  128. sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
  129. sqlspec/adapters/duckdb/litestar/store.py +330 -0
  130. sqlspec/adapters/duckdb/pool.cp314-win_amd64.pyd +0 -0
  131. sqlspec/adapters/duckdb/pool.py +350 -0
  132. sqlspec/adapters/duckdb/type_converter.cp314-win_amd64.pyd +0 -0
  133. sqlspec/adapters/duckdb/type_converter.py +118 -0
  134. sqlspec/adapters/mysqlconnector/__init__.py +39 -0
  135. sqlspec/adapters/mysqlconnector/_typing.py +186 -0
  136. sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
  137. sqlspec/adapters/mysqlconnector/adk/store.py +1183 -0
  138. sqlspec/adapters/mysqlconnector/config.py +421 -0
  139. sqlspec/adapters/mysqlconnector/core.cp314-win_amd64.pyd +0 -0
  140. sqlspec/adapters/mysqlconnector/core.py +472 -0
  141. sqlspec/adapters/mysqlconnector/data_dictionary.py +230 -0
  142. sqlspec/adapters/mysqlconnector/driver.py +516 -0
  143. sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
  144. sqlspec/adapters/mysqlconnector/events/store.py +98 -0
  145. sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
  146. sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
  147. sqlspec/adapters/oracledb/__init__.py +39 -0
  148. sqlspec/adapters/oracledb/_json_handlers.cp314-win_amd64.pyd +0 -0
  149. sqlspec/adapters/oracledb/_json_handlers.py +196 -0
  150. sqlspec/adapters/oracledb/_param_types.cp314-win_amd64.pyd +0 -0
  151. sqlspec/adapters/oracledb/_param_types.py +46 -0
  152. sqlspec/adapters/oracledb/_typing.py +258 -0
  153. sqlspec/adapters/oracledb/_uuid_handlers.cp314-win_amd64.pyd +0 -0
  154. sqlspec/adapters/oracledb/_uuid_handlers.py +163 -0
  155. sqlspec/adapters/oracledb/_vector_handlers.cp314-win_amd64.pyd +0 -0
  156. sqlspec/adapters/oracledb/_vector_handlers.py +228 -0
  157. sqlspec/adapters/oracledb/adk/__init__.py +21 -0
  158. sqlspec/adapters/oracledb/adk/store.py +2453 -0
  159. sqlspec/adapters/oracledb/config.py +575 -0
  160. sqlspec/adapters/oracledb/core.cp314-win_amd64.pyd +0 -0
  161. sqlspec/adapters/oracledb/core.py +820 -0
  162. sqlspec/adapters/oracledb/data_dictionary.py +404 -0
  163. sqlspec/adapters/oracledb/driver.py +1277 -0
  164. sqlspec/adapters/oracledb/events/__init__.py +16 -0
  165. sqlspec/adapters/oracledb/events/_hub.py +345 -0
  166. sqlspec/adapters/oracledb/events/backend.py +300 -0
  167. sqlspec/adapters/oracledb/events/store.py +420 -0
  168. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  169. sqlspec/adapters/oracledb/litestar/store.py +781 -0
  170. sqlspec/adapters/oracledb/migrations.py +539 -0
  171. sqlspec/adapters/oracledb/type_converter.cp314-win_amd64.pyd +0 -0
  172. sqlspec/adapters/oracledb/type_converter.py +211 -0
  173. sqlspec/adapters/psqlpy/__init__.py +18 -0
  174. sqlspec/adapters/psqlpy/_typing.py +121 -0
  175. sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
  176. sqlspec/adapters/psqlpy/adk/store.py +591 -0
  177. sqlspec/adapters/psqlpy/config.py +376 -0
  178. sqlspec/adapters/psqlpy/core.cp314-win_amd64.pyd +0 -0
  179. sqlspec/adapters/psqlpy/core.py +694 -0
  180. sqlspec/adapters/psqlpy/data_dictionary.py +121 -0
  181. sqlspec/adapters/psqlpy/driver.py +411 -0
  182. sqlspec/adapters/psqlpy/events/__init__.py +6 -0
  183. sqlspec/adapters/psqlpy/events/_hub.py +204 -0
  184. sqlspec/adapters/psqlpy/events/backend.py +210 -0
  185. sqlspec/adapters/psqlpy/events/store.py +20 -0
  186. sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
  187. sqlspec/adapters/psqlpy/litestar/store.py +270 -0
  188. sqlspec/adapters/psqlpy/type_converter.cp314-win_amd64.pyd +0 -0
  189. sqlspec/adapters/psqlpy/type_converter.py +113 -0
  190. sqlspec/adapters/psycopg/__init__.py +38 -0
  191. sqlspec/adapters/psycopg/_typing.py +218 -0
  192. sqlspec/adapters/psycopg/adk/__init__.py +10 -0
  193. sqlspec/adapters/psycopg/adk/store.py +1106 -0
  194. sqlspec/adapters/psycopg/config.py +695 -0
  195. sqlspec/adapters/psycopg/core.cp314-win_amd64.pyd +0 -0
  196. sqlspec/adapters/psycopg/core.py +520 -0
  197. sqlspec/adapters/psycopg/data_dictionary.py +278 -0
  198. sqlspec/adapters/psycopg/driver.py +1033 -0
  199. sqlspec/adapters/psycopg/events/__init__.py +20 -0
  200. sqlspec/adapters/psycopg/events/_hub.py +388 -0
  201. sqlspec/adapters/psycopg/events/backend.py +398 -0
  202. sqlspec/adapters/psycopg/events/store.py +42 -0
  203. sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
  204. sqlspec/adapters/psycopg/litestar/store.py +554 -0
  205. sqlspec/adapters/psycopg/type_converter.cp314-win_amd64.pyd +0 -0
  206. sqlspec/adapters/psycopg/type_converter.py +93 -0
  207. sqlspec/adapters/pymysql/__init__.py +21 -0
  208. sqlspec/adapters/pymysql/_typing.py +92 -0
  209. sqlspec/adapters/pymysql/adk/__init__.py +5 -0
  210. sqlspec/adapters/pymysql/adk/store.py +657 -0
  211. sqlspec/adapters/pymysql/config.py +176 -0
  212. sqlspec/adapters/pymysql/core.cp314-win_amd64.pyd +0 -0
  213. sqlspec/adapters/pymysql/core.py +469 -0
  214. sqlspec/adapters/pymysql/data_dictionary.py +120 -0
  215. sqlspec/adapters/pymysql/driver.py +271 -0
  216. sqlspec/adapters/pymysql/events/__init__.py +5 -0
  217. sqlspec/adapters/pymysql/events/store.py +50 -0
  218. sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
  219. sqlspec/adapters/pymysql/litestar/store.py +232 -0
  220. sqlspec/adapters/pymysql/pool.cp314-win_amd64.pyd +0 -0
  221. sqlspec/adapters/pymysql/pool.py +184 -0
  222. sqlspec/adapters/spanner/__init__.py +33 -0
  223. sqlspec/adapters/spanner/_typing.py +102 -0
  224. sqlspec/adapters/spanner/adk/__init__.py +5 -0
  225. sqlspec/adapters/spanner/adk/store.py +758 -0
  226. sqlspec/adapters/spanner/config.py +355 -0
  227. sqlspec/adapters/spanner/core.cp314-win_amd64.pyd +0 -0
  228. sqlspec/adapters/spanner/core.py +263 -0
  229. sqlspec/adapters/spanner/data_dictionary.py +120 -0
  230. sqlspec/adapters/spanner/driver.py +407 -0
  231. sqlspec/adapters/spanner/events/__init__.py +5 -0
  232. sqlspec/adapters/spanner/events/store.py +187 -0
  233. sqlspec/adapters/spanner/litestar/__init__.py +5 -0
  234. sqlspec/adapters/spanner/litestar/store.py +291 -0
  235. sqlspec/adapters/spanner/type_converter.cp314-win_amd64.pyd +0 -0
  236. sqlspec/adapters/spanner/type_converter.py +342 -0
  237. sqlspec/adapters/sqlite/__init__.py +19 -0
  238. sqlspec/adapters/sqlite/_typing.py +123 -0
  239. sqlspec/adapters/sqlite/adk/__init__.py +5 -0
  240. sqlspec/adapters/sqlite/adk/store.py +992 -0
  241. sqlspec/adapters/sqlite/config.py +240 -0
  242. sqlspec/adapters/sqlite/core.cp314-win_amd64.pyd +0 -0
  243. sqlspec/adapters/sqlite/core.py +357 -0
  244. sqlspec/adapters/sqlite/data_dictionary.py +198 -0
  245. sqlspec/adapters/sqlite/driver.py +527 -0
  246. sqlspec/adapters/sqlite/events/__init__.py +5 -0
  247. sqlspec/adapters/sqlite/events/store.py +20 -0
  248. sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
  249. sqlspec/adapters/sqlite/litestar/store.py +316 -0
  250. sqlspec/adapters/sqlite/pool.cp314-win_amd64.pyd +0 -0
  251. sqlspec/adapters/sqlite/pool.py +237 -0
  252. sqlspec/adapters/sqlite/type_converter.cp314-win_amd64.pyd +0 -0
  253. sqlspec/adapters/sqlite/type_converter.py +114 -0
  254. sqlspec/base.py +832 -0
  255. sqlspec/builder/__init__.py +181 -0
  256. sqlspec/builder/_base.cp314-win_amd64.pyd +0 -0
  257. sqlspec/builder/_base.py +1071 -0
  258. sqlspec/builder/_column.cp314-win_amd64.pyd +0 -0
  259. sqlspec/builder/_column.py +521 -0
  260. sqlspec/builder/_ddl.cp314-win_amd64.pyd +0 -0
  261. sqlspec/builder/_ddl.py +1691 -0
  262. sqlspec/builder/_delete.cp314-win_amd64.pyd +0 -0
  263. sqlspec/builder/_delete.py +95 -0
  264. sqlspec/builder/_dml.cp314-win_amd64.pyd +0 -0
  265. sqlspec/builder/_dml.py +386 -0
  266. sqlspec/builder/_explain.cp314-win_amd64.pyd +0 -0
  267. sqlspec/builder/_explain.py +579 -0
  268. sqlspec/builder/_expression_wrappers.cp314-win_amd64.pyd +0 -0
  269. sqlspec/builder/_expression_wrappers.py +46 -0
  270. sqlspec/builder/_factory.cp314-win_amd64.pyd +0 -0
  271. sqlspec/builder/_factory.py +1884 -0
  272. sqlspec/builder/_insert.cp314-win_amd64.pyd +0 -0
  273. sqlspec/builder/_insert.py +405 -0
  274. sqlspec/builder/_join.cp314-win_amd64.pyd +0 -0
  275. sqlspec/builder/_join.py +489 -0
  276. sqlspec/builder/_merge.cp314-win_amd64.pyd +0 -0
  277. sqlspec/builder/_merge.py +823 -0
  278. sqlspec/builder/_parsing_utils.cp314-win_amd64.pyd +0 -0
  279. sqlspec/builder/_parsing_utils.py +295 -0
  280. sqlspec/builder/_select.cp314-win_amd64.pyd +0 -0
  281. sqlspec/builder/_select.py +1666 -0
  282. sqlspec/builder/_temporal.cp314-win_amd64.pyd +0 -0
  283. sqlspec/builder/_temporal.py +167 -0
  284. sqlspec/builder/_update.cp314-win_amd64.pyd +0 -0
  285. sqlspec/builder/_update.py +173 -0
  286. sqlspec/builder/_vector_distance.cp314-win_amd64.pyd +0 -0
  287. sqlspec/builder/_vector_distance.py +330 -0
  288. sqlspec/cli.py +1095 -0
  289. sqlspec/config.py +2383 -0
  290. sqlspec/core/__init__.py +372 -0
  291. sqlspec/core/_correlation.cp314-win_amd64.pyd +0 -0
  292. sqlspec/core/_correlation.py +176 -0
  293. sqlspec/core/_pagination.py +42 -0
  294. sqlspec/core/_pool.cp314-win_amd64.pyd +0 -0
  295. sqlspec/core/_pool.py +76 -0
  296. sqlspec/core/cache.cp314-win_amd64.pyd +0 -0
  297. sqlspec/core/cache.py +1085 -0
  298. sqlspec/core/compiler.cp314-win_amd64.pyd +0 -0
  299. sqlspec/core/compiler.py +1090 -0
  300. sqlspec/core/config_runtime.cp314-win_amd64.pyd +0 -0
  301. sqlspec/core/config_runtime.py +174 -0
  302. sqlspec/core/explain.cp314-win_amd64.pyd +0 -0
  303. sqlspec/core/explain.py +275 -0
  304. sqlspec/core/filters.cp314-win_amd64.pyd +0 -0
  305. sqlspec/core/filters.py +969 -0
  306. sqlspec/core/hashing.cp314-win_amd64.pyd +0 -0
  307. sqlspec/core/hashing.py +266 -0
  308. sqlspec/core/metrics.cp314-win_amd64.pyd +0 -0
  309. sqlspec/core/metrics.py +83 -0
  310. sqlspec/core/parameters/__init__.py +72 -0
  311. sqlspec/core/parameters/_alignment.cp314-win_amd64.pyd +0 -0
  312. sqlspec/core/parameters/_alignment.py +283 -0
  313. sqlspec/core/parameters/_converter.cp314-win_amd64.pyd +0 -0
  314. sqlspec/core/parameters/_converter.py +554 -0
  315. sqlspec/core/parameters/_processor.cp314-win_amd64.pyd +0 -0
  316. sqlspec/core/parameters/_processor.py +1182 -0
  317. sqlspec/core/parameters/_registry.cp314-win_amd64.pyd +0 -0
  318. sqlspec/core/parameters/_registry.py +206 -0
  319. sqlspec/core/parameters/_transformers.cp314-win_amd64.pyd +0 -0
  320. sqlspec/core/parameters/_transformers.py +324 -0
  321. sqlspec/core/parameters/_types.cp314-win_amd64.pyd +0 -0
  322. sqlspec/core/parameters/_types.py +536 -0
  323. sqlspec/core/parameters/_validator.cp314-win_amd64.pyd +0 -0
  324. sqlspec/core/parameters/_validator.py +171 -0
  325. sqlspec/core/pipeline.cp314-win_amd64.pyd +0 -0
  326. sqlspec/core/pipeline.py +333 -0
  327. sqlspec/core/query_modifiers.cp314-win_amd64.pyd +0 -0
  328. sqlspec/core/query_modifiers.py +508 -0
  329. sqlspec/core/result/__init__.py +25 -0
  330. sqlspec/core/result/_base.cp314-win_amd64.pyd +0 -0
  331. sqlspec/core/result/_base.py +1232 -0
  332. sqlspec/core/result/_io.cp314-win_amd64.pyd +0 -0
  333. sqlspec/core/result/_io.py +28 -0
  334. sqlspec/core/splitter.cp314-win_amd64.pyd +0 -0
  335. sqlspec/core/splitter.py +1021 -0
  336. sqlspec/core/sqlcommenter.cp314-win_amd64.pyd +0 -0
  337. sqlspec/core/sqlcommenter.py +249 -0
  338. sqlspec/core/stack.cp314-win_amd64.pyd +0 -0
  339. sqlspec/core/stack.py +163 -0
  340. sqlspec/core/statement.cp314-win_amd64.pyd +0 -0
  341. sqlspec/core/statement.py +1865 -0
  342. sqlspec/core/type_converter.cp314-win_amd64.pyd +0 -0
  343. sqlspec/core/type_converter.py +340 -0
  344. sqlspec/data_dictionary/__init__.py +22 -0
  345. sqlspec/data_dictionary/_loader.cp314-win_amd64.pyd +0 -0
  346. sqlspec/data_dictionary/_loader.py +138 -0
  347. sqlspec/data_dictionary/_registry.cp314-win_amd64.pyd +0 -0
  348. sqlspec/data_dictionary/_registry.py +74 -0
  349. sqlspec/data_dictionary/_types.cp314-win_amd64.pyd +0 -0
  350. sqlspec/data_dictionary/_types.py +121 -0
  351. sqlspec/data_dictionary/dialects/__init__.py +21 -0
  352. sqlspec/data_dictionary/dialects/bigquery.cp314-win_amd64.pyd +0 -0
  353. sqlspec/data_dictionary/dialects/bigquery.py +81 -0
  354. sqlspec/data_dictionary/dialects/cockroachdb.cp314-win_amd64.pyd +0 -0
  355. sqlspec/data_dictionary/dialects/cockroachdb.py +54 -0
  356. sqlspec/data_dictionary/dialects/duckdb.cp314-win_amd64.pyd +0 -0
  357. sqlspec/data_dictionary/dialects/duckdb.py +47 -0
  358. sqlspec/data_dictionary/dialects/mysql.cp314-win_amd64.pyd +0 -0
  359. sqlspec/data_dictionary/dialects/mysql.py +53 -0
  360. sqlspec/data_dictionary/dialects/oracle.cp314-win_amd64.pyd +0 -0
  361. sqlspec/data_dictionary/dialects/oracle.py +197 -0
  362. sqlspec/data_dictionary/dialects/postgres.cp314-win_amd64.pyd +0 -0
  363. sqlspec/data_dictionary/dialects/postgres.py +69 -0
  364. sqlspec/data_dictionary/dialects/spanner.cp314-win_amd64.pyd +0 -0
  365. sqlspec/data_dictionary/dialects/spanner.py +37 -0
  366. sqlspec/data_dictionary/dialects/sqlite.cp314-win_amd64.pyd +0 -0
  367. sqlspec/data_dictionary/dialects/sqlite.py +59 -0
  368. sqlspec/data_dictionary/sql/.gitkeep +0 -0
  369. sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
  370. sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
  371. sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
  372. sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
  373. sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
  374. sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
  375. sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
  376. sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
  377. sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
  378. sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
  379. sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
  380. sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
  381. sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
  382. sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
  383. sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
  384. sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
  385. sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
  386. sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
  387. sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
  388. sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
  389. sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
  390. sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
  391. sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
  392. sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
  393. sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
  394. sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
  395. sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
  396. sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
  397. sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
  398. sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
  399. sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
  400. sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
  401. sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
  402. sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
  403. sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
  404. sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
  405. sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
  406. sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
  407. sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
  408. sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
  409. sqlspec/dialects/__init__.py +22 -0
  410. sqlspec/dialects/_compat.cp314-win_amd64.pyd +0 -0
  411. sqlspec/dialects/_compat.py +14 -0
  412. sqlspec/dialects/postgres/__init__.py +9 -0
  413. sqlspec/dialects/postgres/_generators.cp314-win_amd64.pyd +0 -0
  414. sqlspec/dialects/postgres/_generators.py +57 -0
  415. sqlspec/dialects/postgres/_operators.cp314-win_amd64.pyd +0 -0
  416. sqlspec/dialects/postgres/_operators.py +81 -0
  417. sqlspec/dialects/postgres/_paradedb.py +50 -0
  418. sqlspec/dialects/postgres/_pgvector.py +36 -0
  419. sqlspec/dialects/spanner/__init__.py +6 -0
  420. sqlspec/dialects/spanner/_generators.cp314-win_amd64.pyd +0 -0
  421. sqlspec/dialects/spanner/_generators.py +206 -0
  422. sqlspec/dialects/spanner/_spangres.py +77 -0
  423. sqlspec/dialects/spanner/_spanner.py +179 -0
  424. sqlspec/driver/__init__.py +49 -0
  425. sqlspec/driver/_async.cp314-win_amd64.pyd +0 -0
  426. sqlspec/driver/_async.py +1830 -0
  427. sqlspec/driver/_common.cp314-win_amd64.pyd +0 -0
  428. sqlspec/driver/_common.py +2292 -0
  429. sqlspec/driver/_exception_handler.cp314-win_amd64.pyd +0 -0
  430. sqlspec/driver/_exception_handler.py +108 -0
  431. sqlspec/driver/_query_cache.cp314-win_amd64.pyd +0 -0
  432. sqlspec/driver/_query_cache.py +96 -0
  433. sqlspec/driver/_sql_helpers.cp314-win_amd64.pyd +0 -0
  434. sqlspec/driver/_sql_helpers.py +139 -0
  435. sqlspec/driver/_storage_helpers.cp314-win_amd64.pyd +0 -0
  436. sqlspec/driver/_storage_helpers.py +153 -0
  437. sqlspec/driver/_sync.cp314-win_amd64.pyd +0 -0
  438. sqlspec/driver/_sync.py +1817 -0
  439. sqlspec/exceptions.cp314-win_amd64.pyd +0 -0
  440. sqlspec/exceptions.py +480 -0
  441. sqlspec/extensions/__init__.py +0 -0
  442. sqlspec/extensions/adk/__init__.py +84 -0
  443. sqlspec/extensions/adk/_config_utils.py +199 -0
  444. sqlspec/extensions/adk/_types.cp314-win_amd64.pyd +0 -0
  445. sqlspec/extensions/adk/_types.py +41 -0
  446. sqlspec/extensions/adk/artifact/__init__.py +57 -0
  447. sqlspec/extensions/adk/artifact/_types.cp314-win_amd64.pyd +0 -0
  448. sqlspec/extensions/adk/artifact/_types.py +32 -0
  449. sqlspec/extensions/adk/artifact/service.py +508 -0
  450. sqlspec/extensions/adk/artifact/store.py +361 -0
  451. sqlspec/extensions/adk/converters.py +212 -0
  452. sqlspec/extensions/adk/memory/__init__.py +69 -0
  453. sqlspec/extensions/adk/memory/_types.cp314-win_amd64.pyd +0 -0
  454. sqlspec/extensions/adk/memory/_types.py +30 -0
  455. sqlspec/extensions/adk/memory/converters.py +225 -0
  456. sqlspec/extensions/adk/memory/service.py +316 -0
  457. sqlspec/extensions/adk/memory/store.py +525 -0
  458. sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +184 -0
  459. sqlspec/extensions/adk/migrations/__init__.py +0 -0
  460. sqlspec/extensions/adk/service.py +279 -0
  461. sqlspec/extensions/adk/store.py +590 -0
  462. sqlspec/extensions/events/__init__.py +51 -0
  463. sqlspec/extensions/events/_channel.py +703 -0
  464. sqlspec/extensions/events/_hints.cp314-win_amd64.pyd +0 -0
  465. sqlspec/extensions/events/_hints.py +45 -0
  466. sqlspec/extensions/events/_models.py +23 -0
  467. sqlspec/extensions/events/_payload.cp314-win_amd64.pyd +0 -0
  468. sqlspec/extensions/events/_payload.py +69 -0
  469. sqlspec/extensions/events/_protocols.py +134 -0
  470. sqlspec/extensions/events/_queue.py +462 -0
  471. sqlspec/extensions/events/_store.py +209 -0
  472. sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
  473. sqlspec/extensions/events/migrations/__init__.py +3 -0
  474. sqlspec/extensions/fastapi/__init__.py +22 -0
  475. sqlspec/extensions/fastapi/extension.py +391 -0
  476. sqlspec/extensions/fastapi/providers.cp314-win_amd64.pyd +0 -0
  477. sqlspec/extensions/fastapi/providers.py +712 -0
  478. sqlspec/extensions/flask/__init__.py +38 -0
  479. sqlspec/extensions/flask/_state.py +87 -0
  480. sqlspec/extensions/flask/_utils.py +71 -0
  481. sqlspec/extensions/flask/extension.py +539 -0
  482. sqlspec/extensions/litestar/__init__.py +31 -0
  483. sqlspec/extensions/litestar/_utils.py +52 -0
  484. sqlspec/extensions/litestar/channels.py +165 -0
  485. sqlspec/extensions/litestar/cli.py +102 -0
  486. sqlspec/extensions/litestar/config.py +90 -0
  487. sqlspec/extensions/litestar/handlers.py +316 -0
  488. sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
  489. sqlspec/extensions/litestar/migrations/__init__.py +3 -0
  490. sqlspec/extensions/litestar/plugin.py +1066 -0
  491. sqlspec/extensions/litestar/providers.cp314-win_amd64.pyd +0 -0
  492. sqlspec/extensions/litestar/providers.py +784 -0
  493. sqlspec/extensions/litestar/store.py +298 -0
  494. sqlspec/extensions/otel/__init__.py +58 -0
  495. sqlspec/extensions/prometheus/__init__.py +113 -0
  496. sqlspec/extensions/sanic/__init__.py +19 -0
  497. sqlspec/extensions/sanic/_state.py +43 -0
  498. sqlspec/extensions/sanic/_utils.py +127 -0
  499. sqlspec/extensions/sanic/extension.py +647 -0
  500. sqlspec/extensions/starlette/__init__.py +22 -0
  501. sqlspec/extensions/starlette/_state.py +42 -0
  502. sqlspec/extensions/starlette/_utils.py +96 -0
  503. sqlspec/extensions/starlette/extension.py +374 -0
  504. sqlspec/extensions/starlette/middleware.py +281 -0
  505. sqlspec/loader.cp314-win_amd64.pyd +0 -0
  506. sqlspec/loader.py +727 -0
  507. sqlspec/migrations/__init__.py +39 -0
  508. sqlspec/migrations/base.cp314-win_amd64.pyd +0 -0
  509. sqlspec/migrations/base.py +862 -0
  510. sqlspec/migrations/commands.py +2151 -0
  511. sqlspec/migrations/context.cp314-win_amd64.pyd +0 -0
  512. sqlspec/migrations/context.py +157 -0
  513. sqlspec/migrations/fix.cp314-win_amd64.pyd +0 -0
  514. sqlspec/migrations/fix.py +204 -0
  515. sqlspec/migrations/loaders.cp314-win_amd64.pyd +0 -0
  516. sqlspec/migrations/loaders.py +443 -0
  517. sqlspec/migrations/runner.cp314-win_amd64.pyd +0 -0
  518. sqlspec/migrations/runner.py +1195 -0
  519. sqlspec/migrations/squash.cp314-win_amd64.pyd +0 -0
  520. sqlspec/migrations/squash.py +490 -0
  521. sqlspec/migrations/templates.cp314-win_amd64.pyd +0 -0
  522. sqlspec/migrations/templates.py +234 -0
  523. sqlspec/migrations/tracker.cp314-win_amd64.pyd +0 -0
  524. sqlspec/migrations/tracker.py +792 -0
  525. sqlspec/migrations/utils.cp314-win_amd64.pyd +0 -0
  526. sqlspec/migrations/utils.py +256 -0
  527. sqlspec/migrations/validation.cp314-win_amd64.pyd +0 -0
  528. sqlspec/migrations/validation.py +359 -0
  529. sqlspec/migrations/version.cp314-win_amd64.pyd +0 -0
  530. sqlspec/migrations/version.py +446 -0
  531. sqlspec/observability/__init__.py +57 -0
  532. sqlspec/observability/_common.cp314-win_amd64.pyd +0 -0
  533. sqlspec/observability/_common.py +77 -0
  534. sqlspec/observability/_config.cp314-win_amd64.pyd +0 -0
  535. sqlspec/observability/_config.py +364 -0
  536. sqlspec/observability/_diagnostics.cp314-win_amd64.pyd +0 -0
  537. sqlspec/observability/_diagnostics.py +74 -0
  538. sqlspec/observability/_dispatcher.cp314-win_amd64.pyd +0 -0
  539. sqlspec/observability/_dispatcher.py +200 -0
  540. sqlspec/observability/_formatters/__init__.py +13 -0
  541. sqlspec/observability/_formatters/_aws.cp314-win_amd64.pyd +0 -0
  542. sqlspec/observability/_formatters/_aws.py +102 -0
  543. sqlspec/observability/_formatters/_azure.cp314-win_amd64.pyd +0 -0
  544. sqlspec/observability/_formatters/_azure.py +96 -0
  545. sqlspec/observability/_formatters/_base.cp314-win_amd64.pyd +0 -0
  546. sqlspec/observability/_formatters/_base.py +57 -0
  547. sqlspec/observability/_formatters/_gcp.cp314-win_amd64.pyd +0 -0
  548. sqlspec/observability/_formatters/_gcp.py +131 -0
  549. sqlspec/observability/_formatting.py +58 -0
  550. sqlspec/observability/_observer.cp314-win_amd64.pyd +0 -0
  551. sqlspec/observability/_observer.py +361 -0
  552. sqlspec/observability/_runtime.cp314-win_amd64.pyd +0 -0
  553. sqlspec/observability/_runtime.py +461 -0
  554. sqlspec/observability/_sampling.cp314-win_amd64.pyd +0 -0
  555. sqlspec/observability/_sampling.py +188 -0
  556. sqlspec/observability/_spans.cp314-win_amd64.pyd +0 -0
  557. sqlspec/observability/_spans.py +161 -0
  558. sqlspec/protocols.py +955 -0
  559. sqlspec/py.typed +0 -0
  560. sqlspec/service.py +433 -0
  561. sqlspec/storage/__init__.py +48 -0
  562. sqlspec/storage/_arrow_payload.py +68 -0
  563. sqlspec/storage/_paths.cp314-win_amd64.pyd +0 -0
  564. sqlspec/storage/_paths.py +58 -0
  565. sqlspec/storage/_utils.py +46 -0
  566. sqlspec/storage/backends/__init__.py +1 -0
  567. sqlspec/storage/backends/base.cp314-win_amd64.pyd +0 -0
  568. sqlspec/storage/backends/base.py +374 -0
  569. sqlspec/storage/backends/fsspec.py +574 -0
  570. sqlspec/storage/backends/local.py +468 -0
  571. sqlspec/storage/backends/obstore.py +956 -0
  572. sqlspec/storage/errors.cp314-win_amd64.pyd +0 -0
  573. sqlspec/storage/errors.py +102 -0
  574. sqlspec/storage/pipeline.cp314-win_amd64.pyd +0 -0
  575. sqlspec/storage/pipeline.py +628 -0
  576. sqlspec/storage/registry.cp314-win_amd64.pyd +0 -0
  577. sqlspec/storage/registry.py +329 -0
  578. sqlspec/typing.py +405 -0
  579. sqlspec/utils/__init__.py +7 -0
  580. sqlspec/utils/arrow_helpers.py +384 -0
  581. sqlspec/utils/config_tools.cp314-win_amd64.pyd +0 -0
  582. sqlspec/utils/config_tools.py +314 -0
  583. sqlspec/utils/correlation.cp314-win_amd64.pyd +0 -0
  584. sqlspec/utils/correlation.py +134 -0
  585. sqlspec/utils/deprecation.cp314-win_amd64.pyd +0 -0
  586. sqlspec/utils/deprecation.py +157 -0
  587. sqlspec/utils/dispatch.cp314-win_amd64.pyd +0 -0
  588. sqlspec/utils/dispatch.py +101 -0
  589. sqlspec/utils/fixtures.cp314-win_amd64.pyd +0 -0
  590. sqlspec/utils/fixtures.py +260 -0
  591. sqlspec/utils/logging.cp314-win_amd64.pyd +0 -0
  592. sqlspec/utils/logging.py +251 -0
  593. sqlspec/utils/module_loader.py +306 -0
  594. sqlspec/utils/portal.cp314-win_amd64.pyd +0 -0
  595. sqlspec/utils/portal.py +377 -0
  596. sqlspec/utils/schema.cp314-win_amd64.pyd +0 -0
  597. sqlspec/utils/schema.py +1040 -0
  598. sqlspec/utils/serializers/__init__.py +30 -0
  599. sqlspec/utils/serializers/_json.cp314-win_amd64.pyd +0 -0
  600. sqlspec/utils/serializers/_json.py +415 -0
  601. sqlspec/utils/serializers/_numpy.cp314-win_amd64.pyd +0 -0
  602. sqlspec/utils/serializers/_numpy.py +65 -0
  603. sqlspec/utils/serializers/_schema.cp314-win_amd64.pyd +0 -0
  604. sqlspec/utils/serializers/_schema.py +285 -0
  605. sqlspec/utils/singleton.cp314-win_amd64.pyd +0 -0
  606. sqlspec/utils/singleton.py +41 -0
  607. sqlspec/utils/sync_tools.cp314-win_amd64.pyd +0 -0
  608. sqlspec/utils/sync_tools.py +316 -0
  609. sqlspec/utils/text.cp314-win_amd64.pyd +0 -0
  610. sqlspec/utils/text.py +109 -0
  611. sqlspec/utils/type_converters.cp314-win_amd64.pyd +0 -0
  612. sqlspec/utils/type_converters.py +216 -0
  613. sqlspec/utils/type_guards.cp314-win_amd64.pyd +0 -0
  614. sqlspec/utils/type_guards.py +1508 -0
  615. sqlspec/utils/uuids.cp314-win_amd64.pyd +0 -0
  616. sqlspec/utils/uuids.py +241 -0
  617. sqlspec-0.47.0.dist-info/METADATA +202 -0
  618. sqlspec-0.47.0.dist-info/RECORD +621 -0
  619. sqlspec-0.47.0.dist-info/WHEEL +4 -0
  620. sqlspec-0.47.0.dist-info/entry_points.txt +6 -0
  621. sqlspec-0.47.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1277 @@
1
+ """Oracle Driver"""
2
+
3
+ import logging
4
+ from typing import TYPE_CHECKING, Any, NamedTuple, cast
5
+
6
+ import oracledb
7
+
8
+ from sqlspec.adapters.oracledb._typing import (
9
+ OracleAsyncConnection,
10
+ OracleAsyncCursor,
11
+ OracleAsyncSessionContext,
12
+ OracleSyncConnection,
13
+ OracleSyncCursor,
14
+ OracleSyncSessionContext,
15
+ )
16
+ from sqlspec.adapters.oracledb.core import (
17
+ ORACLEDB_VERSION,
18
+ build_insert_statement,
19
+ build_pipeline_stack_result,
20
+ build_truncate_statement,
21
+ coerce_large_parameters_async,
22
+ coerce_large_parameters_sync,
23
+ collect_async_rows,
24
+ collect_sync_rows,
25
+ create_mapped_exception,
26
+ default_statement_config,
27
+ driver_profile,
28
+ normalize_column_names,
29
+ normalize_execute_many_parameters_async,
30
+ normalize_execute_many_parameters_sync,
31
+ resolve_row_metadata,
32
+ resolve_rowcount,
33
+ )
34
+ from sqlspec.adapters.oracledb.data_dictionary import OracledbAsyncDataDictionary, OracledbSyncDataDictionary
35
+ from sqlspec.core import (
36
+ SQL,
37
+ StackResult,
38
+ StatementConfig,
39
+ StatementStack,
40
+ build_arrow_result_from_table,
41
+ get_cache_config,
42
+ register_driver_profile,
43
+ )
44
+ from sqlspec.driver import (
45
+ AsyncDriverAdapterBase,
46
+ BaseAsyncExceptionHandler,
47
+ BaseSyncExceptionHandler,
48
+ StackExecutionObserver,
49
+ SyncDriverAdapterBase,
50
+ describe_stack_statement,
51
+ hash_stack_operations,
52
+ )
53
+ from sqlspec.exceptions import ImproperConfigurationError, SQLSpecError, StackExecutionError
54
+ from sqlspec.utils.logging import get_logger, log_with_context
55
+ from sqlspec.utils.module_loader import ensure_pyarrow
56
+ from sqlspec.utils.type_guards import has_pipeline_capability
57
+
58
+ if TYPE_CHECKING:
59
+ from collections.abc import Sequence
60
+
61
+ from sqlspec.adapters.oracledb._typing import OraclePipelineDriver
62
+ from sqlspec.builder import QueryBuilder
63
+ from sqlspec.core import ArrowResult, Statement, StatementConfig, StatementFilter
64
+ from sqlspec.core.stack import StackOperation
65
+ from sqlspec.driver import ExecutionResult
66
+ from sqlspec.storage import StorageBridgeJob, StorageDestination, StorageFormat, StorageTelemetry
67
+ from sqlspec.typing import ArrowReturnFormat, StatementParameters, VersionInfo
68
+
69
+
70
+ logger = get_logger(__name__)
71
+
72
+ # Oracle SQL-context byte thresholds (4000 / 2000) live in driver_features so users
73
+ # on MAX_STRING_SIZE=EXTENDED databases can override them; defaults are wired in
74
+ # core.apply_driver_features and read at the dispatch_execute call sites below.
75
+
76
+ __all__ = (
77
+ "OracleAsyncDriver",
78
+ "OracleAsyncExceptionHandler",
79
+ "OracleAsyncSessionContext",
80
+ "OracleSyncDriver",
81
+ "OracleSyncExceptionHandler",
82
+ "OracleSyncSessionContext",
83
+ )
84
+
85
+ PIPELINE_MIN_DRIVER_VERSION: "tuple[int, int, int]" = (2, 4, 0)
86
+ PIPELINE_MIN_DATABASE_MAJOR: int = 23
87
+
88
+
89
+ class _CompiledStackOperation(NamedTuple):
90
+ statement: SQL
91
+ sql: str
92
+ parameters: Any
93
+ method: str
94
+ returns_rows: bool
95
+ summary: str
96
+
97
+
98
+ class OraclePipelineMixin:
99
+ """Shared helpers for Oracle pipeline execution."""
100
+
101
+ __slots__ = ()
102
+
103
+ def _stack_native_blocker(self, stack: "StatementStack") -> "str | None":
104
+ for operation in stack.operations:
105
+ if operation.method == "execute_arrow":
106
+ return "arrow_operation"
107
+ if operation.method == "execute_script":
108
+ return "script_operation"
109
+ return None
110
+
111
+ def _log_pipeline_skip(self, reason: str, stack: "StatementStack") -> None:
112
+ log_level = logging.INFO if reason == "env_override" else logging.DEBUG
113
+ log_with_context(
114
+ logger,
115
+ log_level,
116
+ "stack.native_pipeline.skip",
117
+ driver=type(self).__name__,
118
+ reason=reason,
119
+ hashed_operations=hash_stack_operations(stack),
120
+ )
121
+
122
+ def _prepare_pipeline_operation(self, operation: "StackOperation") -> _CompiledStackOperation:
123
+ driver = cast("OraclePipelineDriver", self)
124
+ kwargs = dict(operation.keyword_arguments) if operation.keyword_arguments else {}
125
+ statement_config = kwargs.pop("statement_config", None)
126
+ config = statement_config or driver.statement_config
127
+
128
+ if operation.method == "execute":
129
+ sql_statement = driver.prepare_statement(
130
+ operation.statement, operation.arguments, statement_config=config, kwargs=kwargs
131
+ )
132
+ elif operation.method == "execute_many":
133
+ if not operation.arguments:
134
+ msg = "execute_many stack operation requires parameter sets"
135
+ raise ValueError(msg)
136
+ parameter_sets = operation.arguments[0]
137
+ filters = operation.arguments[1:]
138
+ if isinstance(operation.statement, SQL):
139
+ statement_seed = operation.statement.raw_expression or operation.statement.raw_sql
140
+ sql_statement = SQL(statement_seed, parameter_sets, statement_config=config, is_many=True, **kwargs)
141
+ else:
142
+ base_statement = driver.prepare_statement(
143
+ operation.statement, filters, statement_config=config, kwargs=kwargs
144
+ )
145
+ statement_seed = base_statement.raw_expression or base_statement.raw_sql
146
+ sql_statement = SQL(statement_seed, parameter_sets, statement_config=config, is_many=True, **kwargs)
147
+ else:
148
+ msg = f"Unsupported stack operation method: {operation.method}"
149
+ raise ValueError(msg)
150
+
151
+ compiled_sql, prepared_parameters = driver._get_compiled_sql( # pyright: ignore[reportPrivateUsage]
152
+ sql_statement, config
153
+ )
154
+ summary = describe_stack_statement(operation.statement)
155
+ return _CompiledStackOperation(
156
+ statement=sql_statement,
157
+ sql=compiled_sql,
158
+ parameters=prepared_parameters,
159
+ method=operation.method,
160
+ returns_rows=sql_statement.returns_rows(),
161
+ summary=summary,
162
+ )
163
+
164
+ def _add_pipeline_operation(self, pipeline: Any, operation: _CompiledStackOperation) -> None:
165
+ parameters = operation.parameters or []
166
+ if operation.method == "execute":
167
+ if operation.returns_rows:
168
+ pipeline.add_fetchall(operation.sql, parameters)
169
+ else:
170
+ pipeline.add_execute(operation.sql, parameters)
171
+ return
172
+
173
+ if operation.method == "execute_many":
174
+ pipeline.add_executemany(operation.sql, parameters)
175
+ return
176
+
177
+ msg = f"Unsupported pipeline operation: {operation.method}"
178
+ raise ValueError(msg)
179
+
180
+ def _build_stack_results_from_pipeline(
181
+ self,
182
+ compiled_operations: "Sequence[_CompiledStackOperation]",
183
+ pipeline_results: "Sequence[Any]",
184
+ continue_on_error: bool,
185
+ observer: StackExecutionObserver,
186
+ ) -> "list[StackResult]":
187
+ driver = cast("OraclePipelineDriver", self)
188
+ stack_results: list[StackResult] = []
189
+ for index, (compiled, result) in enumerate(zip(compiled_operations, pipeline_results, strict=False)):
190
+ try:
191
+ error = result.error
192
+ except AttributeError:
193
+ error = None
194
+ if error is not None:
195
+ stack_error = StackExecutionError(
196
+ index,
197
+ compiled.summary,
198
+ error,
199
+ adapter=type(self).__name__,
200
+ mode="continue-on-error" if continue_on_error else "fail-fast",
201
+ )
202
+ if continue_on_error:
203
+ observer.record_operation_error(stack_error)
204
+ stack_results.append(StackResult.from_error(stack_error))
205
+ continue
206
+ raise stack_error
207
+
208
+ stack_results.append(
209
+ build_pipeline_stack_result(
210
+ compiled.statement,
211
+ compiled.method,
212
+ compiled.returns_rows,
213
+ compiled.parameters,
214
+ result,
215
+ driver.driver_features,
216
+ )
217
+ )
218
+ return stack_results
219
+
220
+ def _wrap_pipeline_error(
221
+ self, error: Exception, stack: "StatementStack", continue_on_error: bool
222
+ ) -> StackExecutionError:
223
+ mode = "continue-on-error" if continue_on_error else "fail-fast"
224
+ return StackExecutionError(
225
+ -1, "Oracle pipeline execution failed", error, adapter=type(self).__name__, mode=mode
226
+ )
227
+
228
+
229
+ class OracleSyncExceptionHandler(BaseSyncExceptionHandler):
230
+ """Sync Context manager for handling Oracle database exceptions.
231
+
232
+ Maps Oracle ORA-XXXXX error codes to specific SQLSpec exceptions
233
+ for better error handling in application code.
234
+
235
+ Uses deferred exception pattern for mypyc compatibility: exceptions
236
+ are stored in pending_exception rather than raised from __exit__
237
+ to avoid ABI boundary violations with compiled code.
238
+ """
239
+
240
+ __slots__ = ()
241
+
242
+ def _handle_exception(self, exc_type: "type[BaseException] | None", exc_val: "BaseException") -> bool:
243
+ if exc_type is None:
244
+ return False
245
+ if issubclass(exc_type, oracledb.DatabaseError):
246
+ self.pending_exception = create_mapped_exception(exc_val)
247
+ return True
248
+ return False
249
+
250
+
251
+ class OracleAsyncExceptionHandler(BaseAsyncExceptionHandler):
252
+ """Async context manager for handling Oracle database exceptions.
253
+
254
+ Maps Oracle ORA-XXXXX error codes to specific SQLSpec exceptions
255
+ for better error handling in application code.
256
+
257
+ Uses deferred exception pattern for mypyc compatibility: exceptions
258
+ are stored in pending_exception rather than raised from __aexit__
259
+ to avoid ABI boundary violations with compiled code.
260
+ """
261
+
262
+ __slots__ = ()
263
+
264
+ def _handle_exception(self, exc_type: "type[BaseException] | None", exc_val: "BaseException") -> bool:
265
+ if exc_type is None:
266
+ return False
267
+ if issubclass(exc_type, oracledb.DatabaseError):
268
+ self.pending_exception = create_mapped_exception(exc_val)
269
+ return True
270
+ return False
271
+
272
+
273
+ class OracleSyncDriver(OraclePipelineMixin, SyncDriverAdapterBase):
274
+ """Synchronous Oracle Database driver.
275
+
276
+ Provides Oracle Database connectivity with parameter style conversion,
277
+ error handling, and transaction management.
278
+ """
279
+
280
+ __slots__ = (
281
+ "_data_dictionary",
282
+ "_oracle_version",
283
+ "_pipeline_support",
284
+ "_pipeline_support_reason",
285
+ "_row_metadata_cache",
286
+ )
287
+ dialect = "oracle"
288
+
289
+ def __init__(
290
+ self,
291
+ connection: OracleSyncConnection,
292
+ statement_config: "StatementConfig | None" = None,
293
+ driver_features: "dict[str, Any] | None" = None,
294
+ ) -> None:
295
+ if statement_config is None:
296
+ statement_config = default_statement_config.replace(
297
+ enable_caching=get_cache_config().compiled_cache_enabled
298
+ )
299
+
300
+ super().__init__(connection=connection, statement_config=statement_config, driver_features=driver_features)
301
+ self._data_dictionary: OracledbSyncDataDictionary | None = None
302
+ self._pipeline_support: bool | None = None
303
+ self._pipeline_support_reason: str | None = None
304
+ self._oracle_version: VersionInfo | None = None
305
+ self._row_metadata_cache: dict[int, tuple[Any, list[str], bool]] = {}
306
+
307
+ # ─────────────────────────────────────────────────────────────────────────────
308
+ # CORE DISPATCH METHODS
309
+ # ─────────────────────────────────────────────────────────────────────────────
310
+
311
+ def dispatch_execute(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
312
+ """Execute single SQL statement with Oracle data handling.
313
+
314
+ Args:
315
+ cursor: Oracle cursor object
316
+ statement: SQL statement to execute
317
+
318
+ Returns:
319
+ Execution result containing data for SELECT statements or row count for others
320
+
321
+ """
322
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
323
+
324
+ prepared_parameters = coerce_large_parameters_sync(
325
+ self.connection,
326
+ prepared_parameters,
327
+ clob_type=oracledb.DB_TYPE_CLOB,
328
+ blob_type=oracledb.DB_TYPE_BLOB,
329
+ varchar2_byte_limit=self.driver_features.get("oracle_varchar2_byte_limit", 4000),
330
+ raw_byte_limit=self.driver_features.get("oracle_raw_byte_limit", 2000),
331
+ )
332
+ prepared_parameters = cast("list[Any] | tuple[Any, ...] | dict[Any, Any] | None", prepared_parameters)
333
+
334
+ cursor.execute(sql, prepared_parameters or {})
335
+
336
+ # SELECT result processing for Oracle
337
+ if statement.returns_rows():
338
+ fetched_data = cursor.fetchall()
339
+ column_names, requires_lob_coercion = self._resolve_row_metadata(cursor.description)
340
+ data, column_names = collect_sync_rows(
341
+ cast("list[Any] | None", fetched_data),
342
+ cursor.description,
343
+ self.driver_features,
344
+ column_names=column_names,
345
+ requires_lob_coercion=requires_lob_coercion,
346
+ )
347
+
348
+ return self.create_execution_result(
349
+ cursor,
350
+ selected_data=data,
351
+ column_names=column_names,
352
+ data_row_count=len(data),
353
+ is_select_result=True,
354
+ row_format="tuple",
355
+ )
356
+
357
+ # Non-SELECT result processing
358
+ affected_rows = resolve_rowcount(cursor)
359
+ return self.create_execution_result(cursor, rowcount_override=affected_rows)
360
+
361
+ def dispatch_execute_many(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
362
+ """Execute SQL with multiple parameter sets using Oracle batch processing.
363
+
364
+ Args:
365
+ cursor: Oracle cursor object
366
+ statement: SQL statement with multiple parameter sets
367
+
368
+ Returns:
369
+ Execution result with affected row count
370
+
371
+ Raises:
372
+ ValueError: If no parameters are provided
373
+
374
+ """
375
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
376
+
377
+ prepared_parameters = normalize_execute_many_parameters_sync(prepared_parameters)
378
+ cursor.executemany(sql, prepared_parameters)
379
+
380
+ affected_rows = len(prepared_parameters)
381
+
382
+ return self.create_execution_result(cursor, rowcount_override=affected_rows, is_many_result=True)
383
+
384
+ def dispatch_execute_script(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
385
+ """Execute SQL script with statement splitting and parameter handling.
386
+
387
+ Parameters are embedded as static values for script execution compatibility.
388
+
389
+ Args:
390
+ cursor: Oracle cursor object
391
+ statement: SQL script statement to execute
392
+
393
+ Returns:
394
+ Execution result containing statement count and success information
395
+
396
+ """
397
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
398
+ prepared_parameters = cast("list[Any] | tuple[Any, ...] | dict[Any, Any] | None", prepared_parameters)
399
+ statements = self.split_script_statements(sql, statement.statement_config, strip_trailing_semicolon=True)
400
+
401
+ successful_count = 0
402
+ last_cursor = cursor
403
+
404
+ for stmt in statements:
405
+ cursor.execute(stmt, prepared_parameters or {})
406
+ successful_count += 1
407
+
408
+ return self.create_execution_result(
409
+ last_cursor, statement_count=len(statements), successful_statements=successful_count, is_script_result=True
410
+ )
411
+
412
+ # ─────────────────────────────────────────────────────────────────────────────
413
+ # TRANSACTION MANAGEMENT
414
+ # ─────────────────────────────────────────────────────────────────────────────
415
+
416
+ def begin(self) -> None:
417
+ """Begin a database transaction.
418
+
419
+ Oracle handles transactions automatically, so this is a no-op.
420
+ """
421
+ # Oracle handles transactions implicitly
422
+
423
+ def commit(self) -> None:
424
+ """Commit the current transaction.
425
+
426
+ Raises:
427
+ SQLSpecError: If commit fails
428
+
429
+ """
430
+ try:
431
+ self.connection.commit()
432
+ except oracledb.Error as e:
433
+ msg = f"Failed to commit Oracle transaction: {e}"
434
+ raise SQLSpecError(msg) from e
435
+
436
+ def rollback(self) -> None:
437
+ """Rollback the current transaction.
438
+
439
+ Raises:
440
+ SQLSpecError: If rollback fails
441
+
442
+ """
443
+ try:
444
+ self.connection.rollback()
445
+ except oracledb.Error as e:
446
+ msg = f"Failed to rollback Oracle transaction: {e}"
447
+ raise SQLSpecError(msg) from e
448
+
449
+ def with_cursor(self, connection: OracleSyncConnection) -> OracleSyncCursor:
450
+ """Create context manager for Oracle cursor.
451
+
452
+ Args:
453
+ connection: Oracle database connection
454
+
455
+ Returns:
456
+ Context manager for cursor operations
457
+
458
+ """
459
+ return OracleSyncCursor(connection)
460
+
461
+ def handle_database_exceptions(self) -> "OracleSyncExceptionHandler":
462
+ """Handle database-specific exceptions and wrap them appropriately."""
463
+ return OracleSyncExceptionHandler()
464
+
465
+ # ─────────────────────────────────────────────────────────────────────────────
466
+ # ARROW API METHODS
467
+ # ─────────────────────────────────────────────────────────────────────────────
468
+
469
+ def select_to_arrow(
470
+ self,
471
+ statement: "Statement | QueryBuilder",
472
+ /,
473
+ *parameters: "StatementParameters | StatementFilter",
474
+ statement_config: "StatementConfig | None" = None,
475
+ return_format: "ArrowReturnFormat" = "table",
476
+ native_only: bool = False,
477
+ batch_size: int | None = None,
478
+ arrow_schema: Any = None,
479
+ **kwargs: Any,
480
+ ) -> "Any":
481
+ """Execute query and return results as Apache Arrow format using Oracle native support.
482
+
483
+ This implementation uses Oracle's native execute_df()/fetch_df_all() methods
484
+ which return OracleDataFrame objects with Arrow PyCapsule interface, providing
485
+ zero-copy data transfer and 5-10x performance improvement over dict conversion.
486
+ If native Arrow is unavailable and native_only is False, it falls back to the
487
+ conversion path.
488
+
489
+ Args:
490
+ statement: SQL query string, Statement, or QueryBuilder
491
+ *parameters: Query parameters (same format as execute()/select())
492
+ statement_config: Optional statement configuration override
493
+ return_format: "table" for pyarrow.Table (default), "batch" for RecordBatch,
494
+ "batches" for list of RecordBatch, "reader" for RecordBatchReader
495
+ native_only: If True, raise error if native Arrow is unavailable
496
+ batch_size: Rows per batch when using "batch" or "batches" format
497
+ arrow_schema: Optional pyarrow.Schema for type casting
498
+ **kwargs: Additional keyword arguments
499
+
500
+ Returns:
501
+ ArrowResult containing pyarrow.Table or RecordBatch
502
+
503
+ Examples:
504
+ >>> result = driver.select_to_arrow(
505
+ ... "SELECT * FROM users WHERE age > :1", (18,)
506
+ ... )
507
+ >>> df = result.to_pandas()
508
+ >>> print(df.head())
509
+
510
+ """
511
+ ensure_pyarrow()
512
+
513
+ import pyarrow as pa
514
+
515
+ config = statement_config or self.statement_config
516
+ prepared_statement = self.prepare_statement(statement, parameters, statement_config=config, kwargs=kwargs)
517
+ sql, prepared_parameters = self._get_compiled_sql(prepared_statement, config)
518
+
519
+ try:
520
+ oracle_df = self._execute_arrow_dataframe(sql, prepared_parameters, batch_size)
521
+ except AttributeError as exc:
522
+ if native_only:
523
+ msg = "Oracle native Arrow support is not available for this connection."
524
+ raise ImproperConfigurationError(msg) from exc
525
+ return super().select_to_arrow(
526
+ statement,
527
+ *parameters,
528
+ statement_config=statement_config,
529
+ return_format=return_format,
530
+ native_only=native_only,
531
+ batch_size=batch_size,
532
+ arrow_schema=arrow_schema,
533
+ **kwargs,
534
+ )
535
+
536
+ arrow_table = pa.table(oracle_df)
537
+ column_names = normalize_column_names(arrow_table.column_names, self.driver_features)
538
+ if column_names != arrow_table.column_names:
539
+ arrow_table = arrow_table.rename_columns(column_names)
540
+
541
+ return build_arrow_result_from_table(
542
+ prepared_statement,
543
+ arrow_table,
544
+ return_format=return_format,
545
+ batch_size=batch_size,
546
+ arrow_schema=arrow_schema,
547
+ )
548
+
549
+ # ─────────────────────────────────────────────────────────────────────────────
550
+ # STACK EXECUTION METHODS
551
+ # ─────────────────────────────────────────────────────────────────────────────
552
+
553
+ def execute_stack(self, stack: "StatementStack", *, continue_on_error: bool = False) -> "tuple[StackResult, ...]":
554
+ """Execute a StatementStack using Oracle's pipeline when available."""
555
+ if not isinstance(stack, StatementStack) or not stack:
556
+ return super().execute_stack(stack, continue_on_error=continue_on_error)
557
+
558
+ blocker = self._stack_native_blocker(stack)
559
+ if blocker is not None:
560
+ self._log_pipeline_skip(blocker, stack)
561
+ return super().execute_stack(stack, continue_on_error=continue_on_error)
562
+
563
+ if not self._pipeline_native_supported():
564
+ self._log_pipeline_skip(self._pipeline_support_reason or "database_version", stack)
565
+ return super().execute_stack(stack, continue_on_error=continue_on_error)
566
+
567
+ return self._execute_stack_native(stack, continue_on_error=continue_on_error)
568
+
569
+ # ─────────────────────────────────────────────────────────────────────────────
570
+ # STORAGE API METHODS
571
+ # ─────────────────────────────────────────────────────────────────────────────
572
+
573
+ def select_to_storage(
574
+ self,
575
+ statement: "Statement | QueryBuilder | SQL | str",
576
+ destination: "StorageDestination",
577
+ /,
578
+ *parameters: "StatementParameters | StatementFilter",
579
+ statement_config: "StatementConfig | None" = None,
580
+ partitioner: "dict[str, object] | None" = None,
581
+ format_hint: "StorageFormat | None" = None,
582
+ telemetry: "StorageTelemetry | None" = None,
583
+ **kwargs: Any,
584
+ ) -> "StorageBridgeJob":
585
+ """Execute a query and stream Arrow-formatted output to storage (sync)."""
586
+ self._require_capability("arrow_export_enabled")
587
+ arrow_result = self.select_to_arrow(statement, *parameters, statement_config=statement_config, **kwargs)
588
+ sync_pipeline = self._storage_pipeline()
589
+ telemetry_payload = self._write_result_to_storage_sync(
590
+ arrow_result, destination, format_hint=format_hint, pipeline=sync_pipeline
591
+ )
592
+ self._attach_partition_telemetry(telemetry_payload, partitioner)
593
+ return self._create_storage_job(telemetry_payload, telemetry)
594
+
595
+ def load_from_arrow(
596
+ self,
597
+ table: str,
598
+ source: "ArrowResult | Any",
599
+ *,
600
+ partitioner: "dict[str, object] | None" = None,
601
+ overwrite: bool = False,
602
+ telemetry: "StorageTelemetry | None" = None,
603
+ ) -> "StorageBridgeJob":
604
+ """Load Arrow data into Oracle using batched executemany calls."""
605
+ self._require_capability("arrow_import_enabled")
606
+ arrow_table = self._coerce_arrow_table(source)
607
+ if overwrite:
608
+ statement = build_truncate_statement(table)
609
+ exc_handler = self.handle_database_exceptions()
610
+ with exc_handler:
611
+ self.connection.execute(statement)
612
+ if exc_handler.pending_exception is not None:
613
+ raise exc_handler.pending_exception from None
614
+ columns, records = self._arrow_table_to_rows(arrow_table)
615
+ if records:
616
+ statement = build_insert_statement(table, columns)
617
+ exc_handler = self.handle_database_exceptions()
618
+ with self.with_cursor(self.connection) as cursor, exc_handler:
619
+ cursor.executemany(statement, records)
620
+ if exc_handler.pending_exception is not None:
621
+ raise exc_handler.pending_exception from None
622
+ telemetry_payload = self._build_ingest_telemetry(arrow_table)
623
+ telemetry_payload["destination"] = table
624
+ self._attach_partition_telemetry(telemetry_payload, partitioner)
625
+ return self._create_storage_job(telemetry_payload, telemetry)
626
+
627
+ def load_from_storage(
628
+ self,
629
+ table: str,
630
+ source: "StorageDestination",
631
+ *,
632
+ file_format: "StorageFormat",
633
+ partitioner: "dict[str, object] | None" = None,
634
+ overwrite: bool = False,
635
+ ) -> "StorageBridgeJob":
636
+ """Load staged artifacts into Oracle."""
637
+ arrow_table, inbound = self._read_arrow_from_storage_sync(source, file_format=file_format)
638
+ return self.load_from_arrow(table, arrow_table, partitioner=partitioner, overwrite=overwrite, telemetry=inbound)
639
+
640
+ # ─────────────────────────────────────────────────────────────────────────────
641
+ # UTILITY METHODS
642
+ # ─────────────────────────────────────────────────────────────────────────────
643
+
644
+ @property
645
+ def data_dictionary(self) -> "OracledbSyncDataDictionary":
646
+ """Get the data dictionary for this driver.
647
+
648
+ Returns:
649
+ Data dictionary instance for metadata queries
650
+
651
+ """
652
+ if self._data_dictionary is None:
653
+ self._data_dictionary = OracledbSyncDataDictionary()
654
+ return self._data_dictionary
655
+
656
+ # ─────────────────────────────────────────────────────────────────────────────
657
+ # PRIVATE/INTERNAL METHODS
658
+ # ─────────────────────────────────────────────────────────────────────────────
659
+
660
+ def collect_rows(self, cursor: Any, fetched: "list[Any]") -> "tuple[list[Any], list[str], int]":
661
+ """Collect Oracle sync rows for the direct execution path."""
662
+ column_names, requires_lob_coercion = self._resolve_row_metadata(cursor.description)
663
+ data, column_names = collect_sync_rows(
664
+ cast("list[Any] | None", fetched),
665
+ cursor.description,
666
+ self.driver_features,
667
+ column_names=column_names,
668
+ requires_lob_coercion=requires_lob_coercion,
669
+ )
670
+ return data, column_names, len(data)
671
+
672
+ def resolve_rowcount(self, cursor: Any) -> int:
673
+ """Resolve rowcount from Oracle cursor for the direct execution path."""
674
+ return resolve_rowcount(cursor)
675
+
676
+ def _connection_in_transaction(self) -> bool:
677
+ """Check if connection is in transaction."""
678
+ return False
679
+
680
+ def _detect_oracle_version(self) -> "VersionInfo | None":
681
+ if self._oracle_version is not None:
682
+ return self._oracle_version
683
+ version = self.data_dictionary.get_version(self)
684
+ self._oracle_version = version
685
+ return version
686
+
687
+ def _detect_oracledb_version(self) -> "tuple[int, int, int]":
688
+ return ORACLEDB_VERSION
689
+
690
+ def _resolve_row_metadata(self, description: Any) -> "tuple[list[str], bool]":
691
+ return resolve_row_metadata(description, self.driver_features, self._row_metadata_cache)
692
+
693
+ def _execute_arrow_dataframe(self, sql: str, parameters: "Any", batch_size: int | None) -> "Any":
694
+ """Execute SQL and return an Oracle DataFrame."""
695
+ params = parameters if parameters is not None else []
696
+ try:
697
+ execute_df = self.connection.execute_df
698
+ except AttributeError:
699
+ execute_df = None
700
+ if execute_df is not None:
701
+ try:
702
+ return execute_df(sql, params, arraysize=batch_size or 1000)
703
+ except TypeError:
704
+ return execute_df(sql, params)
705
+ return self.connection.fetch_df_all(statement=sql, parameters=params, arraysize=batch_size or 1000)
706
+
707
+ def _execute_stack_native(self, stack: "StatementStack", *, continue_on_error: bool) -> "tuple[StackResult, ...]":
708
+ compiled_operations = [self._prepare_pipeline_operation(op) for op in stack.operations]
709
+ pipeline = oracledb.create_pipeline()
710
+ for compiled in compiled_operations:
711
+ self._add_pipeline_operation(pipeline, compiled)
712
+
713
+ results: list[StackResult] = []
714
+ started_transaction = False
715
+
716
+ with StackExecutionObserver(self, stack, continue_on_error, native_pipeline=True) as observer:
717
+ try:
718
+ if not continue_on_error and not self._connection_in_transaction():
719
+ self.begin()
720
+ started_transaction = True
721
+
722
+ pipeline_results = self.connection.run_pipeline(pipeline, continue_on_error=continue_on_error)
723
+ results = self._build_stack_results_from_pipeline(
724
+ compiled_operations, pipeline_results, continue_on_error, observer
725
+ )
726
+
727
+ if started_transaction:
728
+ self.commit()
729
+ except Exception as exc:
730
+ if started_transaction:
731
+ try:
732
+ self.rollback()
733
+ except Exception as rollback_error: # pragma: no cover - diagnostics only
734
+ logger.debug("Rollback after pipeline failure failed: %s", rollback_error)
735
+ raise self._wrap_pipeline_error(exc, stack, continue_on_error) from exc
736
+
737
+ return tuple(results)
738
+
739
+ def _pipeline_native_supported(self) -> bool:
740
+ if self._pipeline_support is not None:
741
+ return self._pipeline_support
742
+
743
+ if self.stack_native_disabled:
744
+ self._pipeline_support = False
745
+ self._pipeline_support_reason = "env_override"
746
+ return False
747
+
748
+ if self._detect_oracledb_version() < PIPELINE_MIN_DRIVER_VERSION:
749
+ self._pipeline_support = False
750
+ self._pipeline_support_reason = "driver_version"
751
+ return False
752
+
753
+ if not has_pipeline_capability(self.connection):
754
+ self._pipeline_support = False
755
+ self._pipeline_support_reason = "driver_api_missing"
756
+ return False
757
+
758
+ version_info = self._detect_oracle_version()
759
+ if version_info and version_info.major >= PIPELINE_MIN_DATABASE_MAJOR:
760
+ self._pipeline_support = True
761
+ self._pipeline_support_reason = None
762
+ return True
763
+
764
+ self._pipeline_support = False
765
+ self._pipeline_support_reason = "database_version"
766
+ return False
767
+
768
+
769
+ class OracleAsyncDriver(OraclePipelineMixin, AsyncDriverAdapterBase):
770
+ """Asynchronous Oracle Database driver.
771
+
772
+ Provides Oracle Database connectivity with parameter style conversion,
773
+ error handling, and transaction management for async operations.
774
+ """
775
+
776
+ __slots__ = (
777
+ "_data_dictionary",
778
+ "_oracle_version",
779
+ "_pipeline_support",
780
+ "_pipeline_support_reason",
781
+ "_row_metadata_cache",
782
+ )
783
+ dialect = "oracle"
784
+
785
+ def __init__(
786
+ self,
787
+ connection: OracleAsyncConnection,
788
+ statement_config: "StatementConfig | None" = None,
789
+ driver_features: "dict[str, Any] | None" = None,
790
+ ) -> None:
791
+ if statement_config is None:
792
+ statement_config = default_statement_config.replace(
793
+ enable_caching=get_cache_config().compiled_cache_enabled
794
+ )
795
+
796
+ super().__init__(connection=connection, statement_config=statement_config, driver_features=driver_features)
797
+ self._data_dictionary: OracledbAsyncDataDictionary | None = None
798
+ self._pipeline_support: bool | None = None
799
+ self._pipeline_support_reason: str | None = None
800
+ self._oracle_version: VersionInfo | None = None
801
+ self._row_metadata_cache: dict[int, tuple[Any, list[str], bool]] = {}
802
+
803
+ # ─────────────────────────────────────────────────────────────────────────────
804
+ # CORE DISPATCH METHODS
805
+ # ─────────────────────────────────────────────────────────────────────────────
806
+
807
+ async def dispatch_execute(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
808
+ """Execute single SQL statement with Oracle data handling.
809
+
810
+ Args:
811
+ cursor: Oracle cursor object
812
+ statement: SQL statement to execute
813
+
814
+ Returns:
815
+ Execution result containing data for SELECT statements or row count for others
816
+
817
+ """
818
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
819
+
820
+ prepared_parameters = await coerce_large_parameters_async(
821
+ self.connection,
822
+ prepared_parameters,
823
+ clob_type=oracledb.DB_TYPE_CLOB,
824
+ blob_type=oracledb.DB_TYPE_BLOB,
825
+ varchar2_byte_limit=self.driver_features.get("oracle_varchar2_byte_limit", 4000),
826
+ raw_byte_limit=self.driver_features.get("oracle_raw_byte_limit", 2000),
827
+ )
828
+ prepared_parameters = cast("list[Any] | tuple[Any, ...] | dict[Any, Any] | None", prepared_parameters)
829
+
830
+ await cursor.execute(sql, prepared_parameters or {})
831
+
832
+ # SELECT result processing for Oracle
833
+ is_select_like = statement.returns_rows() or self._should_force_select(statement, cursor)
834
+
835
+ if is_select_like:
836
+ fetched_data = await cursor.fetchall()
837
+ column_names, requires_lob_coercion = self._resolve_row_metadata(cursor.description)
838
+ data, column_names = await collect_async_rows(
839
+ cast("list[Any] | None", fetched_data),
840
+ cursor.description,
841
+ self.driver_features,
842
+ column_names=column_names,
843
+ requires_lob_coercion=requires_lob_coercion,
844
+ )
845
+
846
+ return self.create_execution_result(
847
+ cursor,
848
+ selected_data=data,
849
+ column_names=column_names,
850
+ data_row_count=len(data),
851
+ is_select_result=True,
852
+ row_format="tuple",
853
+ )
854
+
855
+ # Non-SELECT result processing
856
+ affected_rows = resolve_rowcount(cursor)
857
+ return self.create_execution_result(cursor, rowcount_override=affected_rows)
858
+
859
+ async def dispatch_execute_many(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
860
+ """Execute SQL with multiple parameter sets using Oracle batch processing.
861
+
862
+ Args:
863
+ cursor: Oracle cursor object
864
+ statement: SQL statement with multiple parameter sets
865
+
866
+ Returns:
867
+ Execution result with affected row count
868
+
869
+ Raises:
870
+ ValueError: If no parameters are provided
871
+
872
+ """
873
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
874
+
875
+ prepared_parameters = normalize_execute_many_parameters_async(prepared_parameters)
876
+ await cursor.executemany(sql, prepared_parameters)
877
+
878
+ affected_rows = len(prepared_parameters)
879
+
880
+ return self.create_execution_result(cursor, rowcount_override=affected_rows, is_many_result=True)
881
+
882
+ async def dispatch_execute_script(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
883
+ """Execute SQL script with statement splitting and parameter handling.
884
+
885
+ Parameters are embedded as static values for script execution compatibility.
886
+
887
+ Args:
888
+ cursor: Oracle cursor object
889
+ statement: SQL script statement to execute
890
+
891
+ Returns:
892
+ Execution result containing statement count and success information
893
+
894
+ """
895
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
896
+ statements = self.split_script_statements(sql, statement.statement_config, strip_trailing_semicolon=True)
897
+ script_params = cast("dict[str, Any]", prepared_parameters or {})
898
+
899
+ successful_count = 0
900
+ last_cursor = cursor
901
+
902
+ for stmt in statements:
903
+ await cursor.execute(stmt, script_params)
904
+ successful_count += 1
905
+
906
+ return self.create_execution_result(
907
+ last_cursor, statement_count=len(statements), successful_statements=successful_count, is_script_result=True
908
+ )
909
+
910
+ # ─────────────────────────────────────────────────────────────────────────────
911
+ # TRANSACTION MANAGEMENT
912
+ # ─────────────────────────────────────────────────────────────────────────────
913
+
914
+ async def begin(self) -> None:
915
+ """Begin a database transaction.
916
+
917
+ Oracle handles transactions automatically, so this is a no-op.
918
+ """
919
+ # Oracle handles transactions implicitly
920
+
921
+ async def commit(self) -> None:
922
+ """Commit the current transaction.
923
+
924
+ Raises:
925
+ SQLSpecError: If commit fails
926
+
927
+ """
928
+ try:
929
+ await self.connection.commit()
930
+ except oracledb.Error as e:
931
+ msg = f"Failed to commit Oracle transaction: {e}"
932
+ raise SQLSpecError(msg) from e
933
+
934
+ async def rollback(self) -> None:
935
+ """Rollback the current transaction.
936
+
937
+ Raises:
938
+ SQLSpecError: If rollback fails
939
+
940
+ """
941
+ try:
942
+ await self.connection.rollback()
943
+ except oracledb.Error as e:
944
+ msg = f"Failed to rollback Oracle transaction: {e}"
945
+ raise SQLSpecError(msg) from e
946
+
947
+ def with_cursor(self, connection: OracleAsyncConnection) -> OracleAsyncCursor:
948
+ """Create context manager for Oracle cursor.
949
+
950
+ Args:
951
+ connection: Oracle database connection
952
+
953
+ Returns:
954
+ Context manager for cursor operations
955
+
956
+ """
957
+ return OracleAsyncCursor(connection)
958
+
959
+ def handle_database_exceptions(self) -> "OracleAsyncExceptionHandler":
960
+ """Handle database-specific exceptions and wrap them appropriately."""
961
+ return OracleAsyncExceptionHandler()
962
+
963
+ # ─────────────────────────────────────────────────────────────────────────────
964
+ # ARROW API METHODS
965
+ # ─────────────────────────────────────────────────────────────────────────────
966
+
967
+ async def select_to_arrow(
968
+ self,
969
+ statement: "Statement | QueryBuilder",
970
+ /,
971
+ *parameters: "StatementParameters | StatementFilter",
972
+ statement_config: "StatementConfig | None" = None,
973
+ return_format: "ArrowReturnFormat" = "table",
974
+ native_only: bool = False,
975
+ batch_size: int | None = None,
976
+ arrow_schema: Any = None,
977
+ **kwargs: Any,
978
+ ) -> "Any":
979
+ """Execute query and return results as Apache Arrow format using Oracle native support.
980
+
981
+ This implementation uses Oracle's native execute_df()/fetch_df_all() methods
982
+ which return OracleDataFrame objects with Arrow PyCapsule interface, providing
983
+ zero-copy data transfer and 5-10x performance improvement over dict conversion.
984
+ If native Arrow is unavailable and native_only is False, it falls back to the
985
+ conversion path.
986
+
987
+ Args:
988
+ statement: SQL query string, Statement, or QueryBuilder
989
+ *parameters: Query parameters (same format as execute()/select())
990
+ statement_config: Optional statement configuration override
991
+ return_format: "table" for pyarrow.Table (default), "batch" for RecordBatch,
992
+ "batches" for list of RecordBatch, "reader" for RecordBatchReader
993
+ native_only: If True, raise error if native Arrow is unavailable
994
+ batch_size: Rows per batch when using "batch" or "batches" format
995
+ arrow_schema: Optional pyarrow.Schema for type casting
996
+ **kwargs: Additional keyword arguments
997
+
998
+ Returns:
999
+ ArrowResult containing pyarrow.Table or RecordBatch
1000
+
1001
+ Examples:
1002
+ >>> result = await driver.select_to_arrow(
1003
+ ... "SELECT * FROM users WHERE age > :1", (18,)
1004
+ ... )
1005
+ >>> df = result.to_pandas()
1006
+ >>> print(df.head())
1007
+
1008
+ """
1009
+ ensure_pyarrow()
1010
+
1011
+ import pyarrow as pa
1012
+
1013
+ config = statement_config or self.statement_config
1014
+ prepared_statement = self.prepare_statement(statement, parameters, statement_config=config, kwargs=kwargs)
1015
+ sql, prepared_parameters = self._get_compiled_sql(prepared_statement, config)
1016
+
1017
+ try:
1018
+ oracle_df = await self._execute_arrow_dataframe(sql, prepared_parameters, batch_size)
1019
+ except AttributeError as exc:
1020
+ if native_only:
1021
+ msg = "Oracle native Arrow support is not available for this connection."
1022
+ raise ImproperConfigurationError(msg) from exc
1023
+ return await super().select_to_arrow(
1024
+ statement,
1025
+ *parameters,
1026
+ statement_config=statement_config,
1027
+ return_format=return_format,
1028
+ native_only=native_only,
1029
+ batch_size=batch_size,
1030
+ arrow_schema=arrow_schema,
1031
+ **kwargs,
1032
+ )
1033
+
1034
+ arrow_table = pa.table(oracle_df)
1035
+ column_names = normalize_column_names(arrow_table.column_names, self.driver_features)
1036
+ if column_names != arrow_table.column_names:
1037
+ arrow_table = arrow_table.rename_columns(column_names)
1038
+
1039
+ return build_arrow_result_from_table(
1040
+ prepared_statement,
1041
+ arrow_table,
1042
+ return_format=return_format,
1043
+ batch_size=batch_size,
1044
+ arrow_schema=arrow_schema,
1045
+ )
1046
+
1047
+ # ─────────────────────────────────────────────────────────────────────────────
1048
+ # STACK EXECUTION METHODS
1049
+ # ─────────────────────────────────────────────────────────────────────────────
1050
+
1051
+ async def execute_stack(
1052
+ self, stack: "StatementStack", *, continue_on_error: bool = False
1053
+ ) -> "tuple[StackResult, ...]":
1054
+ """Execute a StatementStack using Oracle's pipeline when available."""
1055
+ if not isinstance(stack, StatementStack) or not stack:
1056
+ return await super().execute_stack(stack, continue_on_error=continue_on_error)
1057
+
1058
+ blocker = self._stack_native_blocker(stack)
1059
+ if blocker is not None:
1060
+ self._log_pipeline_skip(blocker, stack)
1061
+ return await super().execute_stack(stack, continue_on_error=continue_on_error)
1062
+
1063
+ if not await self._pipeline_native_supported():
1064
+ self._log_pipeline_skip(self._pipeline_support_reason or "database_version", stack)
1065
+ return await super().execute_stack(stack, continue_on_error=continue_on_error)
1066
+
1067
+ return await self._execute_stack_native(stack, continue_on_error=continue_on_error)
1068
+
1069
+ # ─────────────────────────────────────────────────────────────────────────────
1070
+ # STORAGE API METHODS
1071
+ # ─────────────────────────────────────────────────────────────────────────────
1072
+
1073
+ async def select_to_storage(
1074
+ self,
1075
+ statement: "Statement | QueryBuilder | SQL | str",
1076
+ destination: "StorageDestination",
1077
+ /,
1078
+ *parameters: "StatementParameters | StatementFilter",
1079
+ statement_config: "StatementConfig | None" = None,
1080
+ partitioner: "dict[str, object] | None" = None,
1081
+ format_hint: "StorageFormat | None" = None,
1082
+ telemetry: "StorageTelemetry | None" = None,
1083
+ **kwargs: Any,
1084
+ ) -> "StorageBridgeJob":
1085
+ """Execute a query and write Arrow-compatible output to storage (async)."""
1086
+ self._require_capability("arrow_export_enabled")
1087
+ arrow_result = await self.select_to_arrow(statement, *parameters, statement_config=statement_config, **kwargs)
1088
+ async_pipeline = self._storage_pipeline()
1089
+ telemetry_payload = await self._write_result_to_storage_async(
1090
+ arrow_result, destination, format_hint=format_hint, pipeline=async_pipeline
1091
+ )
1092
+ self._attach_partition_telemetry(telemetry_payload, partitioner)
1093
+ return self._create_storage_job(telemetry_payload, telemetry)
1094
+
1095
+ async def load_from_arrow(
1096
+ self,
1097
+ table: str,
1098
+ source: "ArrowResult | Any",
1099
+ *,
1100
+ partitioner: "dict[str, object] | None" = None,
1101
+ overwrite: bool = False,
1102
+ telemetry: "StorageTelemetry | None" = None,
1103
+ ) -> "StorageBridgeJob":
1104
+ """Asynchronously load Arrow data into Oracle."""
1105
+ self._require_capability("arrow_import_enabled")
1106
+ arrow_table = self._coerce_arrow_table(source)
1107
+ if overwrite:
1108
+ statement = build_truncate_statement(table)
1109
+ exc_handler = self.handle_database_exceptions()
1110
+ async with exc_handler:
1111
+ await self.connection.execute(statement)
1112
+ if exc_handler.pending_exception is not None:
1113
+ raise exc_handler.pending_exception from None
1114
+ columns, records = self._arrow_table_to_rows(arrow_table)
1115
+ if records:
1116
+ statement = build_insert_statement(table, columns)
1117
+ exc_handler = self.handle_database_exceptions()
1118
+ async with self.with_cursor(self.connection) as cursor, exc_handler:
1119
+ await cursor.executemany(statement, records)
1120
+ if exc_handler.pending_exception is not None:
1121
+ raise exc_handler.pending_exception from None
1122
+ telemetry_payload = self._build_ingest_telemetry(arrow_table)
1123
+ telemetry_payload["destination"] = table
1124
+ self._attach_partition_telemetry(telemetry_payload, partitioner)
1125
+ return self._create_storage_job(telemetry_payload, telemetry)
1126
+
1127
+ async def load_from_storage(
1128
+ self,
1129
+ table: str,
1130
+ source: "StorageDestination",
1131
+ *,
1132
+ file_format: "StorageFormat",
1133
+ partitioner: "dict[str, object] | None" = None,
1134
+ overwrite: bool = False,
1135
+ ) -> "StorageBridgeJob":
1136
+ """Asynchronously load staged artifacts into Oracle."""
1137
+ arrow_table, inbound = await self._read_arrow_from_storage_async(source, file_format=file_format)
1138
+ return await self.load_from_arrow(
1139
+ table, arrow_table, partitioner=partitioner, overwrite=overwrite, telemetry=inbound
1140
+ )
1141
+
1142
+ # ─────────────────────────────────────────────────────────────────────────────
1143
+ # UTILITY METHODS
1144
+ # ─────────────────────────────────────────────────────────────────────────────
1145
+
1146
+ @property
1147
+ def data_dictionary(self) -> "OracledbAsyncDataDictionary":
1148
+ """Get the data dictionary for this driver.
1149
+
1150
+ Returns:
1151
+ Data dictionary instance for metadata queries
1152
+
1153
+ """
1154
+ if self._data_dictionary is None:
1155
+ self._data_dictionary = OracledbAsyncDataDictionary()
1156
+ return self._data_dictionary
1157
+
1158
+ # ─────────────────────────────────────────────────────────────────────────────
1159
+ # PRIVATE/INTERNAL METHODS
1160
+ # ─────────────────────────────────────────────────────────────────────────────
1161
+
1162
+ def collect_rows(self, cursor: Any, fetched: "list[Any]") -> "tuple[list[Any], list[str], int]":
1163
+ """Collect Oracle async rows for the direct execution path.
1164
+
1165
+ Uses synchronous LOB coercion. For async LOB coercion, the standard
1166
+ dispatch path via collect_async_rows is used instead.
1167
+ """
1168
+ column_names, requires_lob_coercion = self._resolve_row_metadata(cursor.description)
1169
+ data, column_names = collect_sync_rows(
1170
+ cast("list[Any] | None", fetched),
1171
+ cursor.description,
1172
+ self.driver_features,
1173
+ column_names=column_names,
1174
+ requires_lob_coercion=requires_lob_coercion,
1175
+ )
1176
+ return data, column_names, len(data)
1177
+
1178
+ def resolve_rowcount(self, cursor: Any) -> int:
1179
+ """Resolve rowcount from Oracle cursor for the direct execution path."""
1180
+ return resolve_rowcount(cursor)
1181
+
1182
+ def _connection_in_transaction(self) -> bool:
1183
+ """Check if connection is in transaction."""
1184
+ return False
1185
+
1186
+ async def _detect_oracle_version(self) -> "VersionInfo | None":
1187
+ if self._oracle_version is not None:
1188
+ return self._oracle_version
1189
+ version = await self.data_dictionary.get_version(self)
1190
+ self._oracle_version = version
1191
+ return version
1192
+
1193
+ def _detect_oracledb_version(self) -> "tuple[int, int, int]":
1194
+ return ORACLEDB_VERSION
1195
+
1196
+ def _resolve_row_metadata(self, description: Any) -> "tuple[list[str], bool]":
1197
+ return resolve_row_metadata(description, self.driver_features, self._row_metadata_cache)
1198
+
1199
+ async def _execute_arrow_dataframe(self, sql: str, parameters: "Any", batch_size: int | None) -> "Any":
1200
+ """Execute SQL and return an Oracle DataFrame."""
1201
+ params = parameters if parameters is not None else []
1202
+ try:
1203
+ execute_df = self.connection.execute_df
1204
+ except AttributeError:
1205
+ execute_df = None
1206
+ if execute_df is not None:
1207
+ try:
1208
+ return await execute_df(sql, params, arraysize=batch_size or 1000)
1209
+ except TypeError:
1210
+ return await execute_df(sql, params)
1211
+ return await self.connection.fetch_df_all(statement=sql, parameters=params, arraysize=batch_size or 1000)
1212
+
1213
+ async def _execute_stack_native(
1214
+ self, stack: "StatementStack", *, continue_on_error: bool
1215
+ ) -> "tuple[StackResult, ...]":
1216
+ compiled_operations = [self._prepare_pipeline_operation(op) for op in stack.operations]
1217
+ pipeline = oracledb.create_pipeline()
1218
+ for compiled in compiled_operations:
1219
+ self._add_pipeline_operation(pipeline, compiled)
1220
+
1221
+ results: list[StackResult] = []
1222
+ started_transaction = False
1223
+
1224
+ with StackExecutionObserver(self, stack, continue_on_error, native_pipeline=True) as observer:
1225
+ try:
1226
+ if not continue_on_error and not self._connection_in_transaction():
1227
+ await self.begin()
1228
+ started_transaction = True
1229
+
1230
+ pipeline_results = await self.connection.run_pipeline(pipeline, continue_on_error=continue_on_error)
1231
+ results = self._build_stack_results_from_pipeline(
1232
+ compiled_operations, pipeline_results, continue_on_error, observer
1233
+ )
1234
+
1235
+ if started_transaction:
1236
+ await self.commit()
1237
+ except Exception as exc:
1238
+ if started_transaction:
1239
+ try:
1240
+ await self.rollback()
1241
+ except Exception as rollback_error: # pragma: no cover - diagnostics only
1242
+ logger.debug("Rollback after pipeline failure failed: %s", rollback_error)
1243
+ raise self._wrap_pipeline_error(exc, stack, continue_on_error) from exc
1244
+
1245
+ return tuple(results)
1246
+
1247
+ async def _pipeline_native_supported(self) -> bool:
1248
+ if self._pipeline_support is not None:
1249
+ return self._pipeline_support
1250
+
1251
+ if self.stack_native_disabled:
1252
+ self._pipeline_support = False
1253
+ self._pipeline_support_reason = "env_override"
1254
+ return False
1255
+
1256
+ if self._detect_oracledb_version() < PIPELINE_MIN_DRIVER_VERSION:
1257
+ self._pipeline_support = False
1258
+ self._pipeline_support_reason = "driver_version"
1259
+ return False
1260
+
1261
+ if not has_pipeline_capability(self.connection):
1262
+ self._pipeline_support = False
1263
+ self._pipeline_support_reason = "driver_api_missing"
1264
+ return False
1265
+
1266
+ version_info = await self._detect_oracle_version()
1267
+ if version_info and version_info.major >= PIPELINE_MIN_DATABASE_MAJOR:
1268
+ self._pipeline_support = True
1269
+ self._pipeline_support_reason = None
1270
+ return True
1271
+
1272
+ self._pipeline_support = False
1273
+ self._pipeline_support_reason = "database_version"
1274
+ return False
1275
+
1276
+
1277
+ register_driver_profile("oracledb", driver_profile)