execsql2 2.21.1__tar.gz → 2.21.2__tar.gz

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 (373) hide show
  1. {execsql2-2.21.1 → execsql2-2.21.2}/.github/workflows/ci-cd.yml +13 -13
  2. {execsql2-2.21.1 → execsql2-2.21.2}/CHANGELOG.md +8 -0
  3. {execsql2-2.21.1 → execsql2-2.21.2}/PKG-INFO +2 -2
  4. {execsql2-2.21.1 → execsql2-2.21.2}/README.md +1 -1
  5. {execsql2-2.21.1 → execsql2-2.21.2}/docs/guides/formatter.md +1 -1
  6. {execsql2-2.21.1 → execsql2-2.21.2}/pyproject.toml +2 -2
  7. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/feather.py +1 -1
  8. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/parquet.py +1 -1
  9. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_postgres.py +46 -0
  10. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_parquet.py +8 -0
  11. {execsql2-2.21.1 → execsql2-2.21.2}/tests/integration/test_postgres.py +51 -0
  12. {execsql2-2.21.1 → execsql2-2.21.2}/uv.lock +1 -1
  13. {execsql2-2.21.1 → execsql2-2.21.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  14. {execsql2-2.21.1 → execsql2-2.21.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  15. {execsql2-2.21.1 → execsql2-2.21.2}/.github/dependabot.yml +0 -0
  16. {execsql2-2.21.1 → execsql2-2.21.2}/.gitignore +0 -0
  17. {execsql2-2.21.1 → execsql2-2.21.2}/.pre-commit-config.yaml +0 -0
  18. {execsql2-2.21.1 → execsql2-2.21.2}/.pre-commit-hooks.yaml +0 -0
  19. {execsql2-2.21.1 → execsql2-2.21.2}/.python-version +0 -0
  20. {execsql2-2.21.1 → execsql2-2.21.2}/.readthedocs.yaml +0 -0
  21. {execsql2-2.21.1 → execsql2-2.21.2}/CONTRIBUTING.md +0 -0
  22. {execsql2-2.21.1 → execsql2-2.21.2}/LICENSE.txt +0 -0
  23. {execsql2-2.21.1 → execsql2-2.21.2}/NOTICE +0 -0
  24. {execsql2-2.21.1 → execsql2-2.21.2}/SECURITY.md +0 -0
  25. {execsql2-2.21.1 → execsql2-2.21.2}/docs/about/contributors.md +0 -0
  26. {execsql2-2.21.1 → execsql2-2.21.2}/docs/about/copyright.md +0 -0
  27. {execsql2-2.21.1 → execsql2-2.21.2}/docs/about/divergence.md +0 -0
  28. {execsql2-2.21.1 → execsql2-2.21.2}/docs/api/cli.md +0 -0
  29. {execsql2-2.21.1 → execsql2-2.21.2}/docs/api/db.md +0 -0
  30. {execsql2-2.21.1 → execsql2-2.21.2}/docs/api/exporters.md +0 -0
  31. {execsql2-2.21.1 → execsql2-2.21.2}/docs/api/importers.md +0 -0
  32. {execsql2-2.21.1 → execsql2-2.21.2}/docs/api/index.md +0 -0
  33. {execsql2-2.21.1 → execsql2-2.21.2}/docs/api/metacommands.md +0 -0
  34. {execsql2-2.21.1 → execsql2-2.21.2}/docs/dev/adding_db_adapters.md +0 -0
  35. {execsql2-2.21.1 → execsql2-2.21.2}/docs/dev/adding_exporters.md +0 -0
  36. {execsql2-2.21.1 → execsql2-2.21.2}/docs/dev/adding_importers.md +0 -0
  37. {execsql2-2.21.1 → execsql2-2.21.2}/docs/dev/adding_metacommands.md +0 -0
  38. {execsql2-2.21.1 → execsql2-2.21.2}/docs/dev/architecture.md +0 -0
  39. {execsql2-2.21.1 → execsql2-2.21.2}/docs/dev/releasing.md +0 -0
  40. {execsql2-2.21.1 → execsql2-2.21.2}/docs/getting-started/installation.md +0 -0
  41. {execsql2-2.21.1 → execsql2-2.21.2}/docs/getting-started/requirements.md +0 -0
  42. {execsql2-2.21.1 → execsql2-2.21.2}/docs/getting-started/syntax.md +0 -0
  43. {execsql2-2.21.1 → execsql2-2.21.2}/docs/guides/debugging.md +0 -0
  44. {execsql2-2.21.1 → execsql2-2.21.2}/docs/guides/documentation.md +0 -0
  45. {execsql2-2.21.1 → execsql2-2.21.2}/docs/guides/encoding.md +0 -0
  46. {execsql2-2.21.1 → execsql2-2.21.2}/docs/guides/examples.md +0 -0
  47. {execsql2-2.21.1 → execsql2-2.21.2}/docs/guides/logging.md +0 -0
  48. {execsql2-2.21.1 → execsql2-2.21.2}/docs/guides/sql_syntax.md +0 -0
  49. {execsql2-2.21.1 → execsql2-2.21.2}/docs/guides/usage.md +0 -0
  50. {execsql2-2.21.1 → execsql2-2.21.2}/docs/guides/using_scripts.md +0 -0
  51. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/Compare_planets.png +0 -0
  52. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/actions.png +0 -0
  53. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/actions2.png +0 -0
  54. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/checkboxes.png +0 -0
  55. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/connect.b64 +0 -0
  56. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/connect.png +0 -0
  57. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/create_conf.png +0 -0
  58. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/data_error1_screenshot.jpg +0 -0
  59. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/entry_form.png +0 -0
  60. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/execsql_console.png +0 -0
  61. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/execsql_logo_01.png +0 -0
  62. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/fatals.png +0 -0
  63. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/logo_small.png +0 -0
  64. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/pause_terminal.png +0 -0
  65. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/pause_terminal_sm.b64 +0 -0
  66. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/pause_terminal_sm.png +0 -0
  67. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/prompt_compare.png +0 -0
  68. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/set_build_commands.jpg +0 -0
  69. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/unit_conversions.b64 +0 -0
  70. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/unit_conversions_029.png +0 -0
  71. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/unmatched.png +0 -0
  72. {execsql2-2.21.1 → execsql2-2.21.2}/docs/images/vim_execsql_highlight.png +0 -0
  73. {execsql2-2.21.1 → execsql2-2.21.2}/docs/index.md +0 -0
  74. {execsql2-2.21.1 → execsql2-2.21.2}/docs/reference/configuration.md +0 -0
  75. {execsql2-2.21.1 → execsql2-2.21.2}/docs/reference/metacommands.md +0 -0
  76. {execsql2-2.21.1 → execsql2-2.21.2}/docs/reference/security.md +0 -0
  77. {execsql2-2.21.1 → execsql2-2.21.2}/docs/reference/substitution_vars.md +0 -0
  78. {execsql2-2.21.1 → execsql2-2.21.2}/extras/plugin-template/README.md +0 -0
  79. {execsql2-2.21.1 → execsql2-2.21.2}/extras/plugin-template/pyproject.toml +0 -0
  80. {execsql2-2.21.1 → execsql2-2.21.2}/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +0 -0
  81. {execsql2-2.21.1 → execsql2-2.21.2}/extras/plugin-template/tests/test_plugin.py.example +0 -0
  82. {execsql2-2.21.1 → execsql2-2.21.2}/extras/vscode-execsql/README.md +0 -0
  83. {execsql2-2.21.1 → execsql2-2.21.2}/extras/vscode-execsql/package.json +0 -0
  84. {execsql2-2.21.1 → execsql2-2.21.2}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
  85. {execsql2-2.21.1 → execsql2-2.21.2}/justfile +0 -0
  86. {execsql2-2.21.1 → execsql2-2.21.2}/scripts/generate_vscode_grammar.py +0 -0
  87. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/__init__.py +0 -0
  88. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/__main__.py +0 -0
  89. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/api.py +0 -0
  90. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/cli/__init__.py +0 -0
  91. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/cli/dsn.py +0 -0
  92. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/cli/help.py +0 -0
  93. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/cli/lint.py +0 -0
  94. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/cli/run.py +0 -0
  95. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/config.py +0 -0
  96. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/data/__init__.py +0 -0
  97. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/data/execsql.conf.template +0 -0
  98. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/__init__.py +0 -0
  99. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/access.py +0 -0
  100. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/base.py +0 -0
  101. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/dsn.py +0 -0
  102. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/duckdb.py +0 -0
  103. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/factory.py +0 -0
  104. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/firebird.py +0 -0
  105. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/mysql.py +0 -0
  106. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/oracle.py +0 -0
  107. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/postgres.py +0 -0
  108. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/sqlite.py +0 -0
  109. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/db/sqlserver.py +0 -0
  110. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/debug/__init__.py +0 -0
  111. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/debug/repl.py +0 -0
  112. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exceptions.py +0 -0
  113. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/__init__.py +0 -0
  114. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/base.py +0 -0
  115. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/delimited.py +0 -0
  116. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/duckdb.py +0 -0
  117. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/html.py +0 -0
  118. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/json.py +0 -0
  119. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/latex.py +0 -0
  120. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/markdown.py +0 -0
  121. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/ods.py +0 -0
  122. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/pretty.py +0 -0
  123. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/protocol.py +0 -0
  124. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/raw.py +0 -0
  125. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/sqlite.py +0 -0
  126. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/templates.py +0 -0
  127. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/values.py +0 -0
  128. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/xls.py +0 -0
  129. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/xlsx.py +0 -0
  130. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/xml.py +0 -0
  131. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/yaml.py +0 -0
  132. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/exporters/zip.py +0 -0
  133. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/format.py +0 -0
  134. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/gui/__init__.py +0 -0
  135. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/gui/base.py +0 -0
  136. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/gui/console.py +0 -0
  137. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/gui/desktop.py +0 -0
  138. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/gui/tui.py +0 -0
  139. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/importers/__init__.py +0 -0
  140. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/importers/base.py +0 -0
  141. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/importers/csv.py +0 -0
  142. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/importers/feather.py +0 -0
  143. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/importers/json.py +0 -0
  144. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/importers/ods.py +0 -0
  145. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/importers/xls.py +0 -0
  146. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/__init__.py +0 -0
  147. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/conditions.py +0 -0
  148. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/connect.py +0 -0
  149. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/control.py +0 -0
  150. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/data.py +0 -0
  151. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/debug.py +0 -0
  152. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/dispatch.py +0 -0
  153. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/io.py +0 -0
  154. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/io_export.py +0 -0
  155. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/io_fileops.py +0 -0
  156. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/io_import.py +0 -0
  157. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/io_write.py +0 -0
  158. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/prompt.py +0 -0
  159. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/script_ext.py +0 -0
  160. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/system.py +0 -0
  161. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/metacommands/upsert.py +0 -0
  162. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/models.py +0 -0
  163. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/parser.py +0 -0
  164. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/plugins.py +0 -0
  165. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/py.typed +0 -0
  166. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/script/__init__.py +0 -0
  167. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/script/ast.py +0 -0
  168. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/script/control.py +0 -0
  169. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/script/engine.py +0 -0
  170. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/script/executor.py +0 -0
  171. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/script/parser.py +0 -0
  172. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/script/variables.py +0 -0
  173. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/state.py +0 -0
  174. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/types.py +0 -0
  175. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/__init__.py +0 -0
  176. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/auth.py +0 -0
  177. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/crypto.py +0 -0
  178. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/datetime.py +0 -0
  179. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/errors.py +0 -0
  180. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/fileio.py +0 -0
  181. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/gui.py +0 -0
  182. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/mail.py +0 -0
  183. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/numeric.py +0 -0
  184. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/regex.py +0 -0
  185. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/strings.py +0 -0
  186. {execsql2-2.21.1 → execsql2-2.21.2}/src/execsql/utils/timer.py +0 -0
  187. {execsql2-2.21.1 → execsql2-2.21.2}/templates/README.md +0 -0
  188. {execsql2-2.21.1 → execsql2-2.21.2}/templates/config_settings.sqlite +0 -0
  189. {execsql2-2.21.1 → execsql2-2.21.2}/templates/example_config_prompt.sql +0 -0
  190. {execsql2-2.21.1 → execsql2-2.21.2}/templates/make_config_db.sql +0 -0
  191. {execsql2-2.21.1 → execsql2-2.21.2}/templates/md_compare.sql +0 -0
  192. {execsql2-2.21.1 → execsql2-2.21.2}/templates/md_glossary.sql +0 -0
  193. {execsql2-2.21.1 → execsql2-2.21.2}/templates/md_upsert.sql +0 -0
  194. {execsql2-2.21.1 → execsql2-2.21.2}/templates/pg_compare.sql +0 -0
  195. {execsql2-2.21.1 → execsql2-2.21.2}/templates/pg_glossary.sql +0 -0
  196. {execsql2-2.21.1 → execsql2-2.21.2}/templates/pg_upsert.sql +0 -0
  197. {execsql2-2.21.1 → execsql2-2.21.2}/templates/script_template.sql +0 -0
  198. {execsql2-2.21.1 → execsql2-2.21.2}/templates/ss_compare.sql +0 -0
  199. {execsql2-2.21.1 → execsql2-2.21.2}/templates/ss_glossary.sql +0 -0
  200. {execsql2-2.21.1 → execsql2-2.21.2}/templates/ss_upsert.sql +0 -0
  201. {execsql2-2.21.1 → execsql2-2.21.2}/tests/__init__.py +0 -0
  202. {execsql2-2.21.1 → execsql2-2.21.2}/tests/cli/__init__.py +0 -0
  203. {execsql2-2.21.1 → execsql2-2.21.2}/tests/cli/test_cli.py +0 -0
  204. {execsql2-2.21.1 → execsql2-2.21.2}/tests/cli/test_cli_e2e.py +0 -0
  205. {execsql2-2.21.1 → execsql2-2.21.2}/tests/cli/test_cli_run.py +0 -0
  206. {execsql2-2.21.1 → execsql2-2.21.2}/tests/cli/test_lint.py +0 -0
  207. {execsql2-2.21.1 → execsql2-2.21.2}/tests/cli/test_ping.py +0 -0
  208. {execsql2-2.21.1 → execsql2-2.21.2}/tests/cli/test_profile.py +0 -0
  209. {execsql2-2.21.1 → execsql2-2.21.2}/tests/conftest.py +0 -0
  210. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/__init__.py +0 -0
  211. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_access_windows.py +0 -0
  212. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_base.py +0 -0
  213. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_db_adapters_mocked.py +0 -0
  214. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_db_adapters_mocked_extra.py +0 -0
  215. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_dsn.py +0 -0
  216. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_duckdb.py +0 -0
  217. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_factory.py +0 -0
  218. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_mysql_case_folding.py +0 -0
  219. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_mysql_inprocess.py +0 -0
  220. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_postgres_inprocess.py +0 -0
  221. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_sqlite.py +0 -0
  222. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_sqlite_extra.py +0 -0
  223. {execsql2-2.21.1 → execsql2-2.21.2}/tests/db/test_sqlserver_inprocess.py +0 -0
  224. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/__init__.py +0 -0
  225. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_base.py +0 -0
  226. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_db.py +0 -0
  227. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_delimited.py +0 -0
  228. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_duckdb_exporter.py +0 -0
  229. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_exporters.py +0 -0
  230. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_feather.py +0 -0
  231. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_html_extended.py +0 -0
  232. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_html_latex.py +0 -0
  233. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_json.py +0 -0
  234. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_json_extended.py +0 -0
  235. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_latex_extended.py +0 -0
  236. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_markdown.py +0 -0
  237. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_ods.py +0 -0
  238. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_ods_export.py +0 -0
  239. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_pretty_extended.py +0 -0
  240. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_raw_extended.py +0 -0
  241. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_sqlite_exporter.py +0 -0
  242. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_templates.py +0 -0
  243. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_templates_extended.py +0 -0
  244. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_values_extended.py +0 -0
  245. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_xls_xlsx.py +0 -0
  246. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_xlsx.py +0 -0
  247. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_xml.py +0 -0
  248. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_yaml.py +0 -0
  249. {execsql2-2.21.1 → execsql2-2.21.2}/tests/exporters/test_zip.py +0 -0
  250. {execsql2-2.21.1 → execsql2-2.21.2}/tests/gui/__init__.py +0 -0
  251. {execsql2-2.21.1 → execsql2-2.21.2}/tests/gui/test_backends.py +0 -0
  252. {execsql2-2.21.1 → execsql2-2.21.2}/tests/gui/test_backends_extended.py +0 -0
  253. {execsql2-2.21.1 → execsql2-2.21.2}/tests/gui/test_compare_stats.py +0 -0
  254. {execsql2-2.21.1 → execsql2-2.21.2}/tests/gui/test_compute_row_diffs.py +0 -0
  255. {execsql2-2.21.1 → execsql2-2.21.2}/tests/gui/test_desktop_dialogs.py +0 -0
  256. {execsql2-2.21.1 → execsql2-2.21.2}/tests/gui/test_tui_pilot.py +0 -0
  257. {execsql2-2.21.1 → execsql2-2.21.2}/tests/gui/test_tui_pilot_complex.py +0 -0
  258. {execsql2-2.21.1 → execsql2-2.21.2}/tests/gui/test_utils_gui_extended.py +0 -0
  259. {execsql2-2.21.1 → execsql2-2.21.2}/tests/importers/__init__.py +0 -0
  260. {execsql2-2.21.1 → execsql2-2.21.2}/tests/importers/test_base_extended.py +0 -0
  261. {execsql2-2.21.1 → execsql2-2.21.2}/tests/importers/test_csv_edge_cases.py +0 -0
  262. {execsql2-2.21.1 → execsql2-2.21.2}/tests/importers/test_csv_importer.py +0 -0
  263. {execsql2-2.21.1 → execsql2-2.21.2}/tests/importers/test_feather_importer.py +0 -0
  264. {execsql2-2.21.1 → execsql2-2.21.2}/tests/importers/test_json_importer.py +0 -0
  265. {execsql2-2.21.1 → execsql2-2.21.2}/tests/importers/test_ods_importer.py +0 -0
  266. {execsql2-2.21.1 → execsql2-2.21.2}/tests/importers/test_xls_importer.py +0 -0
  267. {execsql2-2.21.1 → execsql2-2.21.2}/tests/integration/__init__.py +0 -0
  268. {execsql2-2.21.1 → execsql2-2.21.2}/tests/integration/conftest.py +0 -0
  269. {execsql2-2.21.1 → execsql2-2.21.2}/tests/integration/test_dsn.py +0 -0
  270. {execsql2-2.21.1 → execsql2-2.21.2}/tests/integration/test_duckdb.py +0 -0
  271. {execsql2-2.21.1 → execsql2-2.21.2}/tests/integration/test_mysql.py +0 -0
  272. {execsql2-2.21.1 → execsql2-2.21.2}/tests/integration/test_sqlite.py +0 -0
  273. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/__init__.py +0 -0
  274. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_assert.py +0 -0
  275. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_breakpoint.py +0 -0
  276. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_conditions_extra.py +0 -0
  277. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_connect.py +0 -0
  278. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_io_export.py +0 -0
  279. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_io_import.py +0 -0
  280. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_metacommands.py +0 -0
  281. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_metacommands_connect.py +0 -0
  282. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_metacommands_data.py +0 -0
  283. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_metacommands_extended.py +0 -0
  284. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
  285. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_metacommands_io.py +0 -0
  286. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
  287. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_metacommands_script_ext.py +0 -0
  288. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_metacommands_system.py +0 -0
  289. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_metacommands_system_extra.py +0 -0
  290. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_pg_upsert.py +0 -0
  291. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_prompt.py +0 -0
  292. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_row_count.py +0 -0
  293. {execsql2-2.21.1 → execsql2-2.21.2}/tests/metacommands/test_show_scripts.py +0 -0
  294. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/__init__.py +0 -0
  295. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/audit_lint_bad.sql +0 -0
  296. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/audit_smoke/sample.json +0 -0
  297. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/audit_smoke/sample.jsonl +0 -0
  298. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/audit_smoke.sql +0 -0
  299. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/config_runtime.sql +0 -0
  300. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/control_flow.sql +0 -0
  301. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/counters_and_locals.sql +0 -0
  302. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/error_handling.sql +0 -0
  303. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/import_options/has_comments.csv +0 -0
  304. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/import_options.sql +0 -0
  305. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/includes/helper.sql +0 -0
  306. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/includes.sql +0 -0
  307. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/io_formats.sql +0 -0
  308. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
  309. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/multi_db.sql +0 -0
  310. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/parquet_feather_roundtrip.sql +0 -0
  311. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/parse_only/parse_tree.sql +0 -0
  312. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/predicates.sql +0 -0
  313. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/scripts.sql +0 -0
  314. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/smoke.sql +0 -0
  315. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/subroutine_loops.sql +0 -0
  316. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/subvars_advanced.sql +0 -0
  317. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/template_export/greeting.tmpl +0 -0
  318. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/template_export.sql +0 -0
  319. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/timer.sql +0 -0
  320. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/transactions.sql +0 -0
  321. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/write_create_table.sql +0 -0
  322. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/fixtures/xlsx_ods_roundtrip.sql +0 -0
  323. {execsql2-2.21.1 → execsql2-2.21.2}/tests/scripts/test_sql_scripts.py +0 -0
  324. {execsql2-2.21.1 → execsql2-2.21.2}/tests/security/__init__.py +0 -0
  325. {execsql2-2.21.1 → execsql2-2.21.2}/tests/security/test_env_detection.py +0 -0
  326. {execsql2-2.21.1 → execsql2-2.21.2}/tests/security/test_expansion_bomb.py +0 -0
  327. {execsql2-2.21.1 → execsql2-2.21.2}/tests/security/test_import_regex_hardening.py +0 -0
  328. {execsql2-2.21.1 → execsql2-2.21.2}/tests/security/test_log_redaction.py +0 -0
  329. {execsql2-2.21.1 → execsql2-2.21.2}/tests/security/test_odbc_injection.py +0 -0
  330. {execsql2-2.21.1 → execsql2-2.21.2}/tests/security/test_path_containment.py +0 -0
  331. {execsql2-2.21.1 → execsql2-2.21.2}/tests/security/test_substitution_injection.py +0 -0
  332. {execsql2-2.21.1 → execsql2-2.21.2}/tests/security/test_zip_bomb.py +0 -0
  333. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_api.py +0 -0
  334. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_api_extended.py +0 -0
  335. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_ast.py +0 -0
  336. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_ast_parser.py +0 -0
  337. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_bundled_templates.py +0 -0
  338. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_config.py +0 -0
  339. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_config_data.py +0 -0
  340. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_config_extended.py +0 -0
  341. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_debug_repl.py +0 -0
  342. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_engine.py +0 -0
  343. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_error_messages.py +0 -0
  344. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_exceptions.py +0 -0
  345. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_executor.py +0 -0
  346. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_executor_inprocess.py +0 -0
  347. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_format.py +0 -0
  348. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_mail.py +0 -0
  349. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_models.py +0 -0
  350. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_package.py +0 -0
  351. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_parser.py +0 -0
  352. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_parser_params.py +0 -0
  353. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_plugins.py +0 -0
  354. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_registry.py +0 -0
  355. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_script.py +0 -0
  356. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_state.py +0 -0
  357. {execsql2-2.21.1 → execsql2-2.21.2}/tests/test_types.py +0 -0
  358. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/__init__.py +0 -0
  359. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_auth.py +0 -0
  360. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_auth_extra.py +0 -0
  361. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_crypto.py +0 -0
  362. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_datetime.py +0 -0
  363. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_encodedfile_context.py +0 -0
  364. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_errors.py +0 -0
  365. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_errors_extra.py +0 -0
  366. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_fileio.py +0 -0
  367. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_fileio_extra.py +0 -0
  368. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_numeric.py +0 -0
  369. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_regex.py +0 -0
  370. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_strings.py +0 -0
  371. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_timer.py +0 -0
  372. {execsql2-2.21.1 → execsql2-2.21.2}/tests/utils/test_timer_extra.py +0 -0
  373. {execsql2-2.21.1 → execsql2-2.21.2}/zensical.toml +0 -0
@@ -20,8 +20,8 @@ jobs:
20
20
  permissions:
21
21
  contents: read
22
22
  steps:
23
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
24
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
23
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
24
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
25
25
  with:
26
26
  python-version: "3.13"
27
27
  - run: python -m pip install ruff
@@ -48,13 +48,13 @@ jobs:
48
48
  contents: read
49
49
  steps:
50
50
  - name: Check out repository code
51
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
51
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
52
52
  - name: Setup Python ${{ matrix.python-version }}
53
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
53
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
54
54
  with:
55
55
  python-version: ${{ matrix.python-version }}
56
56
  - name: Cache pip dependencies
57
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
57
+ uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
58
58
  with:
59
59
  path: ~/.cache/pip
60
60
  key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{
@@ -139,9 +139,9 @@ jobs:
139
139
  --health-interval 10s --health-timeout 5s --health-retries 20
140
140
  steps:
141
141
  - name: Check out repository code
142
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
142
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
143
143
  - name: Setup Python ${{ matrix.python-version }}
144
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
144
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
145
145
  with:
146
146
  python-version: ${{ matrix.python-version }}
147
147
  - name: Install tkinter (Ubuntu)
@@ -187,8 +187,8 @@ jobs:
187
187
  permissions:
188
188
  contents: read
189
189
  steps:
190
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
191
- - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
190
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
191
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
192
192
  with:
193
193
  python-version: ${{ matrix.python-version }}
194
194
  - name: Install Microsoft Access Database Engine 2016 (x64)
@@ -238,9 +238,9 @@ jobs:
238
238
  permissions:
239
239
  contents: read
240
240
  steps:
241
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
241
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
242
242
  - name: Set up Python
243
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
243
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
244
244
  with:
245
245
  python-version: "3.13"
246
246
  cache: "pip"
@@ -288,14 +288,14 @@ jobs:
288
288
  contents: write
289
289
  steps:
290
290
  - name: Checkout
291
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
291
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
292
292
  - name: Download dist
293
293
  uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
294
294
  with:
295
295
  name: ${{ github.event.repository.name }}
296
296
  path: dist/
297
297
  - name: Create release
298
- uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
298
+ uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
299
299
  with:
300
300
  draft: false
301
301
  prerelease: false
@@ -13,6 +13,14 @@ ______________________________________________________________________
13
13
 
14
14
  ______________________________________________________________________
15
15
 
16
+ ## [2.21.2] - 2026-06-30
17
+
18
+ ### Fixed
19
+
20
+ - Fixed `EXPORT … AS PARQUET` and `EXPORT … AS FEATHER` `ComputeError` when a result column has more than 100 leading `NULL` values followed by non-null numeric values.
21
+
22
+ ______________________________________________________________________
23
+
16
24
  ## [2.21.1] - 2026-06-24
17
25
 
18
26
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: execsql2
3
- Version: 2.21.1
3
+ Version: 2.21.2
4
4
  Summary: Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables.
5
5
  Project-URL: Homepage, https://execsql2.readthedocs.io
6
6
  Project-URL: Repository, https://github.com/geocoug/execsql
@@ -403,7 +403,7 @@ execsql-format --no-sql --in-place scripts/
403
403
  ```yaml
404
404
  repos:
405
405
  - repo: https://github.com/geocoug/execsql
406
- rev: v2.21.1
406
+ rev: v2.21.2
407
407
  hooks:
408
408
  - id: execsql-format
409
409
  ```
@@ -272,7 +272,7 @@ execsql-format --no-sql --in-place scripts/
272
272
  ```yaml
273
273
  repos:
274
274
  - repo: https://github.com/geocoug/execsql
275
- rev: v2.21.1
275
+ rev: v2.21.2
276
276
  hooks:
277
277
  - id: execsql-format
278
278
  ```
@@ -160,7 +160,7 @@ select id,name,created_at from users where active = true order by name;
160
160
  ```yaml
161
161
  repos:
162
162
  - repo: https://github.com/geocoug/execsql
163
- rev: v2.21.1
163
+ rev: v2.21.2
164
164
  hooks:
165
165
  - id: execsql-format
166
166
  ```
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "execsql2"
7
- version = "2.21.1"
7
+ version = "2.21.2"
8
8
  description = "Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables."
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  license = { file = "LICENSE.txt" }
@@ -178,7 +178,7 @@ skip-magic-trailing-comma = false
178
178
  line-ending = "auto"
179
179
 
180
180
  [tool.bumpversion]
181
- current_version = "2.21.1"
181
+ current_version = "2.21.2"
182
182
  commit = true
183
183
  tag = true
184
184
  tag_name = "v{new_version}"
@@ -33,7 +33,7 @@ def write_query_to_feather(outfile: str, headers: list[str], rows: Any) -> None:
33
33
  ) from e
34
34
  rows_list = list(rows)
35
35
  if rows_list:
36
- df = pl.DataFrame(rows_list, schema=headers, orient="row")
36
+ df = pl.DataFrame(rows_list, schema=headers, orient="row", infer_schema_length=None)
37
37
  else:
38
38
  df = pl.DataFrame({h: [] for h in headers})
39
39
  filewriter_close(outfile)
@@ -28,7 +28,7 @@ def write_query_to_parquet(outfile: str, headers: list[str], rows: Any) -> None:
28
28
  ) from e
29
29
  rows_list = list(rows)
30
30
  if rows_list:
31
- df = pl.DataFrame(rows_list, schema=headers, orient="row")
31
+ df = pl.DataFrame(rows_list, schema=headers, orient="row", infer_schema_length=None)
32
32
  else:
33
33
  df = pl.DataFrame({h: [] for h in headers})
34
34
  filewriter_close(outfile)
@@ -93,3 +93,49 @@ class TestPostgresConnectTimeout:
93
93
  # Credential-less path still uses ``dbname``.
94
94
  assert call_kwargs["dbname"] == "testdb"
95
95
  assert "database" not in call_kwargs
96
+
97
+
98
+ # ---------------------------------------------------------------------------
99
+ # Regression: psycopg3 auto-prepared statements must stay disabled
100
+ #
101
+ # psycopg3 promotes a query to a server-side prepared statement after the same
102
+ # query text runs ``prepare_threshold`` times (default 5). Scripts that re-run
103
+ # a query (e.g. via EXPORT) against an object they drop/recreate or alter then
104
+ # hit "cached plan must not change result type". psycopg2 never auto-prepared,
105
+ # so the adapter passes ``prepare_threshold=None`` to restore that behavior.
106
+ # ---------------------------------------------------------------------------
107
+
108
+
109
+ class TestPostgresPrepareThresholdDisabled:
110
+ @patch.dict("sys.modules", {"psycopg": _make_mock_psycopg()})
111
+ def test_prepare_threshold_disabled_with_credentials(self):
112
+ import sys
113
+
114
+ mock_psycopg = sys.modules["psycopg"]
115
+ from execsql.db.postgres import PostgresDatabase
116
+
117
+ PostgresDatabase(
118
+ server_name="localhost",
119
+ db_name="testdb",
120
+ user_name="user",
121
+ password="pass",
122
+ )
123
+ call_kwargs = mock_psycopg.connect.call_args[1]
124
+ assert "prepare_threshold" in call_kwargs
125
+ assert call_kwargs["prepare_threshold"] is None
126
+
127
+ @patch.dict("sys.modules", {"psycopg": _make_mock_psycopg()})
128
+ def test_prepare_threshold_disabled_without_credentials(self):
129
+ import sys
130
+
131
+ mock_psycopg = sys.modules["psycopg"]
132
+ from execsql.db.postgres import PostgresDatabase
133
+
134
+ PostgresDatabase(
135
+ server_name="localhost",
136
+ db_name="testdb",
137
+ user_name=None,
138
+ )
139
+ call_kwargs = mock_psycopg.connect.call_args[1]
140
+ assert "prepare_threshold" in call_kwargs
141
+ assert call_kwargs["prepare_threshold"] is None
@@ -60,3 +60,11 @@ class TestWriteQueryToParquet:
60
60
  assert len(result["id"]) == 100
61
61
  assert result["id"][0] == 0
62
62
  assert result["label"][99] == "item_99"
63
+
64
+ def test_leading_nulls_then_float(self, noop_filewriter_close, tmp_path):
65
+ out = str(tmp_path / "out.parquet")
66
+ rows = [(None,)] * 100 + [(12.5,), (5.2,)]
67
+ write_query_to_parquet(out, ["val"], iter(rows))
68
+ result = pl.read_parquet(out).to_dict(as_series=False)
69
+ assert result["val"][100] == pytest.approx(12.5)
70
+ assert result["val"][101] == pytest.approx(5.2)
@@ -412,3 +412,54 @@ class TestExportJSON:
412
412
  assert data[1]["label"] == "beta"
413
413
 
414
414
  _exec_pg("DROP TABLE IF EXISTS items")
415
+
416
+
417
+ # ---------------------------------------------------------------------------
418
+ # Regression: psycopg3 cached-plan / auto-prepared statements
419
+ #
420
+ # psycopg3 promotes a query to a server-side prepared statement after the same
421
+ # query text runs prepare_threshold times (default 5). Re-EXPORTing a view that
422
+ # the script drops/recreates with a different result type used to raise
423
+ # "FeatureNotSupported: cached plan must not change result type". The adapter
424
+ # now connects with prepare_threshold=None; this exercises the full pipeline to
425
+ # prove the fix end-to-end. See CHANGELOG 2.21.1.
426
+ # ---------------------------------------------------------------------------
427
+
428
+
429
+ class TestCachedPlanRegression:
430
+ def test_repeated_export_after_view_result_type_change(self, tmp_path):
431
+ """EXPORT the same view past the prepare threshold, then recreate it with
432
+ a different column type and EXPORT again — must not error."""
433
+ _exec_pg("DROP VIEW IF EXISTS val_summ")
434
+ _exec_pg("DROP TABLE IF EXISTS val_src")
435
+ _write_conf(tmp_path)
436
+ out = tmp_path / "summ.txt"
437
+
438
+ # Six exports of identical query text cross psycopg3's default
439
+ # prepare_threshold (5); the view is then recreated returning a TEXT
440
+ # column instead of an INTEGER one and exported again.
441
+ first_exports = "\n".join(f"-- !x! EXPORT val_summ TO {out} AS TXT" for _ in range(6))
442
+ second_exports = "\n".join(f"-- !x! EXPORT val_summ TO {out} AS TXT" for _ in range(6))
443
+ script = write_script(
444
+ tmp_path,
445
+ f"""\
446
+ CREATE TABLE val_src (id INTEGER, name TEXT);
447
+ INSERT INTO val_src VALUES (1, 'alpha');
448
+
449
+ CREATE VIEW val_summ AS SELECT id AS c FROM val_src;
450
+ {first_exports}
451
+
452
+ DROP VIEW val_summ;
453
+ CREATE VIEW val_summ AS SELECT name AS c FROM val_src;
454
+ {second_exports}
455
+ """,
456
+ )
457
+
458
+ result = _run_execsql_pg(tmp_path, script)
459
+ assert result.returncode == 0, f"stderr: {result.stderr}"
460
+ assert "cached plan must not change result type" not in result.stderr
461
+ # The final export reflects the recreated (TEXT) view.
462
+ assert "alpha" in out.read_text()
463
+
464
+ _exec_pg("DROP VIEW IF EXISTS val_summ")
465
+ _exec_pg("DROP TABLE IF EXISTS val_src")
@@ -722,7 +722,7 @@ wheels = [
722
722
 
723
723
  [[package]]
724
724
  name = "execsql2"
725
- version = "2.21.1"
725
+ version = "2.21.2"
726
726
  source = { editable = "." }
727
727
  dependencies = [
728
728
  { name = "python-dateutil" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes