execsql2 2.23.0__tar.gz → 2.24.0__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 (439) hide show
  1. {execsql2-2.23.0 → execsql2-2.24.0}/.github/workflows/ci-cd.yml +107 -2
  2. execsql2-2.24.0/.pre-commit-hooks.yaml +17 -0
  3. {execsql2-2.23.0 → execsql2-2.24.0}/CHANGELOG.md +61 -0
  4. {execsql2-2.23.0 → execsql2-2.24.0}/PKG-INFO +111 -58
  5. {execsql2-2.23.0 → execsql2-2.24.0}/README.md +107 -54
  6. {execsql2-2.23.0 → execsql2-2.24.0}/docs/about/divergence.md +74 -36
  7. {execsql2-2.23.0 → execsql2-2.24.0}/docs/dev/adding_db_adapters.md +2 -2
  8. {execsql2-2.23.0 → execsql2-2.24.0}/docs/dev/adding_metacommands.md +9 -9
  9. {execsql2-2.23.0 → execsql2-2.24.0}/docs/dev/architecture.md +28 -25
  10. {execsql2-2.23.0 → execsql2-2.24.0}/docs/getting-started/installation.md +2 -2
  11. {execsql2-2.23.0 → execsql2-2.24.0}/docs/getting-started/requirements.md +3 -3
  12. execsql2-2.24.0/docs/getting-started/syntax.md +513 -0
  13. execsql2-2.24.0/docs/guides/debugging.md +121 -0
  14. {execsql2-2.23.0 → execsql2-2.24.0}/docs/guides/examples.md +20 -16
  15. {execsql2-2.23.0 → execsql2-2.24.0}/docs/guides/formatter.md +70 -24
  16. {execsql2-2.23.0 → execsql2-2.24.0}/docs/guides/usage.md +1 -1
  17. {execsql2-2.23.0 → execsql2-2.24.0}/docs/reference/configuration.md +48 -1
  18. execsql2-2.24.0/docs/reference/lint.md +266 -0
  19. {execsql2-2.23.0 → execsql2-2.24.0}/docs/reference/metacommands.md +57 -10
  20. {execsql2-2.23.0 → execsql2-2.24.0}/docs/reference/security.md +1 -1
  21. {execsql2-2.23.0 → execsql2-2.24.0}/docs/reference/substitution_vars.md +3 -1
  22. {execsql2-2.23.0 → execsql2-2.24.0}/extras/plugin-template/README.md +2 -2
  23. {execsql2-2.23.0 → execsql2-2.24.0}/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +2 -2
  24. {execsql2-2.23.0 → execsql2-2.24.0}/extras/plugin-template/tests/test_plugin.py.example +3 -2
  25. execsql2-2.24.0/extras/vscode-execsql/.vscodeignore +3 -0
  26. execsql2-2.24.0/extras/vscode-execsql/LICENSE.txt +12 -0
  27. execsql2-2.24.0/extras/vscode-execsql/icon.png +0 -0
  28. execsql2-2.24.0/extras/vscode-execsql/package.json +46 -0
  29. {execsql2-2.23.0 → execsql2-2.24.0}/justfile +29 -0
  30. {execsql2-2.23.0 → execsql2-2.24.0}/pyproject.toml +17 -7
  31. {execsql2-2.23.0 → execsql2-2.24.0}/scripts/benchmarks/run_benchmarks.py +1 -1
  32. {execsql2-2.23.0 → execsql2-2.24.0}/scripts/generate_vscode_grammar.py +6 -6
  33. execsql2-2.24.0/src/execsql/cli/__init__.py +81 -0
  34. execsql2-2.24.0/src/execsql/cli/application.py +309 -0
  35. execsql2-2.24.0/src/execsql/cli/commands/__init__.py +13 -0
  36. execsql2-2.24.0/src/execsql/cli/commands/config.py +205 -0
  37. execsql2-2.24.0/src/execsql/cli/commands/format.py +100 -0
  38. execsql2-2.24.0/src/execsql/cli/commands/init.py +135 -0
  39. execsql2-2.24.0/src/execsql/cli/commands/lint.py +233 -0
  40. execsql2-2.24.0/src/execsql/cli/commands/listing.py +81 -0
  41. execsql2-2.24.0/src/execsql/cli/commands/run.py +451 -0
  42. execsql2-2.24.0/src/execsql/cli/dispatch.py +66 -0
  43. execsql2-2.24.0/src/execsql/cli/help.py +302 -0
  44. execsql2-2.24.0/src/execsql/cli/lint.py +943 -0
  45. execsql2-2.24.0/src/execsql/cli/options.py +108 -0
  46. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/cli/run.py +41 -14
  47. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/config.py +251 -154
  48. execsql2-2.24.0/src/execsql/config_validation.py +282 -0
  49. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/data/execsql.conf.template +24 -1
  50. execsql2-2.24.0/src/execsql/data/script_header.sql +23 -0
  51. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/access.py +22 -6
  52. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/base.py +105 -1
  53. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/dsn.py +2 -0
  54. execsql2-2.24.0/src/execsql/db/duckdb.py +182 -0
  55. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/factory.py +2 -2
  56. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/mysql.py +11 -0
  57. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/oracle.py +12 -4
  58. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/sqlite.py +16 -0
  59. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/debug/repl.py +51 -193
  60. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exceptions.py +9 -0
  61. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/format.py +87 -75
  62. execsql2-2.24.0/src/execsql/interactive.py +232 -0
  63. execsql2-2.24.0/src/execsql/manifest.py +189 -0
  64. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/conditions.py +1 -1
  65. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/control.py +2 -3
  66. execsql2-2.24.0/src/execsql/metacommands/effects.py +124 -0
  67. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/script/__init__.py +0 -9
  68. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/script/ast.py +1 -1
  69. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/script/engine.py +6 -93
  70. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/script/executor.py +153 -34
  71. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/state.py +11 -2
  72. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/state.pyi +3 -0
  73. execsql2-2.24.0/src/execsql/utils/color.py +18 -0
  74. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/errors.py +11 -1
  75. {execsql2-2.23.0 → execsql2-2.24.0}/templates/README.md +1 -1
  76. {execsql2-2.23.0 → execsql2-2.24.0}/tests/cli/test_cli.py +28 -21
  77. {execsql2-2.23.0 → execsql2-2.24.0}/tests/cli/test_cli_e2e.py +8 -3
  78. execsql2-2.24.0/tests/cli/test_cli_surface.py +232 -0
  79. execsql2-2.24.0/tests/cli/test_commands.py +577 -0
  80. execsql2-2.24.0/tests/cli/test_config_validate.py +294 -0
  81. execsql2-2.24.0/tests/cli/test_dispatch.py +456 -0
  82. execsql2-2.24.0/tests/cli/test_init.py +119 -0
  83. execsql2-2.24.0/tests/cli/test_lint.py +923 -0
  84. execsql2-2.24.0/tests/cli/test_manifest.py +172 -0
  85. {execsql2-2.23.0 → execsql2-2.24.0}/tests/cli/test_ping.py +3 -3
  86. {execsql2-2.23.0 → execsql2-2.24.0}/tests/cli/test_profile.py +6 -4
  87. execsql2-2.24.0/tests/cli/test_undeclared_imports.py +45 -0
  88. {execsql2-2.23.0 → execsql2-2.24.0}/tests/conftest.py +50 -0
  89. execsql2-2.24.0/tests/data/formatter_shapes/escapes_and_literals.sql +58 -0
  90. execsql2-2.24.0/tests/data/formatter_shapes/substitution_and_metacommands.sql +43 -0
  91. execsql2-2.24.0/tests/data/formatter_shapes/unparsable_sql.sql +41 -0
  92. execsql2-2.24.0/tests/db/test_transactions.py +372 -0
  93. {execsql2-2.23.0 → execsql2-2.24.0}/tests/integration/test_postgres.py +91 -0
  94. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_breakpoint.py +1 -101
  95. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/test_sql_scripts.py +2 -2
  96. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_bundled_templates.py +3 -3
  97. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_debug_repl.py +2 -171
  98. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_engine.py +10 -81
  99. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_error_messages.py +3 -3
  100. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_executor_inprocess.py +52 -18
  101. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_format.py +37 -15
  102. execsql2-2.24.0/tests/test_interactive.py +260 -0
  103. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_registry.py +6 -6
  104. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_script.py +0 -49
  105. {execsql2-2.23.0 → execsql2-2.24.0}/uv.lock +30 -21
  106. {execsql2-2.23.0 → execsql2-2.24.0}/zensical.toml +2 -1
  107. execsql2-2.23.0/.pre-commit-hooks.yaml +0 -9
  108. execsql2-2.23.0/docs/getting-started/syntax.md +0 -270
  109. execsql2-2.23.0/docs/guides/debugging.md +0 -110
  110. execsql2-2.23.0/extras/vscode-execsql/package.json +0 -24
  111. execsql2-2.23.0/src/execsql/cli/__init__.py +0 -650
  112. execsql2-2.23.0/src/execsql/cli/help.py +0 -151
  113. execsql2-2.23.0/src/execsql/cli/lint.py +0 -506
  114. execsql2-2.23.0/src/execsql/db/duckdb.py +0 -89
  115. execsql2-2.23.0/tests/cli/test_lint.py +0 -329
  116. {execsql2-2.23.0 → execsql2-2.24.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  117. {execsql2-2.23.0 → execsql2-2.24.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  118. {execsql2-2.23.0 → execsql2-2.24.0}/.github/dependabot.yml +0 -0
  119. {execsql2-2.23.0 → execsql2-2.24.0}/.gitignore +0 -0
  120. {execsql2-2.23.0 → execsql2-2.24.0}/.pre-commit-config.yaml +0 -0
  121. {execsql2-2.23.0 → execsql2-2.24.0}/.python-version +0 -0
  122. {execsql2-2.23.0 → execsql2-2.24.0}/.readthedocs.yaml +0 -0
  123. {execsql2-2.23.0 → execsql2-2.24.0}/CONTRIBUTING.md +0 -0
  124. {execsql2-2.23.0 → execsql2-2.24.0}/LICENSE.txt +0 -0
  125. {execsql2-2.23.0 → execsql2-2.24.0}/NOTICE +0 -0
  126. {execsql2-2.23.0 → execsql2-2.24.0}/SECURITY.md +0 -0
  127. {execsql2-2.23.0 → execsql2-2.24.0}/docs/about/contributors.md +0 -0
  128. {execsql2-2.23.0 → execsql2-2.24.0}/docs/about/copyright.md +0 -0
  129. {execsql2-2.23.0 → execsql2-2.24.0}/docs/api/cli.md +0 -0
  130. {execsql2-2.23.0 → execsql2-2.24.0}/docs/api/db.md +0 -0
  131. {execsql2-2.23.0 → execsql2-2.24.0}/docs/api/exporters.md +0 -0
  132. {execsql2-2.23.0 → execsql2-2.24.0}/docs/api/importers.md +0 -0
  133. {execsql2-2.23.0 → execsql2-2.24.0}/docs/api/index.md +0 -0
  134. {execsql2-2.23.0 → execsql2-2.24.0}/docs/api/metacommands.md +0 -0
  135. {execsql2-2.23.0 → execsql2-2.24.0}/docs/dev/adding_exporters.md +0 -0
  136. {execsql2-2.23.0 → execsql2-2.24.0}/docs/dev/adding_importers.md +0 -0
  137. {execsql2-2.23.0 → execsql2-2.24.0}/docs/dev/releasing.md +0 -0
  138. {execsql2-2.23.0 → execsql2-2.24.0}/docs/guides/documentation.md +0 -0
  139. {execsql2-2.23.0 → execsql2-2.24.0}/docs/guides/encoding.md +0 -0
  140. {execsql2-2.23.0 → execsql2-2.24.0}/docs/guides/logging.md +0 -0
  141. {execsql2-2.23.0 → execsql2-2.24.0}/docs/guides/sql_syntax.md +0 -0
  142. {execsql2-2.23.0 → execsql2-2.24.0}/docs/guides/using_scripts.md +0 -0
  143. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/Compare_planets.png +0 -0
  144. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/actions.png +0 -0
  145. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/actions2.png +0 -0
  146. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/checkboxes.png +0 -0
  147. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/connect.b64 +0 -0
  148. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/connect.png +0 -0
  149. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/create_conf.png +0 -0
  150. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/data_error1_screenshot.jpg +0 -0
  151. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/entry_form.png +0 -0
  152. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/execsql_console.png +0 -0
  153. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/execsql_logo_01.png +0 -0
  154. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/fatals.png +0 -0
  155. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/logo_small.png +0 -0
  156. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/pause_terminal.png +0 -0
  157. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/pause_terminal_sm.b64 +0 -0
  158. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/pause_terminal_sm.png +0 -0
  159. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/prompt_compare.png +0 -0
  160. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/set_build_commands.jpg +0 -0
  161. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/unit_conversions.b64 +0 -0
  162. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/unit_conversions_029.png +0 -0
  163. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/unmatched.png +0 -0
  164. {execsql2-2.23.0 → execsql2-2.24.0}/docs/images/vim_execsql_highlight.png +0 -0
  165. {execsql2-2.23.0 → execsql2-2.24.0}/docs/index.md +0 -0
  166. {execsql2-2.23.0 → execsql2-2.24.0}/extras/plugin-template/pyproject.toml +0 -0
  167. {execsql2-2.23.0 → execsql2-2.24.0}/extras/vscode-execsql/README.md +0 -0
  168. {execsql2-2.23.0 → execsql2-2.24.0}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
  169. {execsql2-2.23.0 → execsql2-2.24.0}/scripts/benchmarks/README.md +0 -0
  170. {execsql2-2.23.0 → execsql2-2.24.0}/scripts/benchmarks/results/.gitignore +0 -0
  171. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/__init__.py +0 -0
  172. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/__main__.py +0 -0
  173. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/api.py +0 -0
  174. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/cli/dsn.py +0 -0
  175. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/data/__init__.py +0 -0
  176. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/__init__.py +0 -0
  177. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/firebird.py +0 -0
  178. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/postgres.py +0 -0
  179. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/sqlserver.py +0 -0
  180. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/db/tiers.py +0 -0
  181. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/debug/__init__.py +0 -0
  182. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/__init__.py +0 -0
  183. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/base.py +0 -0
  184. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/delimited.py +0 -0
  185. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/duckdb.py +0 -0
  186. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/feather.py +0 -0
  187. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/html.py +0 -0
  188. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/json.py +0 -0
  189. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/latex.py +0 -0
  190. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/markdown.py +0 -0
  191. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/ods.py +0 -0
  192. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/parquet.py +0 -0
  193. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/pretty.py +0 -0
  194. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/protocol.py +0 -0
  195. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/raw.py +0 -0
  196. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/sqlite.py +0 -0
  197. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/templates.py +0 -0
  198. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/values.py +0 -0
  199. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/xls.py +0 -0
  200. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/xlsx.py +0 -0
  201. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/xml.py +0 -0
  202. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/yaml.py +0 -0
  203. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/exporters/zip.py +0 -0
  204. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/gui/__init__.py +0 -0
  205. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/gui/base.py +0 -0
  206. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/gui/console.py +0 -0
  207. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/gui/desktop.py +0 -0
  208. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/gui/tui.py +0 -0
  209. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/importers/__init__.py +0 -0
  210. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/importers/base.py +0 -0
  211. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/importers/csv.py +0 -0
  212. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/importers/feather.py +0 -0
  213. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/importers/json.py +0 -0
  214. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/importers/ods.py +0 -0
  215. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/importers/xls.py +0 -0
  216. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/__init__.py +0 -0
  217. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/connect.py +0 -0
  218. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/data.py +0 -0
  219. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/debug.py +0 -0
  220. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/dispatch.py +0 -0
  221. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/io.py +0 -0
  222. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/io_export.py +0 -0
  223. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/io_fileops.py +0 -0
  224. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/io_import.py +0 -0
  225. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/io_write.py +0 -0
  226. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/prompt.py +0 -0
  227. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/script_ext.py +0 -0
  228. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/system.py +0 -0
  229. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/metacommands/upsert.py +0 -0
  230. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/models.py +0 -0
  231. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/parser.py +0 -0
  232. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/plugins.py +0 -0
  233. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/py.typed +0 -0
  234. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/script/control.py +0 -0
  235. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/script/parser.py +0 -0
  236. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/script/variables.py +0 -0
  237. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/types.py +0 -0
  238. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/__init__.py +0 -0
  239. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/auth.py +0 -0
  240. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/crypto.py +0 -0
  241. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/datetime.py +0 -0
  242. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/fileio.py +0 -0
  243. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/gui.py +0 -0
  244. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/mail.py +0 -0
  245. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/numeric.py +0 -0
  246. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/regex.py +0 -0
  247. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/strings.py +0 -0
  248. {execsql2-2.23.0 → execsql2-2.24.0}/src/execsql/utils/timer.py +0 -0
  249. {execsql2-2.23.0 → execsql2-2.24.0}/templates/config_settings.sqlite +0 -0
  250. {execsql2-2.23.0 → execsql2-2.24.0}/templates/example_config_prompt.sql +0 -0
  251. {execsql2-2.23.0 → execsql2-2.24.0}/templates/make_config_db.sql +0 -0
  252. {execsql2-2.23.0 → execsql2-2.24.0}/templates/md_compare.sql +0 -0
  253. {execsql2-2.23.0 → execsql2-2.24.0}/templates/md_glossary.sql +0 -0
  254. {execsql2-2.23.0 → execsql2-2.24.0}/templates/md_upsert.sql +0 -0
  255. {execsql2-2.23.0 → execsql2-2.24.0}/templates/pg_compare.sql +0 -0
  256. {execsql2-2.23.0 → execsql2-2.24.0}/templates/pg_glossary.sql +0 -0
  257. {execsql2-2.23.0 → execsql2-2.24.0}/templates/pg_upsert.sql +0 -0
  258. {execsql2-2.23.0 → execsql2-2.24.0}/templates/script_template.sql +0 -0
  259. {execsql2-2.23.0 → execsql2-2.24.0}/templates/ss_compare.sql +0 -0
  260. {execsql2-2.23.0 → execsql2-2.24.0}/templates/ss_glossary.sql +0 -0
  261. {execsql2-2.23.0 → execsql2-2.24.0}/templates/ss_upsert.sql +0 -0
  262. {execsql2-2.23.0 → execsql2-2.24.0}/tests/__init__.py +0 -0
  263. {execsql2-2.23.0 → execsql2-2.24.0}/tests/cli/__init__.py +0 -0
  264. {execsql2-2.23.0 → execsql2-2.24.0}/tests/cli/test_cli_run.py +0 -0
  265. {execsql2-2.23.0 → execsql2-2.24.0}/tests/data/formatter_shapes/comment_anchoring.sql +0 -0
  266. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/__init__.py +0 -0
  267. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_access_windows.py +0 -0
  268. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_base.py +0 -0
  269. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_db_adapters_mocked.py +0 -0
  270. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_db_adapters_mocked_extra.py +0 -0
  271. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_dsn.py +0 -0
  272. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_duckdb.py +0 -0
  273. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_factory.py +0 -0
  274. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_mysql_case_folding.py +0 -0
  275. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_mysql_inprocess.py +0 -0
  276. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_postgres.py +0 -0
  277. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_postgres_inprocess.py +0 -0
  278. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_roundtrip_adapters.py +0 -0
  279. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_sqlite.py +0 -0
  280. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_sqlite_extra.py +0 -0
  281. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_sqlserver_inprocess.py +0 -0
  282. {execsql2-2.23.0 → execsql2-2.24.0}/tests/db/test_tiers.py +0 -0
  283. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/__init__.py +0 -0
  284. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/conftest.py +0 -0
  285. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_base.py +0 -0
  286. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_db.py +0 -0
  287. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_delimited.py +0 -0
  288. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_duckdb_exporter.py +0 -0
  289. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_exporters.py +0 -0
  290. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_feather.py +0 -0
  291. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_html_extended.py +0 -0
  292. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_html_latex.py +0 -0
  293. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_json.py +0 -0
  294. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_json_extended.py +0 -0
  295. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_latex_extended.py +0 -0
  296. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_markdown.py +0 -0
  297. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_ods.py +0 -0
  298. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_ods_export.py +0 -0
  299. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_parquet.py +0 -0
  300. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_pretty_extended.py +0 -0
  301. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_raw_extended.py +0 -0
  302. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_roundtrip_columnar.py +0 -0
  303. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_roundtrip_dbfile.py +0 -0
  304. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_roundtrip_delimited.py +0 -0
  305. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_roundtrip_json.py +0 -0
  306. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_roundtrip_latex_xml.py +0 -0
  307. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_roundtrip_markup.py +0 -0
  308. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_roundtrip_ods.py +0 -0
  309. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_roundtrip_pretty_raw.py +0 -0
  310. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_roundtrip_template.py +0 -0
  311. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_roundtrip_values.py +0 -0
  312. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_roundtrip_xlsx.py +0 -0
  313. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_sqlite_exporter.py +0 -0
  314. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_templates.py +0 -0
  315. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_templates_extended.py +0 -0
  316. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_values_extended.py +0 -0
  317. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_xls_xlsx.py +0 -0
  318. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_xlsx.py +0 -0
  319. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_xml.py +0 -0
  320. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_yaml.py +0 -0
  321. {execsql2-2.23.0 → execsql2-2.24.0}/tests/exporters/test_zip.py +0 -0
  322. {execsql2-2.23.0 → execsql2-2.24.0}/tests/gui/__init__.py +0 -0
  323. {execsql2-2.23.0 → execsql2-2.24.0}/tests/gui/test_backends.py +0 -0
  324. {execsql2-2.23.0 → execsql2-2.24.0}/tests/gui/test_backends_extended.py +0 -0
  325. {execsql2-2.23.0 → execsql2-2.24.0}/tests/gui/test_compare_stats.py +0 -0
  326. {execsql2-2.23.0 → execsql2-2.24.0}/tests/gui/test_compute_row_diffs.py +0 -0
  327. {execsql2-2.23.0 → execsql2-2.24.0}/tests/gui/test_desktop_dialogs.py +0 -0
  328. {execsql2-2.23.0 → execsql2-2.24.0}/tests/gui/test_format_table.py +0 -0
  329. {execsql2-2.23.0 → execsql2-2.24.0}/tests/gui/test_tui_pilot.py +0 -0
  330. {execsql2-2.23.0 → execsql2-2.24.0}/tests/gui/test_tui_pilot_complex.py +0 -0
  331. {execsql2-2.23.0 → execsql2-2.24.0}/tests/gui/test_utils_gui_extended.py +0 -0
  332. {execsql2-2.23.0 → execsql2-2.24.0}/tests/importers/__init__.py +0 -0
  333. {execsql2-2.23.0 → execsql2-2.24.0}/tests/importers/conftest.py +0 -0
  334. {execsql2-2.23.0 → execsql2-2.24.0}/tests/importers/test_base_extended.py +0 -0
  335. {execsql2-2.23.0 → execsql2-2.24.0}/tests/importers/test_csv_edge_cases.py +0 -0
  336. {execsql2-2.23.0 → execsql2-2.24.0}/tests/importers/test_csv_importer.py +0 -0
  337. {execsql2-2.23.0 → execsql2-2.24.0}/tests/importers/test_feather_importer.py +0 -0
  338. {execsql2-2.23.0 → execsql2-2.24.0}/tests/importers/test_json_importer.py +0 -0
  339. {execsql2-2.23.0 → execsql2-2.24.0}/tests/importers/test_ods_importer.py +0 -0
  340. {execsql2-2.23.0 → execsql2-2.24.0}/tests/importers/test_roundtrip_csv.py +0 -0
  341. {execsql2-2.23.0 → execsql2-2.24.0}/tests/importers/test_xls_importer.py +0 -0
  342. {execsql2-2.23.0 → execsql2-2.24.0}/tests/integration/__init__.py +0 -0
  343. {execsql2-2.23.0 → execsql2-2.24.0}/tests/integration/conftest.py +0 -0
  344. {execsql2-2.23.0 → execsql2-2.24.0}/tests/integration/test_dsn.py +0 -0
  345. {execsql2-2.23.0 → execsql2-2.24.0}/tests/integration/test_duckdb.py +0 -0
  346. {execsql2-2.23.0 → execsql2-2.24.0}/tests/integration/test_mysql.py +0 -0
  347. {execsql2-2.23.0 → execsql2-2.24.0}/tests/integration/test_sqlite.py +0 -0
  348. {execsql2-2.23.0 → execsql2-2.24.0}/tests/live_db.py +0 -0
  349. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/__init__.py +0 -0
  350. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_assert.py +0 -0
  351. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_conditions_extra.py +0 -0
  352. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_connect.py +0 -0
  353. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_io_export.py +0 -0
  354. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_io_import.py +0 -0
  355. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_metacommands.py +0 -0
  356. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_metacommands_connect.py +0 -0
  357. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_metacommands_data.py +0 -0
  358. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_metacommands_extended.py +0 -0
  359. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
  360. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_metacommands_io.py +0 -0
  361. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
  362. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_metacommands_script_ext.py +0 -0
  363. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_metacommands_system.py +0 -0
  364. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_metacommands_system_extra.py +0 -0
  365. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_pg_upsert.py +0 -0
  366. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_prompt.py +0 -0
  367. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_row_count.py +0 -0
  368. {execsql2-2.23.0 → execsql2-2.24.0}/tests/metacommands/test_show_scripts.py +0 -0
  369. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/__init__.py +0 -0
  370. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/audit_lint_bad.sql +0 -0
  371. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/audit_smoke/sample.json +0 -0
  372. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/audit_smoke/sample.jsonl +0 -0
  373. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/audit_smoke.sql +0 -0
  374. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/config_runtime.sql +0 -0
  375. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/control_flow.sql +0 -0
  376. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/counters_and_locals.sql +0 -0
  377. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/error_handling.sql +0 -0
  378. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/import_options/has_comments.csv +0 -0
  379. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/import_options.sql +0 -0
  380. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/includes/helper.sql +0 -0
  381. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/includes.sql +0 -0
  382. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/io_formats.sql +0 -0
  383. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
  384. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/multi_db.sql +0 -0
  385. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/parquet_feather_roundtrip.sql +0 -0
  386. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/parse_only/parse_tree.sql +0 -0
  387. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/predicates.sql +0 -0
  388. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/scripts.sql +0 -0
  389. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/smoke.sql +0 -0
  390. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/subroutine_loops.sql +0 -0
  391. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/subvars_advanced.sql +0 -0
  392. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/template_export/greeting.tmpl +0 -0
  393. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/template_export.sql +0 -0
  394. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/timer.sql +0 -0
  395. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/transactions.sql +0 -0
  396. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/write_create_table.sql +0 -0
  397. {execsql2-2.23.0 → execsql2-2.24.0}/tests/scripts/fixtures/xlsx_ods_roundtrip.sql +0 -0
  398. {execsql2-2.23.0 → execsql2-2.24.0}/tests/security/__init__.py +0 -0
  399. {execsql2-2.23.0 → execsql2-2.24.0}/tests/security/test_env_detection.py +0 -0
  400. {execsql2-2.23.0 → execsql2-2.24.0}/tests/security/test_expansion_bomb.py +0 -0
  401. {execsql2-2.23.0 → execsql2-2.24.0}/tests/security/test_import_regex_hardening.py +0 -0
  402. {execsql2-2.23.0 → execsql2-2.24.0}/tests/security/test_log_redaction.py +0 -0
  403. {execsql2-2.23.0 → execsql2-2.24.0}/tests/security/test_odbc_injection.py +0 -0
  404. {execsql2-2.23.0 → execsql2-2.24.0}/tests/security/test_path_containment.py +0 -0
  405. {execsql2-2.23.0 → execsql2-2.24.0}/tests/security/test_substitution_injection.py +0 -0
  406. {execsql2-2.23.0 → execsql2-2.24.0}/tests/security/test_zip_bomb.py +0 -0
  407. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_api.py +0 -0
  408. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_api_extended.py +0 -0
  409. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_api_filewriter.py +0 -0
  410. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_ast.py +0 -0
  411. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_ast_parser.py +0 -0
  412. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_config.py +0 -0
  413. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_config_data.py +0 -0
  414. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_config_extended.py +0 -0
  415. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_exceptions.py +0 -0
  416. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_executor.py +0 -0
  417. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_mail.py +0 -0
  418. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_models.py +0 -0
  419. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_package.py +0 -0
  420. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_parser.py +0 -0
  421. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_parser_params.py +0 -0
  422. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_plugins.py +0 -0
  423. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_state.py +0 -0
  424. {execsql2-2.23.0 → execsql2-2.24.0}/tests/test_types.py +0 -0
  425. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/__init__.py +0 -0
  426. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_auth.py +0 -0
  427. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_auth_extra.py +0 -0
  428. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_crypto.py +0 -0
  429. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_datetime.py +0 -0
  430. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_encodedfile_context.py +0 -0
  431. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_errors.py +0 -0
  432. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_errors_extra.py +0 -0
  433. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_fileio.py +0 -0
  434. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_fileio_extra.py +0 -0
  435. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_numeric.py +0 -0
  436. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_regex.py +0 -0
  437. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_strings.py +0 -0
  438. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_timer.py +0 -0
  439. {execsql2-2.23.0 → execsql2-2.24.0}/tests/utils/test_timer_extra.py +0 -0
@@ -43,6 +43,47 @@ jobs:
43
43
  - run: python -m pip install ".[dev]"
44
44
  - run: mypy src/execsql/
45
45
 
46
+ formatter-corpus:
47
+ name: formatter-corpus
48
+ runs-on: ubuntu-latest
49
+ permissions:
50
+ contents: read
51
+ steps:
52
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
53
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
54
+ with:
55
+ python-version: "3.13"
56
+ cache: "pip"
57
+ - run: python -m pip install --upgrade pip
58
+ - run: python -m pip install ".[dev]"
59
+ # Every formatter bug to date came from real SQL containing a
60
+ # construct the project's own scripts lack. This gate runs those
61
+ # checks under their own name so a corpus failure is legible
62
+ # without reading a 6,000-test log.
63
+ - run: pytest tests/test_format.py -k corpus --no-cov -q
64
+
65
+ typer-floor:
66
+ name: typer-floor
67
+ runs-on: ubuntu-latest
68
+ permissions:
69
+ contents: read
70
+ steps:
71
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
72
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
73
+ with:
74
+ python-version: "3.10"
75
+ cache: "pip"
76
+ - run: python -m pip install --upgrade pip
77
+ # Help rendering and flag parsing lean on Typer internals that
78
+ # move between releases, and every other job runs the newest
79
+ # Typer. Install the declared minimum, read from pyproject.toml so
80
+ # the two cannot drift, and run the CLI tests against it.
81
+ - run: |
82
+ floor=$(grep -oP '"typer>=\K[0-9.]+' pyproject.toml)
83
+ echo "Typer floor: $floor"
84
+ python -m pip install ".[dev]" "typer==$floor"
85
+ - run: pytest tests/cli --no-cov -q
86
+
46
87
  pre-commit:
47
88
  name: pre-commit
48
89
  runs-on: ubuntu-latest
@@ -213,7 +254,7 @@ jobs:
213
254
  - name: Install dependencies
214
255
  run: |
215
256
  python -m pip install --upgrade pip
216
- python -m pip install ".[dev,postgres,mysql,mssql]"
257
+ python -m pip install ".[dev,postgres,mysql,mssql,upsert]"
217
258
  - name: Run subprocess integration tests
218
259
  run: |
219
260
  python -m pytest tests/integration/test_postgres.py tests/integration/test_mysql.py -v --override-ini="addopts="
@@ -289,7 +330,7 @@ jobs:
289
330
  build:
290
331
  name: Build distribution 📦
291
332
  runs-on: ubuntu-latest
292
- needs: [ lint, typecheck, pre-commit, docs, tests, integration-tests ]
333
+ needs: [ lint, typecheck, pre-commit, formatter-corpus, typer-floor, docs, tests, integration-tests ]
293
334
  # Deliberately NOT gated on tags: packaging breaks must surface on a PR,
294
335
  # not at release time. Only publish/generate-release below are tag-gated.
295
336
  permissions:
@@ -364,3 +405,67 @@ jobs:
364
405
  generate_release_notes: true
365
406
  files: |
366
407
  dist/*
408
+
409
+ publish-vscode:
410
+ name: Publish VS Code extension 🧩
411
+ needs: [ build ]
412
+ # Only on a version tag, and only when a Marketplace token is configured.
413
+ # Without VSCE_PAT the job is skipped rather than failed, so a release
414
+ # still completes for anyone who has not set the secret up.
415
+ if: startsWith(github.ref, 'refs/tags/v')
416
+ runs-on: ubuntu-latest
417
+ permissions:
418
+ contents: read
419
+ steps:
420
+ - name: Checkout
421
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
422
+ - name: Check for a Marketplace token
423
+ id: gate
424
+ # Read through env, never interpolated into the command line.
425
+ env:
426
+ VSCE_PAT: ${{ secrets.VSCE_PAT }}
427
+ run: |
428
+ if [ -n "$VSCE_PAT" ]; then
429
+ echo "ready=true" >> "$GITHUB_OUTPUT"
430
+ else
431
+ echo "ready=false" >> "$GITHUB_OUTPUT"
432
+ echo "VSCE_PAT is not set — skipping the Marketplace publish." >> "$GITHUB_STEP_SUMMARY"
433
+ fi
434
+ - name: Setup Python
435
+ if: steps.gate.outputs.ready == 'true'
436
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
437
+ with:
438
+ python-version: "3.13"
439
+ # The grammar is generated from the metacommand dispatch table, so it
440
+ # is rebuilt here rather than trusted to be current in the tree.
441
+ - name: Regenerate the TextMate grammar
442
+ if: steps.gate.outputs.ready == 'true'
443
+ run: |
444
+ python -m pip install --upgrade pip
445
+ python -m pip install .
446
+ python scripts/generate_vscode_grammar.py
447
+ - name: Fail if the committed grammar is stale
448
+ if: steps.gate.outputs.ready == 'true'
449
+ run: git diff --exit-code -- extras/vscode-execsql/syntaxes/
450
+ # The Marketplace refuses a version it already has, so the
451
+ # extension version tracks the tag rather than being bumped by hand
452
+ # in a second place.
453
+ - name: Set the extension version from the tag
454
+ if: steps.gate.outputs.ready == 'true'
455
+ working-directory: extras/vscode-execsql
456
+ run: |
457
+ version="${GITHUB_REF_NAME#v}"
458
+ python - "$version" <<'PY'
459
+ import json, pathlib, sys
460
+ p = pathlib.Path("package.json")
461
+ data = json.loads(p.read_text())
462
+ data["version"] = sys.argv[1]
463
+ p.write_text(json.dumps(data, indent=2) + "\n")
464
+ print("extension version set to", sys.argv[1])
465
+ PY
466
+ - name: Publish
467
+ if: steps.gate.outputs.ready == 'true'
468
+ working-directory: extras/vscode-execsql
469
+ run: npx --yes @vscode/vsce@latest publish
470
+ env:
471
+ VSCE_PAT: ${{ secrets.VSCE_PAT }}
@@ -0,0 +1,17 @@
1
+ - id: execsql-format
2
+ name: execsql-format
3
+ description: Format execsql SQL scripts — normalize metacommand indentation and uppercase keywords.
4
+ entry: execsql format
5
+ language: python
6
+ types: [file]
7
+ files: \.sql$
8
+ args: [--in-place]
9
+ additional_dependencies: ["sqlglot>=25.0,<31"]
10
+
11
+ - id: execsql-lint
12
+ name: execsql-lint
13
+ description: Statically check execsql SQL scripts without a database — unclosed blocks, undefined or unused variables, missing INCLUDE targets, unreachable code.
14
+ entry: execsql lint
15
+ language: python
16
+ types: [file]
17
+ files: \.sql$
@@ -13,6 +13,67 @@ ______________________________________________________________________
13
13
 
14
14
  ______________________________________________________________________
15
15
 
16
+ ## [2.24.0] - 2026-10-01
17
+
18
+ ### Added
19
+
20
+ - **Commands:** `execsql run`, `format`, `lint`, `config`, `list` and `init`. `format` and `lint` take files or directories and need no database, so a whole script library can be linted at once. See [Commands](https://execsql2.readthedocs.io/en/latest/getting-started/syntax/#commands).
21
+ - **`run`:** `--manifest FILE` writes a JSON record of the run (files read and written, connections, statement counts and any error), even when the run fails. `--var NAME=VALUE` sets `!!NAME!!` from the command line.
22
+ - **`lint`:** every issue has a rule code (`V001`, `F002`, …) that `--select` and `--ignore` filter on. `--output-format json|concise|github`, `--statistics`, and `--strict` to fail on warnings. New checks for a `SUB` variable nothing reads, an `IF` whose condition never changes, and statements after `HALT`. See the [lint rules reference](https://execsql2.readthedocs.io/en/latest/reference/lint/).
23
+ - **`execsql-lint` pre-commit hook**, alongside `execsql-format`.
24
+ - **`format`:** `--diff` shows what would change without writing. `--sql` and `--no-leading-comma` override the config for one run.
25
+ - **`format` and `lint`:** read a script from stdin with `-`, and take `-f`/`--script-encoding` and `--config`.
26
+ - **`[format]` and `[lint]` config sections** set project defaults; a command-line flag wins.
27
+ - **`config`:** lists every option with its value, its default and the file that set it, with passwords shown as `***`. `--validate` reports every problem in every config file with its file and line. `--init` prints the config template.
28
+ - **`init`:** creates `execsql.conf`, a starter script and the pre-commit hooks. Existing files are kept unless you pass `--force`.
29
+ - **`list`:** `metacommands`, `encodings`, `plugins` and `keywords`, as text or JSON.
30
+ - **`PG_UPSERT` character-length check:** a staging value longer than its `varchar(n)` or `char(n)` base column fails QA and appears in the `EXPORT_FAILURES` fix sheet.
31
+
32
+ ### Deprecated
33
+
34
+ - Running a script without a command (`execsql script.sql myserver mydb`) prints a warning and stops working in execsql2 3.0. Put `run` first: `execsql run script.sql myserver mydb`. `-m`, `-y`, `--list-plugins`, `--dump-keywords`, `--init-config` and `--ping` without a command warn the same way and name their replacement; see [Flags that became commands](https://execsql2.readthedocs.io/en/latest/getting-started/syntax/#former_flags). After `run` they still work without a warning, but `execsql run --help` no longer lists them.
35
+
36
+ ### Removed
37
+
38
+ - `--lint`: use `execsql lint`. `execsql run --lint` now exits with status 2 without running the script, so update CI steps and hooks that call it.
39
+ - The `execsql-format` command: use `execsql format`, which takes the same options. Pre-commit users need no change, because the hook id is still `execsql-format`. Shell scripts, Makefiles and CI steps that call `execsql-format` must be updated.
40
+ - `SqlStmt`, `MetacommandStmt` and `ScriptCmd` from `execsql.script`. Only Python code that imports them is affected; scripts are not.
41
+
42
+ ### Changed
43
+
44
+ - **`PG_UPSERT` QA follows `METHOD` and `EXCLUDE`:** all three modes check only the staging rows the load would write, so pass `PG_UPSERT QA` the same `METHOD` and `EXCLUDE` as the load that follows it. `CHECK ... METHOD update` treats a missing `NOT NULL` column as a warning. The `upsert` extra now requires pg-upsert 1.25.0 or newer. See [QA follows METHOD and EXCLUDE](https://execsql2.readthedocs.io/en/latest/reference/metacommands/#pg_upsert_qa_method).
45
+ - **`PG_UPSERT` QA can fail where it passed before:** it now catches a unique key that collides with an existing base row, a foreign key parent that is not in `TABLES`, and an excluded `NOT NULL` column on an inserted row, all of which used to fail during the load.
46
+ - A script named exactly like a command (`run`, `format`, `lint`, `config`, `list` or `init`, with no extension) must be run as `execsql run NAME`.
47
+ - `execsql format --encoding` is now `-f`/`--script-encoding`, matching `run`. `--encoding` still works.
48
+ - The debug REPL (`BREAKPOINT`, `--debug`) runs metacommands and blocks as well as SQL, as if they were the next lines of the script where it paused: a `SUB` stays set when the script resumes, and SQL is committed as the script's own SQL would be. See [Debugging](https://execsql2.readthedocs.io/en/latest/guides/debugging/).
49
+ - CLI help is plain text, colored on a terminal (`NO_COLOR` or `EXECSQL_NO_COLOR` turns color off), and uses the terminal's full width. `execsql` with no arguments prints it and exits with status 2.
50
+ - Lint output groups issues under each file in line order, with one summary line. A script that fails to parse is reported on one line with its line number.
51
+ - Error messages name the fix: a missing SQLite or DuckDB file suggests `-n`/`--new-db`, and a config file error names the file and line and suggests `execsql config --validate`.
52
+ - Requires Typer 0.26 or newer (previously 0.12).
53
+
54
+ ### Fixed
55
+
56
+ - `execsql format` without the `[formatter]` extra says sqlglot is needed and how to install it, instead of an uncaught `ImportError`.
57
+ - `-h` works as a short form of `--help`, as it did in upstream execsql.
58
+ - The debug REPL's `.set VAR VALUE` keeps the value's case instead of lowercasing it, and `.vars all` lists environment variables instead of looking up a variable named `all`.
59
+
60
+ ______________________________________________________________________
61
+
62
+ ## [2.23.1] - 2026-09-29
63
+
64
+ ### Added
65
+
66
+ - A warning when MySQL, MariaDB or Oracle commits a statement on its own while `AUTOCOMMIT` is `OFF` or a batch is open — `CREATE TABLE`, `DROP`, `TRUNCATE` and other DDL, which the server commits together with everything before it, so none of it can be rolled back.
67
+ - A warning when `AUTOCOMMIT OFF` or `BEGIN BATCH` cannot hold statements at all: an ODBC DSN whose driver has no transactions, or an MS Access `CREATE TEMPORARY QUERY`, which reopens the connection and rolls back what was not yet committed.
68
+
69
+ ### Fixed
70
+
71
+ - SQLite: `CREATE TABLE`, `DROP` and other DDL run while `AUTOCOMMIT` is `OFF` or inside `BEGIN BATCH` are held until commit. They were committed at once, so `AUTOCOMMIT ON WITH ROLLBACK` and `ROLLBACK BATCH` left them in place.
72
+ - DuckDB: `AUTOCOMMIT OFF` and `BEGIN BATCH` hold statements until commit. Every statement, rows included, was committed as it ran, so nothing could be rolled back. A script's own `BEGIN;` and `COMMIT;` now work too; `COMMIT;` failed with "no transaction is active".
73
+ - DuckDB: `$LAST_ROWCOUNT` holds the number of rows an `INSERT`, `UPDATE` or `DELETE` changed. It was always `-1`.
74
+
75
+ ______________________________________________________________________
76
+
16
77
  ## [2.23.0] - 2026-09-29
17
78
 
18
79
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: execsql2
3
- Version: 2.23.0
3
+ Version: 2.24.0
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
@@ -42,7 +42,7 @@ Requires-Python: >=3.10
42
42
  Requires-Dist: python-dateutil>=2.8
43
43
  Requires-Dist: rich>=13.0
44
44
  Requires-Dist: textual>=1.0
45
- Requires-Dist: typer>=0.12
45
+ Requires-Dist: typer>=0.26
46
46
  Provides-Extra: all
47
47
  Requires-Dist: defusedxml>=0.7; extra == 'all'
48
48
  Requires-Dist: duckdb>=1.0; extra == 'all'
@@ -52,7 +52,7 @@ Requires-Dist: keyring>=25.0; extra == 'all'
52
52
  Requires-Dist: odfpy>=1.4; extra == 'all'
53
53
  Requires-Dist: openpyxl>=3.1; extra == 'all'
54
54
  Requires-Dist: oracledb>=3.0; extra == 'all'
55
- Requires-Dist: pg-upsert>=1.23.0; extra == 'all'
55
+ Requires-Dist: pg-upsert>=1.25.0; extra == 'all'
56
56
  Requires-Dist: polars>=1.0; extra == 'all'
57
57
  Requires-Dist: psycopg[binary]<4,>=3.1; extra == 'all'
58
58
  Requires-Dist: pymysql>=1.1; extra == 'all'
@@ -126,7 +126,7 @@ Requires-Dist: oracledb>=3.0; extra == 'oracle'
126
126
  Provides-Extra: postgres
127
127
  Requires-Dist: psycopg[binary]<4,>=3.1; extra == 'postgres'
128
128
  Provides-Extra: upsert
129
- Requires-Dist: pg-upsert>=1.23.0; extra == 'upsert'
129
+ Requires-Dist: pg-upsert>=1.25.0; extra == 'upsert'
130
130
  Description-Content-Type: text/markdown
131
131
 
132
132
  > [!NOTE]
@@ -154,7 +154,54 @@ Description-Content-Type: text/markdown
154
154
 
155
155
  ## Overview
156
156
 
157
- *execsql* runs SQL scripts against PostgreSQL, MySQL/MariaDB, SQLite, DuckDB, MS-SQL-Server, MS-Access, Firebird, Oracle, or an ODBC DSN. In addition to standard SQL, it supports a set of metacommands (embedded in SQL comments) for importing and exporting data, copying data between databases, conditional execution, looping, substitution variables, and interactive prompts. Because metacommands live in SQL comments, scripts remain valid SQL and are ignored by other tools such as `psql` or `sqlcmd`.
157
+ *execsql* is a toolchain for SQL scripts: **write** them with editor support, **format** them consistently, **lint** them without a database, and **run** them against nine DBMSs.
158
+
159
+ Scripts are ordinary SQL plus metacommands embedded in comments (`-- !x!`), which add importing and exporting data, copying between databases, conditional execution, looping, substitution variables, and interactive prompts. Because the metacommands live in comments, the scripts stay valid SQL and other tools (`psql`, `sqlcmd`, your editor) ignore them.
160
+
161
+ | Command | What it does | Needs a database? |
162
+ | ------------------------------------------ | ----------------------------------------------------------------------- | ----------------- |
163
+ | `execsql format` | Normalize keywords, indentation, and SQL layout | No |
164
+ | `execsql lint` | Static analysis: structure, undefined variables, bad targets | No |
165
+ | `execsql run` | Run the script against PostgreSQL, MySQL, SQLite, DuckDB, … | Yes |
166
+ | `execsql config` | Show every config option, its value, and the file that set it | No |
167
+ | `execsql list` | Metacommands, encodings, plugins, or the keyword vocabulary | No |
168
+ | `execsql init` | Set up a project: config file, a script with a header, pre-commit hooks | No |
169
+ | [VS Code extension](extras/vscode-execsql) | Syntax highlighting for metacommands and variables | No |
170
+
171
+ `format` and `lint` take files or directories.
172
+
173
+ > [!WARNING]
174
+ > The original positional form, `execsql script.sql myserver mydb`, still works
175
+ > but is deprecated: it prints a warning and stops working in execsql2 3.0. Use
176
+ > `execsql run script.sql myserver mydb`.
177
+
178
+ ## Quick start: no database required
179
+
180
+ `format` and `lint` work on a bare `.sql` file, with no server and no config. Try them first:
181
+
182
+ ```bash
183
+ pip install execsql2[formatter]
184
+
185
+ execsql format --check scripts/ # is it formatted?
186
+ execsql format -i scripts/ # format it
187
+ execsql lint scripts/ # find problems before they cost you a run
188
+ ```
189
+
190
+ `lint` reports unmatched blocks, undefined and unused substitution variables, unreachable branches, and `INCLUDE`/`SCRIPT` targets that do not exist: the failures that otherwise surface halfway through a run against a live database:
191
+
192
+ ```text
193
+ $ execsql lint load_data.sql
194
+ load_data.sql
195
+ 1 warning V002 variable !!site_cd!! is never used
196
+ 2 warning I001 INCLUDE file does not exist: common/setup.sql
197
+ 3 warning V001 undefined variable !!site_code!!
198
+
199
+ Found 3 issues in 1 file: 3 warnings (1 file checked)
200
+ ```
201
+
202
+ `V002` and `V001` together point at a typo: `site_cd` is defined and `site_code` is used. Every issue has a rule code for `--select` and `--ignore`; `--output-format concise` prints one `path:line` line per issue and `json` feeds CI tools. The [lint rules](https://execsql2.readthedocs.io/en/latest/reference/lint/) page explains each one.
203
+
204
+ `execsql format` also runs as a [pre-commit hook](#formatting-scripts), so formatting is enforced without anyone remembering to run it.
158
205
 
159
206
  ## Example
160
207
 
@@ -197,49 +244,54 @@ The `PROMPT` metacommand produces a GUI display of the data:
197
244
  ## Installation
198
245
 
199
246
  ```bash
200
- pip install execsql2 # core — SQLite works with no extras
247
+ pip install execsql2 # core: SQLite works with no extras
201
248
  pip install "execsql2[postgres]" # add a driver: postgres, mysql, mssql, duckdb, firebird, oracle, odbc
202
249
  pip install "execsql2[all]" # everything: all drivers plus all feature extras
203
250
  ```
204
251
 
205
- Feature extras cover spreadsheet and Parquet/Feather formats, keyring authentication, PostgreSQL upsert, and more — see the [installation guide](https://execsql2.readthedocs.io/en/latest/getting-started/installation/) for the full list.
252
+ Feature extras cover spreadsheet and Parquet/Feather formats, keyring authentication, PostgreSQL upsert, and more. See the [installation guide](https://execsql2.readthedocs.io/en/latest/getting-started/installation/) for the full list.
206
253
 
207
254
  ## Usage
208
255
 
209
256
  ```text
210
- execsql [OPTIONS] SQL_SCRIPT [SERVER DATABASE | DATABASE_FILE]
257
+ execsql run [OPTIONS] SQL_SCRIPT [SERVER DATABASE | DATABASE_FILE]
258
+ execsql format [--check | -i] [--indent N] FILE_OR_DIR...
259
+ execsql lint [OPTIONS] FILE_OR_DIR...
260
+ execsql config [SQL_SCRIPT] [--init] [--config FILE]
261
+ execsql list metacommands|encodings|plugins|keywords
262
+ execsql init [DIR] [--script NAME] [--no-script] [--no-config] [--no-pre-commit]
211
263
  ```
212
264
 
213
265
  Examples:
214
266
 
215
267
  ```bash
216
- execsql -tp script.sql myserver mydb # PostgreSQL
217
- execsql -tm script.sql myserver mydb # MySQL / MariaDB
218
- execsql -ts script.sql myserver mydb # SQL Server
219
- execsql -tl script.sql mydb.sqlite # SQLite
220
- execsql -tk script.sql mydb.duckdb # DuckDB
221
- execsql -to script.sql myserver myservice # Oracle
222
- execsql script.sql # read connection from config file
268
+ execsql run -tp script.sql myserver mydb # PostgreSQL
269
+ execsql run -tm script.sql myserver mydb # MySQL / MariaDB
270
+ execsql run -ts script.sql myserver mydb # SQL Server
271
+ execsql run -tl script.sql mydb.sqlite # SQLite
272
+ execsql run -tk script.sql mydb.duckdb # DuckDB
273
+ execsql run -to script.sql myserver myservice # Oracle
274
+ execsql run script.sql # read connection from config file
223
275
  ```
224
276
 
225
277
  ### Supported Databases
226
278
 
227
- | Flag | Database | Support |
228
- | ---- | --------------- | ------------------------------------------------ |
229
- | `p` | PostgreSQL | Supported — verified against a live server in CI |
230
- | `m` | MySQL / MariaDB | Supported — verified against a live server in CI |
231
- | `s` | MS SQL Server | Supported — verified against a live server in CI |
232
- | `l` | SQLite | Supported — verified against real files in CI |
233
- | `k` | DuckDB | Supported — verified against real files in CI |
234
- | `a` | MS Access | Best effort — not verified in CI |
235
- | `f` | Firebird | Best effort — not verified in CI |
236
- | `o` | Oracle | Best effort — not verified in CI |
237
- | `d` | ODBC DSN | Best effort — not verified in CI |
279
+ | Flag | Database | Support |
280
+ | ---- | --------------- | ----------------------------------------------- |
281
+ | `p` | PostgreSQL | Supported: verified against a live server in CI |
282
+ | `m` | MySQL / MariaDB | Supported: verified against a live server in CI |
283
+ | `s` | MS SQL Server | Supported: verified against a live server in CI |
284
+ | `l` | SQLite | Supported: verified against real files in CI |
285
+ | `k` | DuckDB | Supported: verified against real files in CI |
286
+ | `a` | MS Access | Best effort: not verified in CI |
287
+ | `f` | Firebird | Best effort: not verified in CI |
288
+ | `o` | Oracle | Best effort: not verified in CI |
289
+ | `d` | ODBC DSN | Best effort: not verified in CI |
238
290
 
239
291
  **Supported** adapters run against a live server or a real database file on
240
292
  every CI run; a regression blocks the release and bugs get fixed. **Best
241
293
  effort** adapters are carried forward from the upstream monolith and are not
242
- exercised anywhere in CI — the code is there and may work, but nothing proves
294
+ exercised anywhere in CI. The code is there and may work, but nothing proves
243
295
  it still does. Issues and pull requests are welcome for them; no guarantee is
244
296
  made. Opening a best-effort connection prints one informational line, which
245
297
  `support_tier_notice=No` in the `[interface]` section of `execsql.conf`
@@ -247,24 +299,24 @@ silences.
247
299
 
248
300
  ### Common options
249
301
 
250
- | Flag | Description |
251
- | ------------------------------------------------- | --------------------------------------------------------------- |
252
- | `-t {p,m,s,l,k,a,f,o,d}` | Database type |
253
- | `-u USER` | Database username |
254
- | `-p PORT` | Server port |
255
- | `--dsn URL` | Connection string (e.g. `postgresql://user:pass@host/db`) |
256
- | `-n` | Create a new SQLite or PostgreSQL database if it does not exist |
257
- | `-c SCRIPT` | Execute inline SQL or metacommand string |
258
- | `-a VALUE` | Set substitution variable `$ARG_x` |
259
- | `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
260
- | `--config FILE` | Load an explicit config file |
261
- | `--dry-run` | Parse the script and report commands without executing |
262
- | `--lint` | Static analysis: check structure and warn on issues (no DB) |
263
- | `--ping` | Test database connectivity and exit |
264
- | `--debug` | Start in step-through debug mode (REPL pauses before each stmt) |
265
- | `--no-system-cmd` / `--no-rm-file` / `--no-serve` | Disable the `SYSTEM_CMD` / `RM_FILE` / `SERVE` metacommands |
266
-
267
- See the [full options reference](https://execsql2.readthedocs.io/en/latest/getting-started/syntax/#options) or run `execsql --help` for the complete list, and `execsql -m` for all metacommands.
302
+ | Flag | Description |
303
+ | ------------------------------------------------- | -------------------------------------------------------------------------- |
304
+ | `-t {p,m,s,l,k,a,f,o,d}` | Database type |
305
+ | `-u USER` | Database username |
306
+ | `-p PORT` | Server port |
307
+ | `--dsn URL` | Connection string (e.g. `postgresql://user:pass@host/db`) |
308
+ | `-n` | Create a new SQLite or PostgreSQL database if it does not exist |
309
+ | `-c SCRIPT` | Execute inline SQL or metacommand string |
310
+ | `-a VALUE` | Set substitution variable `$ARG_x` |
311
+ | `--var NAME=VALUE` | Set the substitution variable `!!NAME!!` |
312
+ | `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
313
+ | `--config FILE` | Load an explicit config file |
314
+ | `--dry-run` | Parse the script and report commands without executing |
315
+ | `--manifest FILE` | Write a JSON record of the run: files read and written, statements, errors |
316
+ | `--debug` | Start in step-through debug mode (REPL pauses before each stmt) |
317
+ | `--no-system-cmd` / `--no-rm-file` / `--no-serve` | Disable the `SYSTEM_CMD` / `RM_FILE` / `SERVE` metacommands |
318
+
319
+ See the [full options reference](https://execsql2.readthedocs.io/en/latest/getting-started/syntax/#options) or run `execsql run --help` for the complete list, `execsql run --ping` to test a connection, `execsql config` to see which config files set what, and `execsql list metacommands` for all metacommands.
268
320
 
269
321
  ## Features
270
322
 
@@ -279,7 +331,7 @@ See the [full options reference](https://execsql2.readthedocs.io/en/latest/getti
279
331
  - Conditionally execute SQL and metacommands using `IF`/`ELSE`/`ENDIF` based on data values, DBMS type, or user input.
280
332
  - Loop over blocks of SQL and metacommands using `LOOP`/`ENDLOOP`; include or chain scripts with `INCLUDE` and `SCRIPT`.
281
333
  - Use substitution variables (`SUB`, `$ARG_x`, built-in variables like `$date_tag`) to parameterize scripts.
282
- - Validate data with `ASSERT` — halt the script with a clear error message if a condition is false (ideal for CI pipelines).
334
+ - Validate data with `ASSERT`: halt the script with a clear error message if a condition is false (ideal for CI pipelines).
283
335
 
284
336
  **Interaction & observability**
285
337
 
@@ -334,7 +386,7 @@ if not result.success:
334
386
  result.raise_on_error() # raises ExecSqlError
335
387
  ```
336
388
 
337
- Use a pre-existing database connection instead of a DSN — useful for reusing one connection across multiple `run()` calls, or when connection parameters come from your application's configuration rather than a URL:
389
+ Use a pre-existing database connection instead of a DSN. This is useful for reusing one connection across multiple `run()` calls, or when connection parameters come from your application's configuration rather than a URL:
338
390
 
339
391
  ```python
340
392
  from execsql import run
@@ -357,7 +409,7 @@ loaded = run(
357
409
  variables={"RUN_DATE": "2026-07-03"},
358
410
  )
359
411
 
360
- # run() does NOT close the connection — you manage its lifecycle
412
+ # run() does NOT close the connection; you manage its lifecycle
361
413
  conn.close()
362
414
 
363
415
  # SQLite works the same way
@@ -366,43 +418,44 @@ result = run(sql="SELECT 1;", connection=conn)
366
418
  conn.close()
367
419
  ```
368
420
 
369
- Factory functions exist for every supported backend (`db_Postgres`, `db_MySQL`, `db_SQLite`, `db_DuckDB`, `db_SqlServer`, `db_Oracle`, `db_Firebird`, `db_Access`, `db_Dsn`) — see [`execsql.db.factory`](https://execsql2.readthedocs.io/en/latest/api/db/).
421
+ Factory functions exist for every supported backend (`db_Postgres`, `db_MySQL`, `db_SQLite`, `db_DuckDB`, `db_SqlServer`, `db_Oracle`, `db_Firebird`, `db_Access`, `db_Dsn`). See [`execsql.db.factory`](https://execsql2.readthedocs.io/en/latest/api/db/).
370
422
 
371
423
  Each call to `run()` uses an isolated `RuntimeContext`, so multiple calls do not share state.
372
424
 
373
425
  ## Formatting Scripts
374
426
 
375
- The `execsql-format` command normalizes execsql script files: it uppercases metacommand keywords, corrects block indentation, and optionally reformats SQL via `sqlglot`. The metacommand / indent / keyword reformatting is built into `execsql2`; SQL reformatting requires the `[formatter]` extra (or pass `--no-sql` to skip it):
427
+ The `execsql format` command normalizes execsql script files: it uppercases metacommand keywords, corrects block indentation, and optionally reformats SQL via `sqlglot`. The metacommand / indent / keyword reformatting is built into `execsql2`; SQL reformatting requires the `[formatter]` extra (or pass `--no-sql` to skip it):
376
428
 
377
429
  ```bash
378
430
  # Install with the SQL-reformatting extra
379
431
  pip install execsql2[formatter]
380
432
 
381
433
  # Format files in place
382
- execsql-format --in-place scripts/
434
+ execsql format --in-place scripts/
383
435
 
384
436
  # Check formatting without writing (useful in CI)
385
- execsql-format --check scripts/
437
+ execsql format --check scripts/
386
438
 
387
- # Run the formatter without sqlglot — keyword/indent normalization only
388
- execsql-format --no-sql --in-place scripts/
439
+ # Run the formatter without sqlglot: keyword/indent normalization only
440
+ execsql format --no-sql --in-place scripts/
389
441
  ```
390
442
 
391
- `execsql-format` is also available as a [pre-commit](https://pre-commit.com/) hook:
443
+ `execsql format` and `execsql lint` are also available as [pre-commit](https://pre-commit.com/) hooks. The format hook id is unchanged, so existing configs keep working:
392
444
 
393
445
  ```yaml
394
446
  repos:
395
447
  - repo: https://github.com/geocoug/execsql
396
- rev: v2.23.0
448
+ rev: v2.24.0
397
449
  hooks:
398
450
  - id: execsql-format
451
+ - id: execsql-lint
399
452
  ```
400
453
 
401
- The hook rewrites `*.sql` files in place by default. See the [formatter documentation](https://execsql2.readthedocs.io/en/latest/guides/formatter/) for `--check`, `--indent`, and other options.
454
+ The format hook rewrites `*.sql` files in place by default; the lint hook fails the commit when a script has a lint error. See the [formatter documentation](https://execsql2.readthedocs.io/en/latest/guides/formatter/) for `--check`, `--indent`, and other options.
402
455
 
403
456
  ## VS Code Syntax Highlighting
404
457
 
405
- A VS Code extension for execsql syntax highlighting is included in [`extras/vscode-execsql`](extras/vscode-execsql). It injects a TextMate grammar into `.sql` files, adding highlighting for `-- !x!` metacommand markers, keywords (control flow, block, action, directive), variable substitutions (`!!var!!`, `!{var}!`), built-in functions, export formats, and config options — all layered on top of standard SQL highlighting.
458
+ A VS Code extension for execsql syntax highlighting is included in [`extras/vscode-execsql`](extras/vscode-execsql). It injects a TextMate grammar into `.sql` files, adding highlighting for `-- !x!` metacommand markers, keywords (control flow, block, action, directive), variable substitutions (`!!var!!`, `!{var}!`), built-in functions, export formats, and config options, all layered on top of standard SQL highlighting.
406
459
 
407
460
  To install, symlink the extension folder into your VS Code extensions directory:
408
461