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,1033 @@
1
+ """PostgreSQL psycopg driver implementation."""
2
+
3
+ from collections.abc import Sized
4
+ from contextlib import AsyncExitStack, ExitStack
5
+ from typing import TYPE_CHECKING, Any, cast
6
+
7
+ import psycopg
8
+ from typing_extensions import LiteralString
9
+
10
+ from sqlspec.adapters.psycopg._typing import (
11
+ PsycopgAsyncConnection,
12
+ PsycopgAsyncCursor,
13
+ PsycopgAsyncSessionContext,
14
+ PsycopgComposed,
15
+ PsycopgSQL,
16
+ PsycopgSyncConnection,
17
+ PsycopgSyncCursor,
18
+ PsycopgSyncSessionContext,
19
+ )
20
+ from sqlspec.adapters.psycopg.core import (
21
+ TRANSACTION_STATUS_IDLE,
22
+ PipelineCursorEntry,
23
+ PreparedStackOperation,
24
+ build_async_pipeline_execution_result,
25
+ build_copy_from_command,
26
+ build_pipeline_execution_result,
27
+ build_truncate_command,
28
+ create_mapped_exception,
29
+ default_statement_config,
30
+ driver_profile,
31
+ execute_with_optional_parameters,
32
+ execute_with_optional_parameters_async,
33
+ pipeline_supported,
34
+ resolve_many_rowcount,
35
+ resolve_rowcount,
36
+ )
37
+ from sqlspec.adapters.psycopg.data_dictionary import PsycopgAsyncDataDictionary, PsycopgSyncDataDictionary
38
+ from sqlspec.core import (
39
+ SQL,
40
+ SQLResult,
41
+ StackResult,
42
+ StatementConfig,
43
+ StatementStack,
44
+ get_cache_config,
45
+ is_copy_from_operation,
46
+ is_copy_operation,
47
+ is_copy_to_operation,
48
+ register_driver_profile,
49
+ )
50
+ from sqlspec.driver import (
51
+ AsyncDriverAdapterBase,
52
+ BaseAsyncExceptionHandler,
53
+ BaseSyncExceptionHandler,
54
+ StackExecutionObserver,
55
+ SyncDriverAdapterBase,
56
+ describe_stack_statement,
57
+ )
58
+ from sqlspec.exceptions import SQLSpecError, StackExecutionError
59
+ from sqlspec.utils.logging import get_logger
60
+ from sqlspec.utils.type_guards import is_readable
61
+
62
+ if TYPE_CHECKING:
63
+ from sqlspec.adapters.psycopg._typing import PsycopgPipelineDriver
64
+ from sqlspec.core import ArrowResult
65
+ from sqlspec.driver import ExecutionResult
66
+ from sqlspec.storage import StorageBridgeJob, StorageDestination, StorageFormat, StorageTelemetry
67
+
68
+
69
+ __all__ = (
70
+ "PsycopgAsyncCursor",
71
+ "PsycopgAsyncDriver",
72
+ "PsycopgAsyncExceptionHandler",
73
+ "PsycopgAsyncSessionContext",
74
+ "PsycopgSyncCursor",
75
+ "PsycopgSyncDriver",
76
+ "PsycopgSyncExceptionHandler",
77
+ "PsycopgSyncSessionContext",
78
+ )
79
+
80
+ logger = get_logger("sqlspec.adapters.psycopg")
81
+ COLUMN_CACHE_MAX_SIZE = 256
82
+
83
+
84
+ class PsycopgPipelineMixin:
85
+ """Shared helpers for psycopg sync/async pipeline execution."""
86
+
87
+ __slots__ = ()
88
+
89
+ def _prepare_pipeline_operations(self, stack: "StatementStack") -> "list[PreparedStackOperation] | None":
90
+ prepared: list[PreparedStackOperation] = []
91
+ for index, operation in enumerate(stack.operations):
92
+ if operation.method != "execute":
93
+ return None
94
+
95
+ kwargs = dict(operation.keyword_arguments) if operation.keyword_arguments else {}
96
+ statement_config = kwargs.pop("statement_config", None)
97
+ driver = cast("PsycopgPipelineDriver", self)
98
+ config = statement_config or driver.statement_config
99
+
100
+ sql_statement = driver.prepare_statement(
101
+ operation.statement, operation.arguments, statement_config=config, kwargs=kwargs
102
+ )
103
+
104
+ if sql_statement.is_script or sql_statement.is_many:
105
+ return None
106
+
107
+ sql_text, prepared_parameters = driver._get_compiled_sql( # pyright: ignore[reportPrivateUsage]
108
+ sql_statement, config
109
+ )
110
+ prepared.append(
111
+ PreparedStackOperation(
112
+ operation_index=index,
113
+ operation=operation,
114
+ statement=sql_statement,
115
+ sql=cast("LiteralString | PsycopgSQL | PsycopgComposed", sql_text),
116
+ parameters=prepared_parameters,
117
+ )
118
+ )
119
+ return prepared
120
+
121
+
122
+ class PsycopgSyncExceptionHandler(BaseSyncExceptionHandler):
123
+ """Context manager for handling PostgreSQL psycopg database exceptions.
124
+
125
+ Maps PostgreSQL SQLSTATE error codes to specific SQLSpec exceptions
126
+ for better error handling in application code.
127
+
128
+ Uses deferred exception pattern for mypyc compatibility: exceptions
129
+ are stored in pending_exception rather than raised from __exit__
130
+ to avoid ABI boundary violations with compiled code.
131
+ """
132
+
133
+ __slots__ = ()
134
+
135
+ def _handle_exception(self, exc_type: "type[BaseException] | None", exc_val: "BaseException") -> bool:
136
+ if exc_type is None:
137
+ return False
138
+ if issubclass(exc_type, psycopg.Error):
139
+ self.pending_exception = create_mapped_exception(exc_val)
140
+ return True
141
+ return False
142
+
143
+
144
+ class PsycopgSyncDriver(PsycopgPipelineMixin, SyncDriverAdapterBase):
145
+ """PostgreSQL psycopg synchronous driver.
146
+
147
+ Provides synchronous database operations for PostgreSQL using psycopg3.
148
+ Supports SQL statement execution with parameter binding, transaction
149
+ management, result processing with column metadata, parameter style
150
+ conversion, PostgreSQL arrays and JSON handling, COPY operations for
151
+ bulk data transfer, and PostgreSQL-specific error handling.
152
+ """
153
+
154
+ __slots__ = ("_column_name_cache", "_data_dictionary")
155
+ dialect = "postgres"
156
+
157
+ def __init__(
158
+ self,
159
+ connection: PsycopgSyncConnection,
160
+ statement_config: "StatementConfig | None" = None,
161
+ driver_features: "dict[str, Any] | None" = None,
162
+ ) -> None:
163
+ if statement_config is None:
164
+ statement_config = default_statement_config.replace(
165
+ enable_caching=get_cache_config().compiled_cache_enabled
166
+ )
167
+
168
+ super().__init__(connection=connection, statement_config=statement_config, driver_features=driver_features)
169
+ self._data_dictionary: PsycopgSyncDataDictionary | None = None
170
+ self._column_name_cache: dict[int, tuple[Any, list[str]]] = {}
171
+
172
+ # ─────────────────────────────────────────────────────────────────────────────
173
+ # CORE DISPATCH METHODS
174
+ # ─────────────────────────────────────────────────────────────────────────────
175
+
176
+ def dispatch_execute(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
177
+ """Execute single SQL statement.
178
+
179
+ Args:
180
+ cursor: Database cursor
181
+ statement: SQL statement to execute
182
+
183
+ Returns:
184
+ ExecutionResult with statement execution details
185
+ """
186
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
187
+
188
+ execute_with_optional_parameters(cursor, sql, prepared_parameters)
189
+
190
+ if statement.returns_rows():
191
+ fetched_data = cursor.fetchall()
192
+ data = cast("list[Any] | None", fetched_data) or []
193
+ column_names = self._resolve_column_names(cursor.description)
194
+
195
+ return self.create_execution_result(
196
+ cursor,
197
+ selected_data=data,
198
+ column_names=column_names,
199
+ data_row_count=len(data),
200
+ is_select_result=True,
201
+ row_format="tuple",
202
+ )
203
+
204
+ affected_rows = resolve_rowcount(cursor)
205
+ return self.create_execution_result(cursor, rowcount_override=affected_rows)
206
+
207
+ def dispatch_execute_many(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
208
+ """Execute SQL with multiple parameter sets.
209
+
210
+ Args:
211
+ cursor: Database cursor
212
+ statement: SQL statement with parameter list
213
+
214
+ Returns:
215
+ ExecutionResult with batch execution details
216
+ """
217
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
218
+
219
+ if not prepared_parameters:
220
+ return self.create_execution_result(cursor, rowcount_override=0, is_many_result=True)
221
+
222
+ parameter_count = len(prepared_parameters) if isinstance(prepared_parameters, Sized) else None
223
+ cursor.executemany(sql, prepared_parameters)
224
+ affected_rows = resolve_many_rowcount(cursor, prepared_parameters, fallback_count=parameter_count)
225
+
226
+ return self.create_execution_result(cursor, rowcount_override=affected_rows, is_many_result=True)
227
+
228
+ def dispatch_execute_script(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
229
+ """Execute SQL script with multiple statements.
230
+
231
+ Args:
232
+ cursor: Database cursor
233
+ statement: SQL statement containing multiple commands
234
+
235
+ Returns:
236
+ ExecutionResult with script execution details
237
+ """
238
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
239
+ statements = self.split_script_statements(sql, statement.statement_config, strip_trailing_semicolon=True)
240
+
241
+ successful_count = 0
242
+ last_cursor = cursor
243
+
244
+ for stmt in statements:
245
+ execute_with_optional_parameters(cursor, stmt, prepared_parameters)
246
+ successful_count += 1
247
+
248
+ return self.create_execution_result(
249
+ last_cursor, statement_count=len(statements), successful_statements=successful_count, is_script_result=True
250
+ )
251
+
252
+ def dispatch_special_handling(self, cursor: Any, statement: "SQL") -> "SQLResult | None":
253
+ """Hook for PostgreSQL-specific special operations.
254
+
255
+ Args:
256
+ cursor: Psycopg cursor object
257
+ statement: SQL statement to analyze
258
+
259
+ Returns:
260
+ SQLResult if special handling was applied, None otherwise
261
+ """
262
+
263
+ if not is_copy_operation(statement.operation_type):
264
+ return None
265
+
266
+ sql, _ = self._get_compiled_sql(statement, statement.statement_config)
267
+ operation_type = statement.operation_type
268
+ copy_data = statement.parameters
269
+ if isinstance(copy_data, list) and len(copy_data) == 1:
270
+ copy_data = copy_data[0]
271
+
272
+ if is_copy_from_operation(operation_type):
273
+ if isinstance(copy_data, (str, bytes)):
274
+ data_to_write = copy_data
275
+ elif is_readable(copy_data):
276
+ data_to_write = copy_data.read()
277
+ else:
278
+ data_to_write = str(copy_data)
279
+
280
+ if isinstance(data_to_write, str):
281
+ data_to_write = data_to_write.encode()
282
+
283
+ with cursor.copy(sql) as copy_ctx:
284
+ copy_ctx.write(data_to_write)
285
+
286
+ rows_affected = max(cursor.rowcount, 0)
287
+
288
+ return SQLResult(
289
+ data=None, rows_affected=rows_affected, statement=statement, metadata={"copy_operation": "FROM_STDIN"}
290
+ )
291
+
292
+ if is_copy_to_operation(operation_type):
293
+ output_data: list[str] = []
294
+ with cursor.copy(sql) as copy_ctx:
295
+ output_data.extend(row.decode() if isinstance(row, bytes) else str(row) for row in copy_ctx)
296
+
297
+ exported_data = "".join(output_data)
298
+
299
+ return SQLResult(
300
+ data=[{"copy_output": exported_data}],
301
+ rows_affected=0,
302
+ statement=statement,
303
+ metadata={"copy_operation": "TO_STDOUT"},
304
+ )
305
+
306
+ cursor.execute(sql)
307
+ rows_affected = max(cursor.rowcount, 0)
308
+
309
+ return SQLResult(
310
+ data=None, rows_affected=rows_affected, statement=statement, metadata={"copy_operation": "FILE"}
311
+ )
312
+
313
+ # ─────────────────────────────────────────────────────────────────────────────
314
+ # TRANSACTION MANAGEMENT
315
+ # ─────────────────────────────────────────────────────────────────────────────
316
+
317
+ def begin(self) -> None:
318
+ """Begin a database transaction on the current connection."""
319
+ try:
320
+ if self.connection.autocommit:
321
+ self.connection.autocommit = False
322
+ except Exception as e:
323
+ msg = f"Failed to begin transaction: {e}"
324
+ raise SQLSpecError(msg) from e
325
+
326
+ def commit(self) -> None:
327
+ """Commit the current transaction on the current connection."""
328
+ try:
329
+ self.connection.commit()
330
+ except Exception as e:
331
+ msg = f"Failed to commit transaction: {e}"
332
+ raise SQLSpecError(msg) from e
333
+
334
+ def rollback(self) -> None:
335
+ """Rollback the current transaction on the current connection."""
336
+ try:
337
+ self.connection.rollback()
338
+ except Exception as e:
339
+ msg = f"Failed to rollback transaction: {e}"
340
+ raise SQLSpecError(msg) from e
341
+
342
+ def with_cursor(self, connection: PsycopgSyncConnection) -> PsycopgSyncCursor:
343
+ """Create context manager for PostgreSQL cursor."""
344
+ return PsycopgSyncCursor(connection)
345
+
346
+ def handle_database_exceptions(self) -> "PsycopgSyncExceptionHandler":
347
+ """Handle database-specific exceptions and wrap them appropriately."""
348
+ return PsycopgSyncExceptionHandler()
349
+
350
+ # ─────────────────────────────────────────────────────────────────────────────
351
+ # STACK EXECUTION METHODS
352
+ # ─────────────────────────────────────────────────────────────────────────────
353
+
354
+ def execute_stack(self, stack: "StatementStack", *, continue_on_error: bool = False) -> "tuple[StackResult, ...]":
355
+ """Execute a StatementStack using psycopg pipeline mode when supported."""
356
+
357
+ if (
358
+ not isinstance(stack, StatementStack)
359
+ or not stack
360
+ or self.stack_native_disabled
361
+ or not pipeline_supported()
362
+ or continue_on_error
363
+ ):
364
+ return super().execute_stack(stack, continue_on_error=continue_on_error)
365
+
366
+ prepared_ops = self._prepare_pipeline_operations(stack)
367
+ if prepared_ops is None:
368
+ return super().execute_stack(stack, continue_on_error=continue_on_error)
369
+
370
+ return self._execute_stack_pipeline(stack, prepared_ops)
371
+
372
+ def _execute_stack_pipeline(
373
+ self, stack: "StatementStack", prepared_ops: "list[PreparedStackOperation]"
374
+ ) -> "tuple[StackResult, ...]":
375
+ def _raise_pending_exception(exception_ctx: "PsycopgSyncExceptionHandler") -> None:
376
+ if exception_ctx.pending_exception is not None:
377
+ raise exception_ctx.pending_exception from None
378
+
379
+ results: list[StackResult] = []
380
+ started_transaction = False
381
+
382
+ with StackExecutionObserver(self, stack, continue_on_error=False, native_pipeline=True):
383
+ try:
384
+ if not self._connection_in_transaction():
385
+ self.begin()
386
+ started_transaction = True
387
+
388
+ exception_handlers = []
389
+ with ExitStack() as resource_stack:
390
+ pipeline = resource_stack.enter_context(self.connection.pipeline())
391
+ pending: list[PipelineCursorEntry] = []
392
+
393
+ for prepared in prepared_ops:
394
+ exception_ctx = self.handle_database_exceptions()
395
+ exception_handlers.append(exception_ctx)
396
+ resource_stack.enter_context(exception_ctx)
397
+ cursor = resource_stack.enter_context(self.with_cursor(self.connection))
398
+
399
+ try:
400
+ sql = cast("LiteralString | PsycopgSQL | PsycopgComposed", prepared.sql) # type: ignore[redundant-cast]
401
+ if prepared.parameters:
402
+ cursor.execute(sql, prepared.parameters)
403
+ else:
404
+ cursor.execute(sql)
405
+ except Exception as exc:
406
+ stack_error = StackExecutionError(
407
+ prepared.operation_index,
408
+ describe_stack_statement(prepared.operation.statement),
409
+ exc,
410
+ adapter=type(self).__name__,
411
+ mode="fail-fast",
412
+ )
413
+ raise stack_error from exc
414
+
415
+ pending.append(PipelineCursorEntry(prepared=prepared, cursor=cursor))
416
+
417
+ pipeline.sync()
418
+ for entry in pending:
419
+ statement = entry.prepared.statement
420
+ cursor = entry.cursor
421
+
422
+ execution_result = build_pipeline_execution_result(
423
+ statement, cursor, column_name_resolver=self._resolve_column_names
424
+ )
425
+ sql_result = self.build_statement_result(statement, execution_result)
426
+ results.append(StackResult.from_sql_result(sql_result))
427
+
428
+ for exception_ctx in exception_handlers:
429
+ _raise_pending_exception(exception_ctx)
430
+
431
+ if started_transaction:
432
+ self.commit()
433
+ except Exception:
434
+ if started_transaction:
435
+ try:
436
+ self.rollback()
437
+ except Exception as rollback_error: # pragma: no cover - diagnostics only
438
+ logger.debug("Rollback after psycopg pipeline failure failed: %s", rollback_error)
439
+ raise
440
+
441
+ return tuple(results)
442
+
443
+ # ─────────────────────────────────────────────────────────────────────────────
444
+ # STORAGE API METHODS
445
+ # ─────────────────────────────────────────────────────────────────────────────
446
+
447
+ def select_to_storage(
448
+ self,
449
+ statement: "SQL | str",
450
+ destination: "StorageDestination",
451
+ /,
452
+ *parameters: Any,
453
+ statement_config: "StatementConfig | None" = None,
454
+ partitioner: "dict[str, object] | None" = None,
455
+ format_hint: "StorageFormat | None" = None,
456
+ telemetry: "StorageTelemetry | None" = None,
457
+ **kwargs: Any,
458
+ ) -> "StorageBridgeJob":
459
+ """Execute a query and stream Arrow results to storage (sync)."""
460
+
461
+ self._require_capability("arrow_export_enabled")
462
+ arrow_result = self.select_to_arrow(statement, *parameters, statement_config=statement_config, **kwargs)
463
+ sync_pipeline = self._storage_pipeline()
464
+ telemetry_payload = self._write_result_to_storage_sync(
465
+ arrow_result, destination, format_hint=format_hint, pipeline=sync_pipeline
466
+ )
467
+ self._attach_partition_telemetry(telemetry_payload, partitioner)
468
+ return self._create_storage_job(telemetry_payload, telemetry)
469
+
470
+ def load_from_arrow(
471
+ self,
472
+ table: str,
473
+ source: "ArrowResult | Any",
474
+ *,
475
+ partitioner: "dict[str, object] | None" = None,
476
+ overwrite: bool = False,
477
+ telemetry: "StorageTelemetry | None" = None,
478
+ ) -> "StorageBridgeJob":
479
+ """Load Arrow data into PostgreSQL using COPY."""
480
+
481
+ self._require_capability("arrow_import_enabled")
482
+ arrow_table = self._coerce_arrow_table(source)
483
+ if overwrite:
484
+ truncate_sql = build_truncate_command(table)
485
+ exc_handler = self.handle_database_exceptions()
486
+ with self.with_cursor(self.connection) as cursor, exc_handler:
487
+ cursor.execute(truncate_sql)
488
+ if exc_handler.pending_exception is not None:
489
+ raise exc_handler.pending_exception from None
490
+ columns, records = self._arrow_table_to_rows(arrow_table)
491
+ if records:
492
+ copy_sql = build_copy_from_command(table, columns)
493
+ exc_handler = self.handle_database_exceptions()
494
+ with ExitStack() as stack:
495
+ stack.enter_context(exc_handler)
496
+ cursor = stack.enter_context(self.with_cursor(self.connection))
497
+ copy_ctx = stack.enter_context(cursor.copy(copy_sql))
498
+ for record in records:
499
+ copy_ctx.write_row(record)
500
+ if exc_handler.pending_exception is not None:
501
+ raise exc_handler.pending_exception from None
502
+ telemetry_payload = self._build_ingest_telemetry(arrow_table)
503
+ telemetry_payload["destination"] = table
504
+ self._attach_partition_telemetry(telemetry_payload, partitioner)
505
+ return self._create_storage_job(telemetry_payload, telemetry)
506
+
507
+ def load_from_storage(
508
+ self,
509
+ table: str,
510
+ source: "StorageDestination",
511
+ *,
512
+ file_format: "StorageFormat",
513
+ partitioner: "dict[str, object] | None" = None,
514
+ overwrite: bool = False,
515
+ ) -> "StorageBridgeJob":
516
+ """Load staged artifacts into PostgreSQL via COPY."""
517
+
518
+ arrow_table, inbound = self._read_arrow_from_storage_sync(source, file_format=file_format)
519
+ return self.load_from_arrow(table, arrow_table, partitioner=partitioner, overwrite=overwrite, telemetry=inbound)
520
+
521
+ # ─────────────────────────────────────────────────────────────────────────────
522
+ # UTILITY METHODS
523
+ # ─────────────────────────────────────────────────────────────────────────────
524
+
525
+ @property
526
+ def data_dictionary(self) -> "PsycopgSyncDataDictionary":
527
+ """Get the data dictionary for this driver.
528
+
529
+ Returns:
530
+ Data dictionary instance for metadata queries
531
+ """
532
+ if self._data_dictionary is None:
533
+ self._data_dictionary = PsycopgSyncDataDictionary()
534
+ return self._data_dictionary
535
+
536
+ # ─────────────────────────────────────────────────────────────────────────────
537
+ # PRIVATE / INTERNAL METHODS
538
+ # ─────────────────────────────────────────────────────────────────────────────
539
+
540
+ def _resolve_column_names(self, description: Any) -> list[str]:
541
+ """Resolve and cache psycopg column names for hot row materialization paths."""
542
+ if not description:
543
+ return []
544
+
545
+ cache_key = id(description)
546
+ cached = self._column_name_cache.get(cache_key)
547
+ if cached is not None and cached[0] is description:
548
+ return cached[1]
549
+
550
+ column_names = [col.name for col in description]
551
+
552
+ if len(self._column_name_cache) >= COLUMN_CACHE_MAX_SIZE:
553
+ self._column_name_cache.pop(next(iter(self._column_name_cache)))
554
+ self._column_name_cache[cache_key] = (description, column_names)
555
+ return column_names
556
+
557
+ def collect_rows(self, cursor: Any, fetched: "list[Any]") -> "tuple[list[Any], list[str], int]":
558
+ """Collect psycopg sync rows for the direct execution path."""
559
+ data = cast("list[Any] | None", fetched) or []
560
+ column_names = self._resolve_column_names(cursor.description)
561
+ return data, column_names, len(data)
562
+
563
+ def resolve_rowcount(self, cursor: Any) -> int:
564
+ """Resolve rowcount from psycopg cursor for the direct execution path."""
565
+ return resolve_rowcount(cursor)
566
+
567
+ def _connection_in_transaction(self) -> bool:
568
+ """Check if connection is in transaction."""
569
+ return bool(self.connection.info.transaction_status != TRANSACTION_STATUS_IDLE)
570
+
571
+
572
+ class PsycopgAsyncExceptionHandler(BaseAsyncExceptionHandler):
573
+ """Async context manager for handling PostgreSQL psycopg database exceptions.
574
+
575
+ Maps PostgreSQL SQLSTATE error codes to specific SQLSpec exceptions
576
+ for better error handling in application code.
577
+
578
+ Uses deferred exception pattern for mypyc compatibility: exceptions
579
+ are stored in pending_exception rather than raised from __aexit__
580
+ to avoid ABI boundary violations with compiled code.
581
+ """
582
+
583
+ __slots__ = ()
584
+
585
+ def _handle_exception(self, exc_type: "type[BaseException] | None", exc_val: "BaseException") -> bool:
586
+ if exc_type is None:
587
+ return False
588
+ if issubclass(exc_type, psycopg.Error):
589
+ self.pending_exception = create_mapped_exception(exc_val)
590
+ return True
591
+ return False
592
+
593
+
594
+ class PsycopgAsyncDriver(PsycopgPipelineMixin, AsyncDriverAdapterBase):
595
+ """PostgreSQL psycopg asynchronous driver.
596
+
597
+ Provides asynchronous database operations for PostgreSQL using psycopg3.
598
+ Supports async SQL statement execution with parameter binding, async
599
+ transaction management, async result processing with column metadata,
600
+ parameter style conversion, PostgreSQL arrays and JSON handling, COPY
601
+ operations for bulk data transfer, PostgreSQL-specific error handling,
602
+ and async pub/sub support.
603
+ """
604
+
605
+ __slots__ = ("_column_name_cache", "_data_dictionary")
606
+ dialect = "postgres"
607
+
608
+ def __init__(
609
+ self,
610
+ connection: "PsycopgAsyncConnection",
611
+ statement_config: "StatementConfig | None" = None,
612
+ driver_features: "dict[str, Any] | None" = None,
613
+ ) -> None:
614
+ if statement_config is None:
615
+ statement_config = default_statement_config.replace(
616
+ enable_caching=get_cache_config().compiled_cache_enabled
617
+ )
618
+
619
+ super().__init__(connection=connection, statement_config=statement_config, driver_features=driver_features)
620
+ self._data_dictionary: PsycopgAsyncDataDictionary | None = None
621
+ self._column_name_cache: dict[int, tuple[Any, list[str]]] = {}
622
+
623
+ # ─────────────────────────────────────────────────────────────────────────────
624
+ # CORE DISPATCH METHODS
625
+ # ─────────────────────────────────────────────────────────────────────────────
626
+
627
+ async def dispatch_execute(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
628
+ """Execute single SQL statement (async).
629
+
630
+ Args:
631
+ cursor: Database cursor
632
+ statement: SQL statement to execute
633
+
634
+ Returns:
635
+ ExecutionResult with statement execution details
636
+ """
637
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
638
+
639
+ await execute_with_optional_parameters_async(cursor, sql, prepared_parameters)
640
+
641
+ if statement.returns_rows():
642
+ fetched_data = await cursor.fetchall()
643
+ data = cast("list[Any] | None", fetched_data) or []
644
+ column_names = self._resolve_column_names(cursor.description)
645
+
646
+ return self.create_execution_result(
647
+ cursor,
648
+ selected_data=data,
649
+ column_names=column_names,
650
+ data_row_count=len(data),
651
+ is_select_result=True,
652
+ row_format="tuple",
653
+ )
654
+
655
+ affected_rows = resolve_rowcount(cursor)
656
+ return self.create_execution_result(cursor, rowcount_override=affected_rows)
657
+
658
+ async def dispatch_execute_many(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
659
+ """Execute SQL with multiple parameter sets (async).
660
+
661
+ Args:
662
+ cursor: Database cursor
663
+ statement: SQL statement with parameter list
664
+
665
+ Returns:
666
+ ExecutionResult with batch execution details
667
+ """
668
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
669
+
670
+ if not prepared_parameters:
671
+ return self.create_execution_result(cursor, rowcount_override=0, is_many_result=True)
672
+
673
+ parameter_count = len(prepared_parameters) if isinstance(prepared_parameters, Sized) else None
674
+ await cursor.executemany(sql, prepared_parameters)
675
+ affected_rows = resolve_many_rowcount(cursor, prepared_parameters, fallback_count=parameter_count)
676
+
677
+ return self.create_execution_result(cursor, rowcount_override=affected_rows, is_many_result=True)
678
+
679
+ async def dispatch_execute_script(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
680
+ """Execute SQL script with multiple statements (async).
681
+
682
+ Args:
683
+ cursor: Database cursor
684
+ statement: SQL statement containing multiple commands
685
+
686
+ Returns:
687
+ ExecutionResult with script execution details
688
+ """
689
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
690
+ statements = self.split_script_statements(sql, statement.statement_config, strip_trailing_semicolon=True)
691
+
692
+ successful_count = 0
693
+ last_cursor = cursor
694
+
695
+ for stmt in statements:
696
+ await execute_with_optional_parameters_async(cursor, stmt, prepared_parameters)
697
+ successful_count += 1
698
+
699
+ return self.create_execution_result(
700
+ last_cursor, statement_count=len(statements), successful_statements=successful_count, is_script_result=True
701
+ )
702
+
703
+ async def dispatch_special_handling(self, cursor: Any, statement: "SQL") -> "SQLResult | None":
704
+ """Hook for PostgreSQL-specific special operations.
705
+
706
+ Args:
707
+ cursor: Psycopg async cursor object
708
+ statement: SQL statement to analyze
709
+
710
+ Returns:
711
+ SQLResult if special handling was applied, None otherwise
712
+ """
713
+
714
+ if not is_copy_operation(statement.operation_type):
715
+ return None
716
+
717
+ sql, _ = self._get_compiled_sql(statement, statement.statement_config)
718
+ sql_upper = sql.upper()
719
+ operation_type = statement.operation_type
720
+ copy_data = statement.parameters
721
+ if isinstance(copy_data, list) and len(copy_data) == 1:
722
+ copy_data = copy_data[0]
723
+
724
+ if is_copy_from_operation(operation_type) and "FROM STDIN" in sql_upper:
725
+ if isinstance(copy_data, (str, bytes)):
726
+ data_to_write = copy_data
727
+ elif is_readable(copy_data):
728
+ data_to_write = copy_data.read()
729
+ else:
730
+ data_to_write = str(copy_data)
731
+
732
+ if isinstance(data_to_write, str):
733
+ data_to_write = data_to_write.encode()
734
+
735
+ async with cursor.copy(sql) as copy_ctx:
736
+ await copy_ctx.write(data_to_write)
737
+
738
+ rows_affected = max(cursor.rowcount, 0)
739
+
740
+ return SQLResult(
741
+ data=None, rows_affected=rows_affected, statement=statement, metadata={"copy_operation": "FROM_STDIN"}
742
+ )
743
+
744
+ if is_copy_to_operation(operation_type) and "TO STDOUT" in sql_upper:
745
+ output_data: list[str] = []
746
+ async with cursor.copy(sql) as copy_ctx:
747
+ output_data.extend([row.decode() if isinstance(row, bytes) else str(row) async for row in copy_ctx])
748
+
749
+ exported_data = "".join(output_data)
750
+
751
+ return SQLResult(
752
+ data=[{"copy_output": exported_data}],
753
+ rows_affected=0,
754
+ statement=statement,
755
+ metadata={"copy_operation": "TO_STDOUT"},
756
+ )
757
+
758
+ await cursor.execute(sql)
759
+ rows_affected = max(cursor.rowcount, 0)
760
+
761
+ return SQLResult(
762
+ data=None, rows_affected=rows_affected, statement=statement, metadata={"copy_operation": "FILE"}
763
+ )
764
+
765
+ # ─────────────────────────────────────────────────────────────────────────────
766
+ # TRANSACTION MANAGEMENT
767
+ # ─────────────────────────────────────────────────────────────────────────────
768
+
769
+ async def begin(self) -> None:
770
+ """Begin a database transaction on the current connection."""
771
+ try:
772
+ try:
773
+ autocommit_flag = self.connection.autocommit
774
+ except AttributeError:
775
+ autocommit_flag = None
776
+ if isinstance(autocommit_flag, bool) and not autocommit_flag:
777
+ return
778
+ await self.connection.set_autocommit(False)
779
+ except Exception as e:
780
+ msg = f"Failed to begin transaction: {e}"
781
+ raise SQLSpecError(msg) from e
782
+
783
+ async def commit(self) -> None:
784
+ """Commit the current transaction on the current connection."""
785
+ try:
786
+ await self.connection.commit()
787
+ except Exception as e:
788
+ msg = f"Failed to commit transaction: {e}"
789
+ raise SQLSpecError(msg) from e
790
+
791
+ async def rollback(self) -> None:
792
+ """Rollback the current transaction on the current connection."""
793
+ try:
794
+ await self.connection.rollback()
795
+ except Exception as e:
796
+ msg = f"Failed to rollback transaction: {e}"
797
+ raise SQLSpecError(msg) from e
798
+
799
+ def with_cursor(self, connection: "PsycopgAsyncConnection") -> "PsycopgAsyncCursor":
800
+ """Create async context manager for PostgreSQL cursor."""
801
+ return PsycopgAsyncCursor(connection)
802
+
803
+ def handle_database_exceptions(self) -> "PsycopgAsyncExceptionHandler":
804
+ """Handle database-specific exceptions and wrap them appropriately."""
805
+ return PsycopgAsyncExceptionHandler()
806
+
807
+ # ─────────────────────────────────────────────────────────────────────────────
808
+ # STACK EXECUTION METHODS
809
+ # ─────────────────────────────────────────────────────────────────────────────
810
+
811
+ async def execute_stack(
812
+ self, stack: "StatementStack", *, continue_on_error: bool = False
813
+ ) -> "tuple[StackResult, ...]":
814
+ """Execute a StatementStack using psycopg async pipeline when supported."""
815
+
816
+ if (
817
+ not isinstance(stack, StatementStack)
818
+ or not stack
819
+ or self.stack_native_disabled
820
+ or not pipeline_supported()
821
+ or continue_on_error
822
+ ):
823
+ return await super().execute_stack(stack, continue_on_error=continue_on_error)
824
+
825
+ prepared_ops = self._prepare_pipeline_operations(stack)
826
+ if prepared_ops is None:
827
+ return await super().execute_stack(stack, continue_on_error=continue_on_error)
828
+
829
+ return await self._execute_stack_pipeline(stack, prepared_ops)
830
+
831
+ async def _execute_stack_pipeline(
832
+ self, stack: "StatementStack", prepared_ops: "list[PreparedStackOperation]"
833
+ ) -> "tuple[StackResult, ...]":
834
+ def _raise_pending_exception(exception_ctx: "PsycopgAsyncExceptionHandler") -> None:
835
+ if exception_ctx.pending_exception is not None:
836
+ raise exception_ctx.pending_exception from None
837
+
838
+ results: list[StackResult] = []
839
+ started_transaction = False
840
+
841
+ with StackExecutionObserver(self, stack, continue_on_error=False, native_pipeline=True):
842
+ try:
843
+ if not self._connection_in_transaction():
844
+ await self.begin()
845
+ started_transaction = True
846
+
847
+ exception_handlers = []
848
+ async with AsyncExitStack() as resource_stack:
849
+ pipeline = await resource_stack.enter_async_context(self.connection.pipeline())
850
+ pending: list[PipelineCursorEntry] = []
851
+
852
+ for prepared in prepared_ops:
853
+ exception_ctx = self.handle_database_exceptions()
854
+ exception_handlers.append(exception_ctx)
855
+ await resource_stack.enter_async_context(exception_ctx)
856
+ cursor = await resource_stack.enter_async_context(self.with_cursor(self.connection))
857
+
858
+ try:
859
+ sql = cast("LiteralString | PsycopgSQL | PsycopgComposed", prepared.sql) # type: ignore[redundant-cast]
860
+ if prepared.parameters:
861
+ await cursor.execute(sql, prepared.parameters)
862
+ else:
863
+ await cursor.execute(sql)
864
+ except Exception as exc:
865
+ stack_error = StackExecutionError(
866
+ prepared.operation_index,
867
+ describe_stack_statement(prepared.operation.statement),
868
+ exc,
869
+ adapter=type(self).__name__,
870
+ mode="fail-fast",
871
+ )
872
+ raise stack_error from exc
873
+
874
+ pending.append(PipelineCursorEntry(prepared=prepared, cursor=cursor))
875
+
876
+ await pipeline.sync()
877
+ for entry in pending:
878
+ statement = entry.prepared.statement
879
+ cursor = entry.cursor
880
+
881
+ execution_result = await build_async_pipeline_execution_result(
882
+ statement, cursor, column_name_resolver=self._resolve_column_names
883
+ )
884
+ sql_result = self.build_statement_result(statement, execution_result)
885
+ results.append(StackResult.from_sql_result(sql_result))
886
+
887
+ for exception_ctx in exception_handlers:
888
+ _raise_pending_exception(exception_ctx)
889
+
890
+ if started_transaction:
891
+ await self.commit()
892
+ except Exception:
893
+ if started_transaction:
894
+ try:
895
+ await self.rollback()
896
+ except Exception as rollback_error: # pragma: no cover - diagnostics only
897
+ logger.debug("Rollback after psycopg pipeline failure failed: %s", rollback_error)
898
+ raise
899
+
900
+ return tuple(results)
901
+
902
+ # ─────────────────────────────────────────────────────────────────────────────
903
+ # STORAGE API METHODS
904
+ # ─────────────────────────────────────────────────────────────────────────────
905
+
906
+ async def select_to_storage(
907
+ self,
908
+ statement: "SQL | str",
909
+ destination: "StorageDestination",
910
+ /,
911
+ *parameters: Any,
912
+ statement_config: "StatementConfig | None" = None,
913
+ partitioner: "dict[str, object] | None" = None,
914
+ format_hint: "StorageFormat | None" = None,
915
+ telemetry: "StorageTelemetry | None" = None,
916
+ **kwargs: Any,
917
+ ) -> "StorageBridgeJob":
918
+ """Execute a query and stream Arrow data to storage asynchronously."""
919
+
920
+ self._require_capability("arrow_export_enabled")
921
+ arrow_result = await self.select_to_arrow(statement, *parameters, statement_config=statement_config, **kwargs)
922
+ async_pipeline = self._storage_pipeline()
923
+ telemetry_payload = await self._write_result_to_storage_async(
924
+ arrow_result, destination, format_hint=format_hint, pipeline=async_pipeline
925
+ )
926
+ self._attach_partition_telemetry(telemetry_payload, partitioner)
927
+ return self._create_storage_job(telemetry_payload, telemetry)
928
+
929
+ async def load_from_arrow(
930
+ self,
931
+ table: str,
932
+ source: "ArrowResult | Any",
933
+ *,
934
+ partitioner: "dict[str, object] | None" = None,
935
+ overwrite: bool = False,
936
+ telemetry: "StorageTelemetry | None" = None,
937
+ ) -> "StorageBridgeJob":
938
+ """Load Arrow data into PostgreSQL asynchronously via COPY."""
939
+
940
+ self._require_capability("arrow_import_enabled")
941
+ arrow_table = self._coerce_arrow_table(source)
942
+ if overwrite:
943
+ truncate_sql = build_truncate_command(table)
944
+ exc_handler = self.handle_database_exceptions()
945
+ async with self.with_cursor(self.connection) as cursor, exc_handler:
946
+ await cursor.execute(truncate_sql)
947
+ if exc_handler.pending_exception is not None:
948
+ raise exc_handler.pending_exception from None
949
+ columns, records = self._arrow_table_to_rows(arrow_table)
950
+ if records:
951
+ copy_sql = build_copy_from_command(table, columns)
952
+ exc_handler = self.handle_database_exceptions()
953
+ async with AsyncExitStack() as stack:
954
+ await stack.enter_async_context(exc_handler)
955
+ cursor = await stack.enter_async_context(self.with_cursor(self.connection))
956
+ copy_ctx = await stack.enter_async_context(cursor.copy(copy_sql))
957
+ for record in records:
958
+ await copy_ctx.write_row(record)
959
+ if exc_handler.pending_exception is not None:
960
+ raise exc_handler.pending_exception from None
961
+ telemetry_payload = self._build_ingest_telemetry(arrow_table)
962
+ telemetry_payload["destination"] = table
963
+ self._attach_partition_telemetry(telemetry_payload, partitioner)
964
+ return self._create_storage_job(telemetry_payload, telemetry)
965
+
966
+ async def load_from_storage(
967
+ self,
968
+ table: str,
969
+ source: "StorageDestination",
970
+ *,
971
+ file_format: "StorageFormat",
972
+ partitioner: "dict[str, object] | None" = None,
973
+ overwrite: bool = False,
974
+ ) -> "StorageBridgeJob":
975
+ """Load staged artifacts asynchronously."""
976
+
977
+ arrow_table, inbound = await self._read_arrow_from_storage_async(source, file_format=file_format)
978
+ return await self.load_from_arrow(
979
+ table, arrow_table, partitioner=partitioner, overwrite=overwrite, telemetry=inbound
980
+ )
981
+
982
+ # ─────────────────────────────────────────────────────────────────────────────
983
+ # UTILITY METHODS
984
+ # ─────────────────────────────────────────────────────────────────────────────
985
+
986
+ @property
987
+ def data_dictionary(self) -> "PsycopgAsyncDataDictionary":
988
+ """Get the data dictionary for this driver.
989
+
990
+ Returns:
991
+ Data dictionary instance for metadata queries
992
+ """
993
+ if self._data_dictionary is None:
994
+ self._data_dictionary = PsycopgAsyncDataDictionary()
995
+ return self._data_dictionary
996
+
997
+ # ─────────────────────────────────────────────────────────────────────────────
998
+ # PRIVATE / INTERNAL METHODS
999
+ # ─────────────────────────────────────────────────────────────────────────────
1000
+
1001
+ def _resolve_column_names(self, description: Any) -> list[str]:
1002
+ """Resolve and cache psycopg column names for hot row materialization paths."""
1003
+ if not description:
1004
+ return []
1005
+
1006
+ cache_key = id(description)
1007
+ cached = self._column_name_cache.get(cache_key)
1008
+ if cached is not None and cached[0] is description:
1009
+ return cached[1]
1010
+
1011
+ column_names = [col.name for col in description]
1012
+
1013
+ if len(self._column_name_cache) >= COLUMN_CACHE_MAX_SIZE:
1014
+ self._column_name_cache.pop(next(iter(self._column_name_cache)))
1015
+ self._column_name_cache[cache_key] = (description, column_names)
1016
+ return column_names
1017
+
1018
+ def collect_rows(self, cursor: Any, fetched: "list[Any]") -> "tuple[list[Any], list[str], int]":
1019
+ """Collect psycopg async rows for the direct execution path."""
1020
+ data = cast("list[Any] | None", fetched) or []
1021
+ column_names = self._resolve_column_names(cursor.description)
1022
+ return data, column_names, len(data)
1023
+
1024
+ def resolve_rowcount(self, cursor: Any) -> int:
1025
+ """Resolve rowcount from psycopg cursor for the direct execution path."""
1026
+ return resolve_rowcount(cursor)
1027
+
1028
+ def _connection_in_transaction(self) -> bool:
1029
+ """Check if connection is in transaction."""
1030
+ return bool(self.connection.info.transaction_status != TRANSACTION_STATUS_IDLE)
1031
+
1032
+
1033
+ register_driver_profile("psycopg", driver_profile)