execsql2 2.29.0__tar.gz → 2.30.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 (492) hide show
  1. execsql2-2.30.0/.github/ISSUE_TEMPLATE/bug_report.yml +57 -0
  2. execsql2-2.30.0/.github/ISSUE_TEMPLATE/feature_request.yml +28 -0
  3. {execsql2-2.29.0 → execsql2-2.30.0}/.github/workflows/ci-cd.yml +3 -21
  4. {execsql2-2.29.0 → execsql2-2.30.0}/CHANGELOG.md +30 -0
  5. {execsql2-2.29.0 → execsql2-2.30.0}/PKG-INFO +2 -4
  6. {execsql2-2.29.0 → execsql2-2.30.0}/README.md +1 -1
  7. {execsql2-2.29.0 → execsql2-2.30.0}/docs/about/divergence.md +11 -11
  8. {execsql2-2.29.0 → execsql2-2.30.0}/docs/api/index.md +1 -1
  9. {execsql2-2.29.0 → execsql2-2.30.0}/docs/dev/architecture.md +73 -36
  10. {execsql2-2.29.0 → execsql2-2.30.0}/docs/getting-started/syntax.md +3 -3
  11. {execsql2-2.29.0 → execsql2-2.30.0}/docs/guides/editors.md +57 -9
  12. {execsql2-2.29.0 → execsql2-2.30.0}/docs/guides/examples.md +20 -10
  13. {execsql2-2.29.0 → execsql2-2.30.0}/docs/guides/formatter.md +2 -2
  14. {execsql2-2.29.0 → execsql2-2.30.0}/docs/guides/sql_syntax.md +4 -0
  15. {execsql2-2.29.0 → execsql2-2.30.0}/docs/guides/usage.md +2 -0
  16. {execsql2-2.29.0 → execsql2-2.30.0}/docs/reference/configuration.md +6 -2
  17. {execsql2-2.29.0 → execsql2-2.30.0}/docs/reference/lint.md +3 -1
  18. {execsql2-2.29.0 → execsql2-2.30.0}/docs/reference/metacommands.md +36 -15
  19. {execsql2-2.29.0 → execsql2-2.30.0}/docs/reference/security.md +4 -2
  20. {execsql2-2.29.0 → execsql2-2.30.0}/docs/reference/substitution_vars.md +4 -1
  21. {execsql2-2.29.0 → execsql2-2.30.0}/extras/vscode-execsql/README.md +14 -10
  22. {execsql2-2.29.0 → execsql2-2.30.0}/extras/vscode-execsql/extension.js +71 -25
  23. {execsql2-2.29.0 → execsql2-2.30.0}/extras/vscode-execsql/package.json +22 -0
  24. {execsql2-2.29.0 → execsql2-2.30.0}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +1 -1
  25. {execsql2-2.29.0 → execsql2-2.30.0}/justfile +2 -2
  26. {execsql2-2.29.0 → execsql2-2.30.0}/pyproject.toml +2 -4
  27. {execsql2-2.29.0 → execsql2-2.30.0}/scripts/generate_vscode_grammar.py +1 -26
  28. execsql2-2.30.0/src/execsql/__main__.py +12 -0
  29. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/api.py +5 -0
  30. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/__init__.py +3 -14
  31. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/application.py +5 -3
  32. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/commands/lint.py +4 -1
  33. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/commands/lsp.py +42 -0
  34. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/dsn.py +3 -1
  35. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/lint.py +14 -6
  36. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/run.py +17 -9
  37. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/config.py +32 -6
  38. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/duckdb.py +96 -14
  39. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/gui/__init__.py +3 -31
  40. execsql2-2.30.0/src/execsql/lsp/_util.py +21 -0
  41. execsql2-2.30.0/src/execsql/lsp/cache.py +73 -0
  42. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/lsp/code_actions.py +10 -14
  43. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/lsp/completion.py +8 -15
  44. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/lsp/diagnostics.py +14 -2
  45. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/lsp/document.py +139 -41
  46. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/lsp/hover.py +5 -13
  47. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/lsp/navigation.py +7 -10
  48. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/lsp/server.py +111 -29
  49. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/manifest.py +29 -9
  50. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/__init__.py +0 -2
  51. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/io_fileops.py +5 -0
  52. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/script/executor.py +2 -21
  53. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/state.py +6 -3
  54. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/state.pyi +2 -0
  55. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/errors.py +19 -36
  56. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/fileio.py +44 -48
  57. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/regex.py +0 -5
  58. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_cli.py +13 -18
  59. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_cli_e2e.py +0 -33
  60. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_cli_run.py +0 -27
  61. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_cli_surface.py +1 -1
  62. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_commands.py +3 -1
  63. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_dispatch.py +20 -2
  64. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_lint.py +20 -0
  65. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_manifest.py +23 -0
  66. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_duckdb.py +65 -0
  67. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_transactions.py +0 -1
  68. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/conftest.py +0 -9
  69. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_exporters.py +1 -1
  70. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_ods_export.py +1 -1
  71. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_roundtrip_values.py +0 -5
  72. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_xlsx.py +1 -1
  73. {execsql2-2.29.0 → execsql2-2.30.0}/tests/gui/test_backends.py +0 -64
  74. execsql2-2.30.0/tests/lsp/test_cache.py +130 -0
  75. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/test_document.py +7 -0
  76. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/test_server.py +264 -15
  77. execsql2-2.30.0/tests/metacommands/conftest.py +22 -0
  78. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_metacommands.py +6 -46
  79. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_metacommands_extended.py +0 -7
  80. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_metacommands_script_ext.py +0 -4
  81. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_row_count.py +3 -31
  82. {execsql2-2.29.0 → execsql2-2.30.0}/tests/security/test_env_detection.py +2 -2
  83. {execsql2-2.29.0 → execsql2-2.30.0}/tests/security/test_log_redaction.py +1 -1
  84. {execsql2-2.29.0 → execsql2-2.30.0}/tests/security/test_log_secrets.py +48 -0
  85. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_api_isolation.py +28 -0
  86. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_config_data.py +50 -0
  87. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_executor_inprocess.py +0 -8
  88. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_reference.py +1 -1
  89. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_registry.py +5 -5
  90. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_state.py +1 -1
  91. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_tooling_versions.py +10 -0
  92. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_errors.py +21 -36
  93. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_errors_extra.py +17 -15
  94. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_fileio.py +0 -20
  95. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_fileio_extra.py +1 -9
  96. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_regex.py +0 -25
  97. {execsql2-2.29.0 → execsql2-2.30.0}/uv.lock +1 -140
  98. execsql2-2.29.0/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  99. execsql2-2.29.0/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  100. execsql2-2.29.0/docs/images/connect.b64 +0 -1
  101. execsql2-2.29.0/docs/images/create_conf.png +0 -0
  102. execsql2-2.29.0/docs/images/entry_form.png +0 -0
  103. execsql2-2.29.0/docs/images/execsql_console.png +0 -0
  104. execsql2-2.29.0/docs/images/logo_small.png +0 -0
  105. execsql2-2.29.0/docs/images/pause_terminal.png +0 -0
  106. execsql2-2.29.0/docs/images/pause_terminal_sm.b64 +0 -1
  107. execsql2-2.29.0/docs/images/prompt_compare.png +0 -0
  108. execsql2-2.29.0/docs/images/unit_conversions.b64 +0 -1
  109. execsql2-2.29.0/src/execsql/__main__.py +0 -13
  110. {execsql2-2.29.0 → execsql2-2.30.0}/.github/dependabot.yml +0 -0
  111. {execsql2-2.29.0 → execsql2-2.30.0}/.gitignore +0 -0
  112. {execsql2-2.29.0 → execsql2-2.30.0}/.pre-commit-config.yaml +0 -0
  113. {execsql2-2.29.0 → execsql2-2.30.0}/.pre-commit-hooks.yaml +0 -0
  114. {execsql2-2.29.0 → execsql2-2.30.0}/.python-version +0 -0
  115. {execsql2-2.29.0 → execsql2-2.30.0}/.readthedocs.yaml +0 -0
  116. {execsql2-2.29.0 → execsql2-2.30.0}/CONTRIBUTING.md +0 -0
  117. {execsql2-2.29.0 → execsql2-2.30.0}/LICENSE.txt +0 -0
  118. {execsql2-2.29.0 → execsql2-2.30.0}/NOTICE +0 -0
  119. {execsql2-2.29.0 → execsql2-2.30.0}/SECURITY.md +0 -0
  120. {execsql2-2.29.0 → execsql2-2.30.0}/docs/about/contributors.md +0 -0
  121. {execsql2-2.29.0 → execsql2-2.30.0}/docs/about/copyright.md +0 -0
  122. {execsql2-2.29.0 → execsql2-2.30.0}/docs/api/cli.md +0 -0
  123. {execsql2-2.29.0 → execsql2-2.30.0}/docs/api/db.md +0 -0
  124. {execsql2-2.29.0 → execsql2-2.30.0}/docs/api/exporters.md +0 -0
  125. {execsql2-2.29.0 → execsql2-2.30.0}/docs/api/importers.md +0 -0
  126. {execsql2-2.29.0 → execsql2-2.30.0}/docs/api/metacommands.md +0 -0
  127. {execsql2-2.29.0 → execsql2-2.30.0}/docs/dev/adding_db_adapters.md +0 -0
  128. {execsql2-2.29.0 → execsql2-2.30.0}/docs/dev/adding_exporters.md +0 -0
  129. {execsql2-2.29.0 → execsql2-2.30.0}/docs/dev/adding_importers.md +0 -0
  130. {execsql2-2.29.0 → execsql2-2.30.0}/docs/dev/adding_metacommands.md +0 -0
  131. {execsql2-2.29.0 → execsql2-2.30.0}/docs/dev/releasing.md +0 -0
  132. {execsql2-2.29.0 → execsql2-2.30.0}/docs/getting-started/installation.md +0 -0
  133. {execsql2-2.29.0 → execsql2-2.30.0}/docs/getting-started/requirements.md +0 -0
  134. {execsql2-2.29.0 → execsql2-2.30.0}/docs/guides/debugging.md +0 -0
  135. {execsql2-2.29.0 → execsql2-2.30.0}/docs/guides/documentation.md +0 -0
  136. {execsql2-2.29.0 → execsql2-2.30.0}/docs/guides/encoding.md +0 -0
  137. {execsql2-2.29.0 → execsql2-2.30.0}/docs/guides/logging.md +0 -0
  138. {execsql2-2.29.0 → execsql2-2.30.0}/docs/guides/using_scripts.md +0 -0
  139. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/Compare_planets.png +0 -0
  140. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/actions.png +0 -0
  141. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/actions2.png +0 -0
  142. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/checkboxes.png +0 -0
  143. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/connect.png +0 -0
  144. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/data_error1_screenshot.jpg +0 -0
  145. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/execsql_logo_01.png +0 -0
  146. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/fatals.png +0 -0
  147. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/pause_terminal_sm.png +0 -0
  148. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/set_build_commands.jpg +0 -0
  149. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/unit_conversions_029.png +0 -0
  150. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/unmatched.png +0 -0
  151. {execsql2-2.29.0 → execsql2-2.30.0}/docs/images/vim_execsql_highlight.png +0 -0
  152. {execsql2-2.29.0 → execsql2-2.30.0}/docs/index.md +0 -0
  153. {execsql2-2.29.0 → execsql2-2.30.0}/extras/plugin-template/README.md +0 -0
  154. {execsql2-2.29.0 → execsql2-2.30.0}/extras/plugin-template/pyproject.toml +0 -0
  155. {execsql2-2.29.0 → execsql2-2.30.0}/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +0 -0
  156. {execsql2-2.29.0 → execsql2-2.30.0}/extras/plugin-template/tests/test_plugin.py.example +0 -0
  157. {execsql2-2.29.0 → execsql2-2.30.0}/extras/vscode-execsql/.vscodeignore +0 -0
  158. {execsql2-2.29.0 → execsql2-2.30.0}/extras/vscode-execsql/LICENSE.txt +0 -0
  159. {execsql2-2.29.0 → execsql2-2.30.0}/extras/vscode-execsql/icon.png +0 -0
  160. {execsql2-2.29.0 → execsql2-2.30.0}/extras/vscode-execsql/package-lock.json +0 -0
  161. {execsql2-2.29.0 → execsql2-2.30.0}/scripts/benchmarks/README.md +0 -0
  162. {execsql2-2.29.0 → execsql2-2.30.0}/scripts/benchmarks/results/.gitignore +0 -0
  163. {execsql2-2.29.0 → execsql2-2.30.0}/scripts/benchmarks/run_benchmarks.py +0 -0
  164. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/__init__.py +0 -0
  165. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/commands/__init__.py +0 -0
  166. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/commands/config.py +0 -0
  167. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/commands/format.py +0 -0
  168. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/commands/init.py +0 -0
  169. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/commands/listing.py +0 -0
  170. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/commands/run.py +0 -0
  171. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/dispatch.py +0 -0
  172. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/help.py +0 -0
  173. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/cli/options.py +0 -0
  174. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/config_validation.py +0 -0
  175. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/data/__init__.py +0 -0
  176. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/data/execsql.conf.template +0 -0
  177. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/data/script_header.sql +0 -0
  178. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/__init__.py +0 -0
  179. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/access.py +0 -0
  180. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/base.py +0 -0
  181. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/dsn.py +0 -0
  182. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/factory.py +0 -0
  183. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/firebird.py +0 -0
  184. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/mysql.py +0 -0
  185. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/oracle.py +0 -0
  186. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/postgres.py +0 -0
  187. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/sqlite.py +0 -0
  188. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/sqlserver.py +0 -0
  189. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/db/tiers.py +0 -0
  190. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/debug/__init__.py +0 -0
  191. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/debug/repl.py +0 -0
  192. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exceptions.py +0 -0
  193. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/__init__.py +0 -0
  194. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/base.py +0 -0
  195. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/delimited.py +0 -0
  196. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/duckdb.py +0 -0
  197. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/feather.py +0 -0
  198. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/html.py +0 -0
  199. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/json.py +0 -0
  200. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/latex.py +0 -0
  201. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/markdown.py +0 -0
  202. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/ods.py +0 -0
  203. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/parquet.py +0 -0
  204. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/pretty.py +0 -0
  205. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/protocol.py +0 -0
  206. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/raw.py +0 -0
  207. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/sqlite.py +0 -0
  208. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/templates.py +0 -0
  209. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/values.py +0 -0
  210. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/xls.py +0 -0
  211. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/xlsx.py +0 -0
  212. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/xml.py +0 -0
  213. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/yaml.py +0 -0
  214. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/exporters/zip.py +0 -0
  215. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/format.py +0 -0
  216. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/gui/base.py +0 -0
  217. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/gui/console.py +0 -0
  218. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/gui/desktop.py +0 -0
  219. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/gui/tui.py +0 -0
  220. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/importers/__init__.py +0 -0
  221. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/importers/base.py +0 -0
  222. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/importers/csv.py +0 -0
  223. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/importers/feather.py +0 -0
  224. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/importers/json.py +0 -0
  225. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/importers/ods.py +0 -0
  226. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/importers/xls.py +0 -0
  227. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/interactive.py +0 -0
  228. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/lsp/__init__.py +0 -0
  229. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/lsp/folding.py +0 -0
  230. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/lsp/formatting.py +0 -0
  231. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/lsp/rename.py +0 -0
  232. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/conditions.py +0 -0
  233. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/connect.py +0 -0
  234. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/control.py +0 -0
  235. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/data.py +0 -0
  236. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/debug.py +0 -0
  237. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/dispatch.py +0 -0
  238. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/effects.py +0 -0
  239. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/io.py +0 -0
  240. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/io_export.py +0 -0
  241. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/io_import.py +0 -0
  242. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/io_write.py +0 -0
  243. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/prompt.py +0 -0
  244. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/reference.py +0 -0
  245. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/script_ext.py +0 -0
  246. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/system.py +0 -0
  247. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/metacommands/upsert.py +0 -0
  248. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/models.py +0 -0
  249. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/parser.py +0 -0
  250. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/plugins.py +0 -0
  251. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/py.typed +0 -0
  252. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/script/__init__.py +0 -0
  253. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/script/ast.py +0 -0
  254. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/script/control.py +0 -0
  255. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/script/engine.py +0 -0
  256. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/script/parser.py +0 -0
  257. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/script/variables.py +0 -0
  258. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/types.py +0 -0
  259. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/__init__.py +0 -0
  260. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/auth.py +0 -0
  261. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/color.py +0 -0
  262. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/crypto.py +0 -0
  263. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/datetime.py +0 -0
  264. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/gui.py +0 -0
  265. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/mail.py +0 -0
  266. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/numeric.py +0 -0
  267. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/strings.py +0 -0
  268. {execsql2-2.29.0 → execsql2-2.30.0}/src/execsql/utils/timer.py +0 -0
  269. {execsql2-2.29.0 → execsql2-2.30.0}/templates/README.md +0 -0
  270. {execsql2-2.29.0 → execsql2-2.30.0}/templates/config_settings.sqlite +0 -0
  271. {execsql2-2.29.0 → execsql2-2.30.0}/templates/example_config_prompt.sql +0 -0
  272. {execsql2-2.29.0 → execsql2-2.30.0}/templates/make_config_db.sql +0 -0
  273. {execsql2-2.29.0 → execsql2-2.30.0}/templates/md_compare.sql +0 -0
  274. {execsql2-2.29.0 → execsql2-2.30.0}/templates/md_glossary.sql +0 -0
  275. {execsql2-2.29.0 → execsql2-2.30.0}/templates/md_upsert.sql +0 -0
  276. {execsql2-2.29.0 → execsql2-2.30.0}/templates/pg_compare.sql +0 -0
  277. {execsql2-2.29.0 → execsql2-2.30.0}/templates/pg_glossary.sql +0 -0
  278. {execsql2-2.29.0 → execsql2-2.30.0}/templates/pg_upsert.sql +0 -0
  279. {execsql2-2.29.0 → execsql2-2.30.0}/templates/script_template.sql +0 -0
  280. {execsql2-2.29.0 → execsql2-2.30.0}/templates/ss_compare.sql +0 -0
  281. {execsql2-2.29.0 → execsql2-2.30.0}/templates/ss_glossary.sql +0 -0
  282. {execsql2-2.29.0 → execsql2-2.30.0}/templates/ss_upsert.sql +0 -0
  283. {execsql2-2.29.0 → execsql2-2.30.0}/tests/__init__.py +0 -0
  284. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/__init__.py +0 -0
  285. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_config_validate.py +0 -0
  286. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_error_location.py +0 -0
  287. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_init.py +0 -0
  288. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_lint_fixtures.py +0 -0
  289. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_log_exit_record.py +0 -0
  290. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_ping.py +0 -0
  291. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_profile.py +0 -0
  292. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_sigterm.py +0 -0
  293. {execsql2-2.29.0 → execsql2-2.30.0}/tests/cli/test_undeclared_imports.py +0 -0
  294. {execsql2-2.29.0 → execsql2-2.30.0}/tests/conftest.py +0 -0
  295. {execsql2-2.29.0 → execsql2-2.30.0}/tests/data/formatter_shapes/comment_anchoring.sql +0 -0
  296. {execsql2-2.29.0 → execsql2-2.30.0}/tests/data/formatter_shapes/escapes_and_literals.sql +0 -0
  297. {execsql2-2.29.0 → execsql2-2.30.0}/tests/data/formatter_shapes/substitution_and_metacommands.sql +0 -0
  298. {execsql2-2.29.0 → execsql2-2.30.0}/tests/data/formatter_shapes/unparsable_sql.sql +0 -0
  299. {execsql2-2.29.0 → execsql2-2.30.0}/tests/data/lint/conditions_and_blocks.sql +0 -0
  300. {execsql2-2.29.0 → execsql2-2.30.0}/tests/data/lint/does_not_parse.sql +0 -0
  301. {execsql2-2.29.0 → execsql2-2.30.0}/tests/data/lint/every_metacommand.sql +0 -0
  302. {execsql2-2.29.0 → execsql2-2.30.0}/tests/data/lint/invalid.sql +0 -0
  303. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/__init__.py +0 -0
  304. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_access_windows.py +0 -0
  305. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_base.py +0 -0
  306. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_copy_new.py +0 -0
  307. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_db_adapters_mocked.py +0 -0
  308. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_db_adapters_mocked_extra.py +0 -0
  309. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_dsn.py +0 -0
  310. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_factory.py +0 -0
  311. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_factory_postgres_encoding.py +0 -0
  312. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_import_atomic.py +0 -0
  313. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_import_replacement_quoted.py +0 -0
  314. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_import_short_rows.py +0 -0
  315. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_import_timezones.py +0 -0
  316. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_mysql_case_folding.py +0 -0
  317. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_mysql_inprocess.py +0 -0
  318. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_new_table_checks.py +0 -0
  319. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_oracle_driver.py +0 -0
  320. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_postgres.py +0 -0
  321. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_postgres_inprocess.py +0 -0
  322. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_quoted_substitution_roundtrip.py +0 -0
  323. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_roundtrip_adapters.py +0 -0
  324. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_sqlite.py +0 -0
  325. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_sqlite_extra.py +0 -0
  326. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_sqlserver_inprocess.py +0 -0
  327. {execsql2-2.29.0 → execsql2-2.30.0}/tests/db/test_tiers.py +0 -0
  328. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/__init__.py +0 -0
  329. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_base.py +0 -0
  330. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_db.py +0 -0
  331. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_delimited.py +0 -0
  332. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_duckdb_exporter.py +0 -0
  333. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_feather.py +0 -0
  334. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_html_extended.py +0 -0
  335. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_html_latex.py +0 -0
  336. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_json.py +0 -0
  337. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_json_extended.py +0 -0
  338. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_latex_extended.py +0 -0
  339. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_markdown.py +0 -0
  340. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_ods.py +0 -0
  341. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_parquet.py +0 -0
  342. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_pretty_extended.py +0 -0
  343. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_raw_extended.py +0 -0
  344. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_roundtrip_columnar.py +0 -0
  345. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_roundtrip_dbfile.py +0 -0
  346. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_roundtrip_delimited.py +0 -0
  347. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_roundtrip_json.py +0 -0
  348. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_roundtrip_latex_xml.py +0 -0
  349. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_roundtrip_markup.py +0 -0
  350. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_roundtrip_ods.py +0 -0
  351. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_roundtrip_pretty_raw.py +0 -0
  352. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_roundtrip_template.py +0 -0
  353. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_roundtrip_xlsx.py +0 -0
  354. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_sqlite_exporter.py +0 -0
  355. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_templates.py +0 -0
  356. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_templates_extended.py +0 -0
  357. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_values_extended.py +0 -0
  358. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_xls_xlsx.py +0 -0
  359. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_xml.py +0 -0
  360. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_yaml.py +0 -0
  361. {execsql2-2.29.0 → execsql2-2.30.0}/tests/exporters/test_zip.py +0 -0
  362. {execsql2-2.29.0 → execsql2-2.30.0}/tests/gui/__init__.py +0 -0
  363. {execsql2-2.29.0 → execsql2-2.30.0}/tests/gui/test_backends_extended.py +0 -0
  364. {execsql2-2.29.0 → execsql2-2.30.0}/tests/gui/test_compare_stats.py +0 -0
  365. {execsql2-2.29.0 → execsql2-2.30.0}/tests/gui/test_compute_row_diffs.py +0 -0
  366. {execsql2-2.29.0 → execsql2-2.30.0}/tests/gui/test_desktop_dialogs.py +0 -0
  367. {execsql2-2.29.0 → execsql2-2.30.0}/tests/gui/test_format_table.py +0 -0
  368. {execsql2-2.29.0 → execsql2-2.30.0}/tests/gui/test_tui_pilot.py +0 -0
  369. {execsql2-2.29.0 → execsql2-2.30.0}/tests/gui/test_tui_pilot_complex.py +0 -0
  370. {execsql2-2.29.0 → execsql2-2.30.0}/tests/gui/test_utils_gui_extended.py +0 -0
  371. {execsql2-2.29.0 → execsql2-2.30.0}/tests/importers/__init__.py +0 -0
  372. {execsql2-2.29.0 → execsql2-2.30.0}/tests/importers/conftest.py +0 -0
  373. {execsql2-2.29.0 → execsql2-2.30.0}/tests/importers/test_base_extended.py +0 -0
  374. {execsql2-2.29.0 → execsql2-2.30.0}/tests/importers/test_csv_blank_lines.py +0 -0
  375. {execsql2-2.29.0 → execsql2-2.30.0}/tests/importers/test_csv_edge_cases.py +0 -0
  376. {execsql2-2.29.0 → execsql2-2.30.0}/tests/importers/test_csv_importer.py +0 -0
  377. {execsql2-2.29.0 → execsql2-2.30.0}/tests/importers/test_feather_importer.py +0 -0
  378. {execsql2-2.29.0 → execsql2-2.30.0}/tests/importers/test_json_importer.py +0 -0
  379. {execsql2-2.29.0 → execsql2-2.30.0}/tests/importers/test_ods_importer.py +0 -0
  380. {execsql2-2.29.0 → execsql2-2.30.0}/tests/importers/test_roundtrip_csv.py +0 -0
  381. {execsql2-2.29.0 → execsql2-2.30.0}/tests/importers/test_xls_importer.py +0 -0
  382. {execsql2-2.29.0 → execsql2-2.30.0}/tests/integration/__init__.py +0 -0
  383. {execsql2-2.29.0 → execsql2-2.30.0}/tests/integration/conftest.py +0 -0
  384. {execsql2-2.29.0 → execsql2-2.30.0}/tests/integration/test_dsn.py +0 -0
  385. {execsql2-2.29.0 → execsql2-2.30.0}/tests/integration/test_duckdb.py +0 -0
  386. {execsql2-2.29.0 → execsql2-2.30.0}/tests/integration/test_mysql.py +0 -0
  387. {execsql2-2.29.0 → execsql2-2.30.0}/tests/integration/test_postgres.py +0 -0
  388. {execsql2-2.29.0 → execsql2-2.30.0}/tests/integration/test_sqlite.py +0 -0
  389. {execsql2-2.29.0 → execsql2-2.30.0}/tests/live_db.py +0 -0
  390. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/__init__.py +0 -0
  391. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/test_code_actions.py +0 -0
  392. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/test_completion.py +0 -0
  393. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/test_diagnostics.py +0 -0
  394. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/test_folding.py +0 -0
  395. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/test_formatting.py +0 -0
  396. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/test_hover.py +0 -0
  397. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/test_lsp_command.py +0 -0
  398. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/test_navigation.py +0 -0
  399. {execsql2-2.29.0 → execsql2-2.30.0}/tests/lsp/test_rename.py +0 -0
  400. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/__init__.py +0 -0
  401. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_assert.py +0 -0
  402. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_breakpoint.py +0 -0
  403. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_conditions_extra.py +0 -0
  404. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_connect.py +0 -0
  405. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_io_export.py +0 -0
  406. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_io_import.py +0 -0
  407. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_metacommands_connect.py +0 -0
  408. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_metacommands_data.py +0 -0
  409. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
  410. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_metacommands_io.py +0 -0
  411. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
  412. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_metacommands_system.py +0 -0
  413. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_metacommands_system_extra.py +0 -0
  414. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_pg_upsert.py +0 -0
  415. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_prompt.py +0 -0
  416. {execsql2-2.29.0 → execsql2-2.30.0}/tests/metacommands/test_show_scripts.py +0 -0
  417. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/__init__.py +0 -0
  418. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/audit_lint_bad.sql +0 -0
  419. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/audit_smoke/sample.json +0 -0
  420. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/audit_smoke/sample.jsonl +0 -0
  421. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/audit_smoke.sql +0 -0
  422. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/config_runtime.sql +0 -0
  423. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/control_flow.sql +0 -0
  424. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/counters_and_locals.sql +0 -0
  425. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/error_handling.sql +0 -0
  426. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/import_options/has_comments.csv +0 -0
  427. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/import_options.sql +0 -0
  428. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/includes/helper.sql +0 -0
  429. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/includes.sql +0 -0
  430. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/io_formats.sql +0 -0
  431. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
  432. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/multi_db.sql +0 -0
  433. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/parquet_feather_roundtrip.sql +0 -0
  434. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/parse_only/parse_tree.sql +0 -0
  435. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/predicates.sql +0 -0
  436. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/scripts.sql +0 -0
  437. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/smoke.sql +0 -0
  438. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/subroutine_loops.sql +0 -0
  439. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/subvars_advanced.sql +0 -0
  440. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/template_export/greeting.tmpl +0 -0
  441. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/template_export.sql +0 -0
  442. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/timer.sql +0 -0
  443. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/transactions.sql +0 -0
  444. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/write_create_table.sql +0 -0
  445. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/fixtures/xlsx_ods_roundtrip.sql +0 -0
  446. {execsql2-2.29.0 → execsql2-2.30.0}/tests/scripts/test_sql_scripts.py +0 -0
  447. {execsql2-2.29.0 → execsql2-2.30.0}/tests/security/__init__.py +0 -0
  448. {execsql2-2.29.0 → execsql2-2.30.0}/tests/security/test_expansion_bomb.py +0 -0
  449. {execsql2-2.29.0 → execsql2-2.30.0}/tests/security/test_import_regex_hardening.py +0 -0
  450. {execsql2-2.29.0 → execsql2-2.30.0}/tests/security/test_odbc_injection.py +0 -0
  451. {execsql2-2.29.0 → execsql2-2.30.0}/tests/security/test_path_containment.py +0 -0
  452. {execsql2-2.29.0 → execsql2-2.30.0}/tests/security/test_substitution_injection.py +0 -0
  453. {execsql2-2.29.0 → execsql2-2.30.0}/tests/security/test_zip_bomb.py +0 -0
  454. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_api.py +0 -0
  455. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_api_errors.py +0 -0
  456. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_api_extended.py +0 -0
  457. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_api_filewriter.py +0 -0
  458. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_api_subprocess.py +0 -0
  459. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_ast.py +0 -0
  460. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_ast_parser.py +0 -0
  461. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_bundled_templates.py +0 -0
  462. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_config.py +0 -0
  463. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_config_extended.py +0 -0
  464. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_date_inference.py +0 -0
  465. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_debug_repl.py +0 -0
  466. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_engine.py +0 -0
  467. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_error_messages.py +0 -0
  468. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_exceptions.py +0 -0
  469. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_executor.py +0 -0
  470. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_format.py +0 -0
  471. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_interactive.py +0 -0
  472. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_mail.py +0 -0
  473. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_models.py +0 -0
  474. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_package.py +0 -0
  475. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_parser.py +0 -0
  476. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_parser_params.py +0 -0
  477. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_plugins.py +0 -0
  478. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_script.py +0 -0
  479. {execsql2-2.29.0 → execsql2-2.30.0}/tests/test_types.py +0 -0
  480. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/__init__.py +0 -0
  481. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_auth.py +0 -0
  482. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_auth_extra.py +0 -0
  483. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_crypto.py +0 -0
  484. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_datetime.py +0 -0
  485. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_encodedfile_context.py +0 -0
  486. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_keyring_rules.py +0 -0
  487. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_mail_tls.py +0 -0
  488. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_numeric.py +0 -0
  489. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_strings.py +0 -0
  490. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_timer.py +0 -0
  491. {execsql2-2.29.0 → execsql2-2.30.0}/tests/utils/test_timer_extra.py +0 -0
  492. {execsql2-2.29.0 → execsql2-2.30.0}/zensical.toml +0 -0
@@ -0,0 +1,57 @@
1
+ name: Bug report
2
+ description: Something execsql does wrong, from the command line, the library, or an editor.
3
+ labels: [bug]
4
+ body:
5
+ - type: textarea
6
+ id: what
7
+ attributes:
8
+ label: What happened
9
+ description: What you ran, what you expected, and what happened instead.
10
+ placeholder: |
11
+ `execsql run load.sql prod.db -t l` stopped at line 12 with ...
12
+ I expected ...
13
+ validations:
14
+ required: true
15
+ - type: textarea
16
+ id: script
17
+ attributes:
18
+ label: A script that shows it
19
+ description: The smallest script that reproduces the problem, if you can share one. Leave out data and credentials.
20
+ render: sql
21
+ - type: textarea
22
+ id: output
23
+ attributes:
24
+ label: Error output
25
+ description: The full message or traceback, and the end of `execsql.log` if the run wrote one.
26
+ render: text
27
+ - type: input
28
+ id: version
29
+ attributes:
30
+ label: execsql version
31
+ description: The output of `execsql --version`.
32
+ placeholder: execsql 2.30.0
33
+ validations:
34
+ required: true
35
+ - type: input
36
+ id: install
37
+ attributes:
38
+ label: How execsql is installed
39
+ description: The command, with its extras.
40
+ placeholder: uv tool install "execsql2[postgres,lsp]"
41
+ validations:
42
+ required: true
43
+ - type: input
44
+ id: environment
45
+ attributes:
46
+ label: Operating system, Python and database
47
+ placeholder: macOS 15, Python 3.12, PostgreSQL 16
48
+ validations:
49
+ required: true
50
+ - type: textarea
51
+ id: editor
52
+ attributes:
53
+ label: Editor and language server (only for a problem in an editor)
54
+ description: |
55
+ The editor and the execsql extension's version, the output of `execsql lsp --check`, and the server's log
56
+ at `info` (VS Code: View → Output → execsql). See https://execsql2.readthedocs.io/en/latest/guides/editors/#troubleshooting
57
+ render: text
@@ -0,0 +1,28 @@
1
+ name: Feature request
2
+ description: A new feature, metacommand or option, or a change to how something works.
3
+ labels: [enhancement]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: The problem
9
+ description: What you are trying to do, and what gets in the way today.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposal
14
+ attributes:
15
+ label: What you would like
16
+ description: For a new metacommand or CLI option, the syntax you would expect.
17
+ placeholder: "-- !x! NEW_METACOMMAND ..."
18
+ validations:
19
+ required: true
20
+ - type: textarea
21
+ id: alternatives
22
+ attributes:
23
+ label: Alternatives and workarounds
24
+ description: What you tried instead, if anything.
25
+ - type: textarea
26
+ id: context
27
+ attributes:
28
+ label: Anything else
@@ -51,25 +51,6 @@ jobs:
51
51
  - run: uv sync --locked --all-extras
52
52
  - run: uv run --no-sync mypy src/execsql/
53
53
 
54
- formatter-corpus:
55
- name: formatter-corpus
56
- runs-on: ubuntu-latest
57
- permissions:
58
- contents: read
59
- steps:
60
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
61
- - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
62
- with:
63
- python-version: "3.13"
64
- cache: "pip"
65
- - run: python -m pip install --upgrade pip
66
- - run: python -m pip install ".[dev]"
67
- # Every formatter bug to date came from real SQL containing a
68
- # construct the project's own scripts lack. This gate runs those
69
- # checks under their own name so a corpus failure is legible
70
- # without reading a 6,000-test log.
71
- - run: pytest tests/test_format.py -k corpus --no-cov -q
72
-
73
54
  typer-floor:
74
55
  name: typer-floor
75
56
  runs-on: ubuntu-latest
@@ -155,7 +136,8 @@ jobs:
155
136
  - run: python -m pip install --upgrade pip
156
137
  - run: python -m pip install ".[dev]"
157
138
  - run: cp CHANGELOG.md docs/about/change_log.md
158
- - run: zensical build
139
+ # --strict: a warning, such as a link to an #anchor that does not exist, fails the job.
140
+ - run: zensical build --strict
159
141
 
160
142
  tests:
161
143
  strategy:
@@ -369,7 +351,7 @@ jobs:
369
351
  build:
370
352
  name: Build distribution 📦
371
353
  runs-on: ubuntu-latest
372
- needs: [ lint, typecheck, pre-commit, formatter-corpus, typer-floor, docs, tests, integration-tests, vscode-extension ]
354
+ needs: [ lint, typecheck, pre-commit, typer-floor, docs, tests, integration-tests, vscode-extension ]
373
355
  # Deliberately NOT gated on tags: packaging breaks must surface on a PR,
374
356
  # not at release time. Only publish/generate-release below are tag-gated.
375
357
  permissions:
@@ -13,6 +13,36 @@ ______________________________________________________________________
13
13
 
14
14
  ______________________________________________________________________
15
15
 
16
+ ## [2.30.0] - 2026-10-14
17
+
18
+ ### Added
19
+
20
+ - **`execsql lsp --log-level` and `--log-file`** (or `EXECSQL_LSP_LOG_LEVEL`): at `info` the server logs its version, the Python running it, whether the formatter is installed, the workspace folders and the config files each folder read; `debug` adds every protocol message. See [Troubleshooting](https://execsql2.readthedocs.io/en/latest/guides/editors/#troubleshooting) for what to include in a bug report.
21
+ - **VS Code extension:** the **execsql** Output channel shows the server's log (setting `execsql.server.logLevel`, default `info`) and why the server did not start; `execsql.trace.server` traces the protocol there.
22
+
23
+ ### Fixed
24
+
25
+ - **`execsql lint` checks every file** when one has an `INCLUDE` path the operating system rejects (such as a name too long for it): that file gets an I001 finding instead of the whole run stopping with "Uncaught exception", and a script lint cannot check at all is reported as one P001 error.
26
+ - **The language server shows "execsql could not check this script"** when checking a script fails unexpectedly, instead of keeping its old findings; hover, completion and navigation keep working for a script with such an `INCLUDE`.
27
+ - **The language server answers quickly in a script with many or large `INCLUDE`s:** completion, hover, go-to-definition and the other features no longer reread and reparse every included file on each request (50 included 3,000-line files: about 0.55 s per keystroke before, under 20 ms now). A changed included file is read again.
28
+ - **The language server lints less after a save:** saving a script, or a change to a `.sql` file on disk, lints again only the open scripts that `INCLUDE` that file, once, instead of every open script two or three times.
29
+ - **`execsql --help` shows each command's whole summary**, wrapped to the terminal, instead of cutting it off with `...` on a narrow one.
30
+ - **DuckDB temporary tables last for the whole run:** a table created with `CREATE TEMPORARY TABLE` is visible to the statements and metacommands after it (`INSERT`, `EXPORT`, `COPY`, conditions); before, it was gone by the next statement.
31
+ - **A `--dsn` / `dsn=` value without a scheme** (`//user:password@host/db`) is reported with its password as `***` instead of in full.
32
+ - **`--manifest` masks passwords and tokens:** a password, `SUB_DECRYPT` result or token (a URL's password, `password=...`, an API key) that reaches a file path, connection target or error message is written as `***`. `-a` and `--var` values are still written where a path uses them.
33
+ - **A registered secret no longer reaches `execsql.log` through a `HALT MESSAGE`** (the `exit` record of a halted run), an exported file name (`action` records) or a connection name (`connect` records); these now show `***` like every other log record.
34
+ - **`execsql.run()` returns the caller to their working directory** after a script that ran `CD`, including when the script fails; before, the caller was left in the script's last directory.
35
+ - **Language server settings for a workspace folder added after the first folder was deleted** are read; before, every later settings reload failed and the folder linted with stale rules. An unsaved script's relative `INCLUDE` resolves against the workspace root.
36
+ - **VS Code extension:** after `CONFIG`, only options `CONFIG` accepts are highlighted; config-file-only keys such as `DB_FILE`, `CONSOLE_HEIGHT` or `CSS_FILE` (which `CONFIG` rejects) no longer look valid.
37
+ - **VS Code extension:** turning `execsql.server.enabled` on or off, or changing `execsql.server.path`, takes effect without reloading the window; **execsql: Restart Language Server** works (and says so) when the server is off, and two quick restarts no longer leave a second server running.
38
+
39
+ ### Removed
40
+
41
+ - **Unused helpers:** `execsql.gui.get_backend()` (the GUI picks its backend in `enable_gui()`), `ins_quoted_rx()` (re-exported from `execsql.metacommands`; nothing built a metacommand with it) `execsql.utils.errors.exception_info()` (use `exception_desc()`), and the `execsql.cli.main` re-export (the run command's own module, `execsql.cli.commands.run`, keeps it).
42
+ - **`execsql.utils.fileio`:** `filewriter_closeall()`, `filewriter_shutdown()` and `list_encodings()`, which nothing called; use `filewriter_end()` to stop a writer and `execsql list encodings` for the encodings. `FileWriter.ping()` is gone too.
43
+
44
+ ______________________________________________________________________
45
+
16
46
  ## [2.29.0] - 2026-10-13
17
47
 
18
48
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: execsql2
3
- Version: 2.29.0
3
+ Version: 2.30.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
@@ -83,7 +83,6 @@ Provides-Extra: auth-plaintext
83
83
  Requires-Dist: keyring>=25.0; extra == 'auth-plaintext'
84
84
  Requires-Dist: keyrings-alt>=5.0; extra == 'auth-plaintext'
85
85
  Provides-Extra: dev
86
- Requires-Dist: build>=1.2.2.post1; extra == 'dev'
87
86
  Requires-Dist: bump-my-version>=1.2.7; extra == 'dev'
88
87
  Requires-Dist: defusedxml>=0.7; extra == 'dev'
89
88
  Requires-Dist: jinja2>=3.1; extra == 'dev'
@@ -104,7 +103,6 @@ Requires-Dist: ruff>=0.4; extra == 'dev'
104
103
  Requires-Dist: sqlglot<30.22,>=30.21.0; extra == 'dev'
105
104
  Requires-Dist: tables>=3.10; extra == 'dev'
106
105
  Requires-Dist: tox-uv>=1.13.1; extra == 'dev'
107
- Requires-Dist: twine>=6.1.0; extra == 'dev'
108
106
  Requires-Dist: xlrd>=2.0; extra == 'dev'
109
107
  Requires-Dist: zensical==0.0.67; extra == 'dev'
110
108
  Provides-Extra: duckdb
@@ -466,7 +464,7 @@ execsql format --no-sql --in-place scripts/
466
464
  ```yaml
467
465
  repos:
468
466
  - repo: https://github.com/geocoug/execsql
469
- rev: v2.29.0
467
+ rev: v2.30.0
470
468
  hooks:
471
469
  - id: execsql-format
472
470
  - id: execsql-lint
@@ -321,7 +321,7 @@ execsql format --no-sql --in-place scripts/
321
321
  ```yaml
322
322
  repos:
323
323
  - repo: https://github.com/geocoug/execsql
324
- rev: v2.29.0
324
+ rev: v2.30.0
325
325
  hooks:
326
326
  - id: execsql-format
327
327
  - id: execsql-lint
@@ -28,7 +28,7 @@ ______________________________________________________________________
28
28
  | `--dry-run` | Parse the script and print the full command list without connecting to a database or executing anything. Substitution variables already populated at parse time (env vars, `--assign-arg` values, built-in start-time vars) are expanded in the output; execution-time variables (`$DB_NAME`, `$CURRENT_TIME`, etc.) remain unexpanded. |
29
29
  | `--profile` | Record wall-clock time for each SQL and metacommand statement. After the script completes, print a summary table sorted by elapsed time (descending), showing time, percentage of total, source location, command type, and a command preview. |
30
30
  | `--profile-limit N` | Number of top statements to display in the `--profile` summary (default: 20). Remaining statements are counted and noted in the output footer. |
31
- | `--manifest FILE` | Write a JSON record of the run when it ends, even on failure: script, database, statement counts, files read, written and deleted (paths after substitution), connections, errors. Variable values and passwords are never written. |
31
+ | `--manifest FILE` | Write a JSON record of the run when it ends, even on failure: script, database, statement counts, files read, written and deleted (paths after substitution), connections, errors. Variable values are never listed; passwords, decrypted values and token shapes are masked as `***` wherever they appear. |
32
32
  | `--ping` | Test database connectivity and exit. Connects using the supplied connection parameters, queries for the server version, and prints a one-line success message (exit 0) or the error (exit 1). No script file argument is required. |
33
33
  | `--lint` | Removed. Replaced by `execsql lint`, which takes files and directories and adds rule selection and JSON output. `execsql run --lint` now exits 2 with `run --lint was removed; use execsql lint` and never runs the script. |
34
34
  | `--parse-tree` | Parse the script into an Abstract Syntax Tree and print a visual tree showing block nesting (IF/LOOP/BATCH/SCRIPT), source line ranges, compound conditions (ANDIF/ORIF), and all metacommands. Does not connect to a database or execute anything. Useful for understanding script structure and verifying the parser handles a script correctly. |
@@ -205,7 +205,7 @@ result = run(
205
205
  result.raise_on_error()
206
206
  ```
207
207
 
208
- Accepts `dsn=` or a pre-built `connection=` `Database` object. Each call runs in its own thread-local `RuntimeContext` with its own file-writer thread, so concurrent calls from different threads are safe and a halt in one does not stop another's file output. `halt_on_error=False` collects errors instead of raising.
208
+ Accepts `dsn=` or a pre-built `connection=` `Database` object. Each call runs in its own thread-local `RuntimeContext` with its own file-writer thread, so concurrent calls from different threads are safe and a halt in one does not stop another's file output. `halt_on_error=False` collects errors instead of raising. A script's `CD` lasts until `run()` returns, which then changes back to the caller's directory.
209
209
 
210
210
  ______________________________________________________________________
211
211
 
@@ -267,7 +267,8 @@ All 33 mutable runtime globals in `state.py` have been consolidated into a `Runt
267
267
  - **DuckDB temporal types** — `TIMESTAMPTZ`, `TIMESTAMP`, `DATE`, `TIME` now map to native DuckDB types instead of `TEXT`.
268
268
  - **SQLite `DT_Long` mapping** — `DT_Long` maps to `"hugeint"` in the SQLite type table. SQLite does not have a native `HUGEINT` type; the value receives `TEXT` affinity. In practice this is harmless because SQLite's type affinity system handles large integers transparently, but the mapping name differs from upstream.
269
269
  - **`Database.auto_commits_ddl()` not provided** — 2.18.0 shipped this capability hook on the base `Database` class with `True` overrides on Oracle, MySQL, SQL Server, and MS Access. No call site ever consumed the hook, so 2.19.0 removed it. Its replacement is `Database.implicit_commit_rx`: MySQL and Oracle name the statements their server commits on its own (DDL), and a warning is written when one runs while `AUTOCOMMIT` is `OFF` or a batch is open. SQL Server holds DDL in a transaction like any other statement. (The companion hook `Database.needs_explicit_commit_after_ddl()`, used by the Firebird import path, remains.)
270
- - **Statements are held until commit on every adapter** — while `AUTOCOMMIT` is `OFF` or a batch is open, `Database.before_statement()` makes sure each statement is inside a transaction. Most drivers already opened one; SQLite's (Python's `sqlite3`) opened one only before `INSERT`/`UPDATE`/`DELETE`/`REPLACE`, and DuckDB's never did, so upstream committed SQLite DDL, and every DuckDB statement, at once. SQLite now begins a transaction before other statements (except `VACUUM`, `ATTACH`, `DETACH`, `PRAGMA`); DuckDB begins one itself, tracks it, and runs statements on the connection rather than on cursors while it is open, since a DuckDB cursor is a separate connection with its own transaction.
270
+ - **Statements are held until commit on every adapter** — while `AUTOCOMMIT` is `OFF` or a batch is open, `Database.before_statement()` makes sure each statement is inside a transaction. Most drivers already opened one; SQLite's (Python's `sqlite3`) opened one only before `INSERT`/`UPDATE`/`DELETE`/`REPLACE`, and DuckDB's never did, so upstream committed SQLite DDL, and every DuckDB statement, at once. SQLite now begins a transaction before other statements (except `VACUUM`, `ATTACH`, `DETACH`, `PRAGMA`); DuckDB begins one itself and tracks it.
271
+ - **DuckDB statements share one connection** — a DuckDB cursor is a separate connection with its own transaction and its own temporary tables, and upstream ran each statement on a new cursor, so a `CREATE TEMPORARY TABLE` was gone by the next statement and a held transaction did not cover them. Every statement now runs on the database's one connection. That connection holds one result at a time, so when a statement runs while another query's rows are still being read (`COPY` scans its source while reading it), the unread rows are fetched into memory first; an `EXPORT` still streams.
271
272
  - **DuckDB `$LAST_ROWCOUNT`** — the duckdb driver's `rowcount` is always `-1`; DuckDB answers an `INSERT`, `UPDATE` or `DELETE` with a one-column `Count` result instead. The DuckDB adapter reads that result, so `$LAST_ROWCOUNT` holds the rows changed, as on the other adapters. Upstream set it to `-1`.
272
273
 
273
274
  ### Execution Engine
@@ -279,7 +280,6 @@ The legacy flat command-list engine (`_parse_script_lines` / `runscripts` / `Com
279
280
  - **BREAK outside LOOP is an error** — `BREAK` outside a loop block now raises an error (exit 1) instead of being silently ignored. This catches script bugs that upstream would not report.
280
281
  - **File writer is a thread, one per run** — `WRITE`, `TEE` and the other text-file metacommands hand their output to a background thread owned by the run's `RuntimeContext`, which `execsql.run()` stops before returning. Upstream uses one `multiprocessing` subprocess for the whole program; under the `spawn` start method (macOS, Windows) that re-imported the calling program, so a library caller without an `if __name__ == "__main__":` guard ran its script twice.
281
282
  - **Instance-scoped script registry** — Named SCRIPT blocks are stored on the `RuntimeContext` instance instead of a module-level dict, preventing cross-execution contamination.
282
- - **Script source directory resolution** — `ScriptCmd` resolves `source_dir` at construction time (when the command is parsed) rather than per-statement at execution time. This is functionally equivalent for all normal usage since the script file does not move between parse and execution.
283
283
 
284
284
  ### Error Handling
285
285
 
@@ -322,13 +322,13 @@ These are behavioral changes driven by security or correctness issues in the ups
322
322
 
323
323
  ### Credential and Logging Safety
324
324
 
325
- | Area | Fix |
326
- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
327
- | ODBC password redaction | Connection strings in log output have `Pwd=***` substituted before logging. |
328
- | `enc_password` documentation | Prominent warnings that XOR encryption is obfuscation only — keys are hardcoded in source. |
329
- | Env-var secret denylist | Extended `_SENSITIVE_SUBSTRINGS` to cover mainstream cloud / payment / observability / VCS conventions (`*_KEY`, `APIKEY`, `API_KEY`, `DSN`, `WEBHOOK`). `-a` positional assignment log lines now redact unconditionally (`{***}` instead of the raw value). |
330
- | Secrets registered at source | The `run` record lists a count of `-a` values instead of the values (upstream wrote them in clear). DSN and SMTP passwords, prompted and keyring database passwords, `PROMPT ENTER_SUB ... PASSWORD` and `PROMPT CREDENTIALS` values, and `SUB_DECRYPT` results are registered for redaction, so SQL logged with `LOG_SQL ON`, `SYSTEM_CMD` echoes and error messages show `***`. |
331
- | SMTP certificate verification | `EMAIL` over `use_ssl` or `use_tls` verifies the server certificate (upstream accepted any certificate, so the SMTP password could go to an impostor). New `[email]` settings: `ca_file` to trust an internal CA, `verify_certificate = No` to turn the check off. |
325
+ | Area | Fix |
326
+ | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
327
+ | ODBC password redaction | Connection strings in log output have `Pwd=***` substituted before logging. |
328
+ | `enc_password` documentation | Prominent warnings that XOR encryption is obfuscation only — keys are hardcoded in source. |
329
+ | Env-var secret denylist | Extended `_SENSITIVE_SUBSTRINGS` to cover mainstream cloud / payment / observability / VCS conventions (`*_KEY`, `APIKEY`, `API_KEY`, `DSN`, `WEBHOOK`). `-a` positional assignment log lines now redact unconditionally (`{***}` instead of the raw value). |
330
+ | Secrets registered at source | The `run` record lists a count of `-a` values instead of the values (upstream wrote them in clear). DSN and SMTP passwords, prompted and keyring database passwords, `PROMPT ENTER_SUB ... PASSWORD` and `PROMPT CREDENTIALS` values, and `SUB_DECRYPT` results are registered for redaction, so SQL logged with `LOG_SQL ON`, `SYSTEM_CMD` echoes, error messages, the `exit` record (including a `HALT MESSAGE`), `action` export records and `connect` records show `***`. |
331
+ | SMTP certificate verification | `EMAIL` over `use_ssl` or `use_tls` verifies the server certificate (upstream accepted any certificate, so the SMTP password could go to an impostor). New `[email]` settings: `ca_file` to trust an internal CA, `verify_certificate = No` to turn the check off. |
332
332
 
333
333
  ### Bug Fixes
334
334
 
@@ -80,7 +80,7 @@ Each run has its own [file writer](#file-output), so two runs writing files at t
80
80
 
81
81
  Three things are still shared by every thread in the process, so keep them apart yourself:
82
82
 
83
- - **The working directory.** `CD` calls `os.chdir()`, which moves every thread. Use absolute paths in scripts that run concurrently, or don't use `CD` in them.
83
+ - **The working directory.** `CD` calls `os.chdir()`, which moves every thread while the script runs. Use absolute paths in scripts that run concurrently, or don't use `CD` in them. When a script that ran `CD` finishes, `run()` changes back to the directory it was in before that `CD`, so the caller ends where it started; a run without `CD` leaves the directory as it finds it.
84
84
  - **The same output file.** Two runs writing one file at the same time can interleave their lines. Give each run its own output paths.
85
85
  - **Interactive prompts.** `PROMPT` and the other GUI metacommands are not meant to be driven from several threads at once.
86
86
 
@@ -56,6 +56,8 @@ flowchart LR
56
56
  UTILS["utils/<br/>auth, crypto,<br/>fileio, mail,<br/>regex, strings"]
57
57
  PARSER["parser.py<br/>CondParser,<br/>NumericParser"]
58
58
  DEBUG["debug/<br/>REPL debugger"]
59
+ LSP["lsp/<br/>execsql lsp,<br/>editor features"]
60
+ REF["metacommands/<br/>reference.py<br/>syntax registry"]
59
61
 
60
62
  CLI --> CONFIG
61
63
  CLI --> STATE
@@ -75,35 +77,66 @@ flowchart LR
75
77
  EXPORT --> STATE
76
78
  GUI --> STATE
77
79
  SCRIPT --> PARSER
80
+ CLI --> LSP
81
+ LSP --> SCRIPT
82
+ LSP --> REF
83
+ LSP --> CLI
78
84
  ```
79
85
 
80
86
  ### Package summary
81
87
 
82
- | Package | Purpose |
83
- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
84
- | `cli/` | Typer app and help rendering, one module per command under `cli/commands/`, shared options, `_run()` orchestration, DSN URL parsing |
85
- | `api.py` | Public `execsql.run()` Python entry point for notebooks, pipelines, and library use |
86
- | `config.py` | `ConfigData` (INI merging), `StatObj` (runtime flags), `WriteHooks` (stdout/stderr redirection) |
87
- | `state.py` | Thread-local runtime store — all shared mutable state lives here, isolated per-thread |
88
- | `script/` | AST node types, parser, `MetaCommandList`, `SubVarSet`, `BatchLevels`, `ScriptExecSpec`, `set_system_vars()` |
89
- | `metacommands/` | `build_dispatch_table()`, all `x_*` handlers, `build_conditional_table()`, all `xf_*` predicates |
90
- | `db/` | `Database` ABC, `DatabasePool`, 9 adapter modules (postgres, sqlite, duckdb, mysql, sqlserver, oracle, firebird, access, dsn) |
91
- | `exporters/` | `ExportRecord`, `ExportMetadata`, `WriteSpec`, 20+ format writers (CSV, JSON, XML, HTML, etc.) |
92
- | `importers/` | `CsvFile`, `OdsFile`, `XlsFile`, `FeatherFile` — data import backends |
93
- | `gui/` | `GuiBackend` ABC, `TkinterBackend`, `TextualBackend`, `ConsoleBackend` |
94
- | `utils/` | Shared utilities: file I/O, encryption, mail, regex helpers, string manipulation, timers |
95
- | `parser.py` | Recursive-descent parsers for conditional (`IF`) and arithmetic (`SET`) expressions |
96
- | `types.py` | `DataType` subclasses and `DbType` per-DBMS type dialect mappings |
97
- | `models.py` | `Column`, `DataTable`, `JsonDatatype` |
98
- | `format.py` | `execsql format` formatter — opinionated formatter for execsql scripts |
99
- | `exceptions.py` | `ExecSqlError` base, `ErrInfo`, `ConfigError`, `DataTypeError`, `DbTypeError`, etc. |
100
- | `plugins.py` | Entry-point plugin discovery for metacommands, exporters, and importers |
101
- | `debug/` | Interactive REPL debugger for stepping through script execution |
102
- | `interactive.py` | Engine behind the debug REPL: input typed at a BREAKPOINT runs as the next lines of the paused script via `executor.execute_input`; errors return to the prompt |
103
- | `data/` | Bundled package data (`execsql.conf.template` powers `execsql config --init`) |
88
+ | Package | Purpose |
89
+ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
90
+ | `cli/` | Typer app and help rendering, one module per command under `cli/commands/`, shared options, `_run()` orchestration, DSN URL parsing |
91
+ | `api.py` | Public `execsql.run()` Python entry point for notebooks, pipelines, and library use |
92
+ | `config.py` | `ConfigData` (INI merging), `StatObj` (runtime flags), `WriteHooks` (stdout/stderr redirection) |
93
+ | `state.py` | Thread-local runtime store — all shared mutable state lives here, isolated per-thread |
94
+ | `script/` | AST node types, parser, `MetaCommandList`, `SubVarSet`, `BatchLevels`, `ScriptExecSpec`, `set_system_vars()` |
95
+ | `metacommands/` | `build_dispatch_table()`, all `x_*` handlers, `build_conditional_table()`, all `xf_*` predicates |
96
+ | `db/` | `Database` ABC, `DatabasePool`, 9 adapter modules (postgres, sqlite, duckdb, mysql, sqlserver, oracle, firebird, access, dsn) |
97
+ | `exporters/` | `ExportRecord`, `ExportMetadata`, `WriteSpec`, 20+ format writers (CSV, JSON, XML, HTML, etc.) |
98
+ | `importers/` | `CsvFile`, `OdsFile`, `XlsFile`, `FeatherFile` — data import backends |
99
+ | `gui/` | `GuiBackend` ABC, `TkinterBackend`, `TextualBackend`, `ConsoleBackend` |
100
+ | `utils/` | Shared utilities: file I/O, encryption, mail, regex helpers, string manipulation, timers |
101
+ | `parser.py` | Recursive-descent parsers for conditional (`IF`) and arithmetic (`SET`) expressions |
102
+ | `types.py` | `DataType` subclasses and `DbType` per-DBMS type dialect mappings |
103
+ | `models.py` | `Column`, `DataTable`, `JsonDatatype` |
104
+ | `format.py` | `execsql format` formatter — opinionated formatter for execsql scripts |
105
+ | `exceptions.py` | `ExecSqlError` base, `ErrInfo`, `ConfigError`, `DataTypeError`, `DbTypeError`, etc. |
106
+ | `plugins.py` | Entry-point plugin discovery for metacommands, exporters, and importers |
107
+ | `debug/` | Interactive REPL debugger for stepping through script execution |
108
+ | `interactive.py` | Engine behind the debug REPL: input typed at a BREAKPOINT runs as the next lines of the paused script via `executor.execute_input`; errors return to the prompt |
109
+ | `lsp/` | `execsql lsp`, the language server editors start (pygls 2): diagnostics, completion, hover, navigation, rename, folding, quick fixes, Format Document. See [Language Server](#language-server) |
110
+ | `manifest.py` | `RunManifest`: the JSON record `--manifest FILE` writes when a run ends (script, database, statements, files read/written/deleted, connections, outcome) |
111
+ | `config_validation.py` | `execsql config --validate`: reads the same config files as a run and reports every problem with its file and line |
112
+ | `data/` | Bundled package data (`execsql.conf.template` powers `execsql config --init`) |
104
113
 
105
114
  ______________________________________________________________________
106
115
 
116
+ ## Language Server { #language-server }
117
+
118
+ `execsql lsp` (`cli/commands/lsp.py` → `lsp/server.py:create_server()`) is a pygls 2 server on stdin/stdout. It never runs a script or connects to a database: it reuses the static tools.
119
+
120
+ | Module | Feature | Reuses |
121
+ | ------------------------------------------ | ------------------------------------------------------- | ------------------------------------------------------------------ |
122
+ | `server.py` | handlers, settings, debounced lint, watched files | `cli.run._tool_config` |
123
+ | `diagnostics.py` | lint findings as LSP diagnostics | `cli.lint.lint_source` |
124
+ | `document.py` | `ScriptIndex`: definitions, references, `INCLUDE` graph | `script.parser`, `cli.lint.variables_defined_by` |
125
+ | `cache.py` | each text's `FileFacts`, included files' text | `document` |
126
+ | `_util.py` | `span()`, `markdown()`, the metacommand-line regex | `lsprotocol` |
127
+ | `completion.py`, `hover.py` | completion and hover | `metacommands.reference` |
128
+ | `navigation.py`, `rename.py`, `folding.py` | definition, references, outline, links, rename, folding | `ScriptIndex`, the parser |
129
+ | `code_actions.py` | quick fixes for P002, P003, P004, V001 | the dispatch table (each fix is re-validated before it is offered) |
130
+ | `formatting.py` | Format Document | `format.format_file` with the `[format]` settings |
131
+
132
+ **Settings per workspace folder.** `ConfigData(start_dir=...)` (through `_tool_config(None, start_dir=folder)`) reads config as a run started in that directory would: its `execsql.conf`, and relative `config_file` chains resolved against it. `load_settings()` reads each folder's `[lint]` / `[format]` settings that way and keeps them by folder; a document uses its innermost folder's settings, a document in no folder those of the workspace root (`base_dir()`, or the server's working directory when there is no root or it is gone). The server never changes its working directory. An unsaved script's relative `INCLUDE` resolves against `base_dir()` too, for both lint (`lint_source(base_dir=...)`) and the index.
133
+
134
+ **Index lifetime.** A `ScriptIndex` is assembled on every request that needs one (hover, completion, definition, references, rename, links, code actions) from per-file `FileFacts`: what one file defines, calls, includes and refers to, independent of the files it includes. `lsp/cache.py` keeps each text's facts and each included file's text (by path, size and modification time, dropped when the client reports the file changed), so a request reparses only the edited buffer; a file with a `SUB_INI` is reparsed every time, since its INI file can change on its own. `INCLUDE`d files are read too (the editor's unsaved copy when the file is open), up to 200 files, 10 MiB each and 20 MiB together, regular files only; `SUB_INI` files at most 1 MiB, cached by path, size and modification time.
135
+
136
+ **Linting.** On open, and 200 ms after the last edit (`LINT_DELAY_SECONDS`), lint runs on the document and the result is published with the document's version. A change to a watched `**/execsql.conf` reloads the settings and relints every open document. Saving a script, or a change to a watched `**/*.sql`, relints only the open documents that are that file or `INCLUDE` it directly: lint reads no included file's text, it only checks that each exists. Both go through the same debounce, so the editor's `didSave` and its watcher's report of the same save lint once.
137
+
138
+ **Trust.** The server reads the files the workspace names, so the VS Code client (`extras/vscode-execsql/extension.js`) starts it only in a trusted workspace, resolves `execsql` through `PATH` (never from the open folder) and runs it from the home directory. Plugins load from the server's own Python environment, not from the workspace.
139
+
107
140
  ## AST Parser and Executor
108
141
 
109
142
  execsql2 parses scripts into an AST and walks the tree to execute. There is no separate flat-command-list engine; the AST executor is the only path.
@@ -157,6 +190,10 @@ ______________________________________________________________________
157
190
 
158
191
  Metacommands are lines in SQL scripts prefixed with `-- !x!`. At import time, `metacommands/__init__.py` calls `build_dispatch_table()`, which populates a `MetaCommandList` with all `mcl.add()` registrations (~225 regex patterns). This singleton is stored as `_state.metacommandlist`.
159
192
 
193
+ ### The syntax registry
194
+
195
+ `metacommands/reference.py` describes every metacommand a second way: the syntax forms as the reference docs write them, a one-line summary, a category and the docs anchor. The regex dispatch table decides what *runs*; the registry is what people and editors *read*. `execsql list metacommands`, the language server's completion snippets and hover text come from it. `tests/test_reference.py` checks that every registry form is accepted by the dispatch table, that every dispatch keyword has an entry, and that each anchor exists in `docs/reference/metacommands.md`. A new metacommand therefore needs both: an `mcl.add()` registration and a registry entry.
196
+
160
197
  ### How dispatch works
161
198
 
162
199
  For each `MetaCommandStatement` AST node, the executor calls `_exec_metacommand()` in `script/executor.py`, which delegates to `_state.metacommandlist.eval(cmd_str)`. The dispatcher extracts the leading keyword, narrows ~225 entries to a small candidate set via a keyword index, then tests each candidate's compiled regex against the full command. The matched handler is called with the regex's named groups as keyword arguments plus `metacommandline` (the original unmodified line), and its hit counter is incremented.
@@ -303,19 +340,19 @@ This import pattern (always as `_state`, always accessed inside function/method
303
340
 
304
341
  ### Key state variables
305
342
 
306
- | Variable | Type | Purpose |
307
- | ----------------- | ------------------------ | ---------------------------------------------------------------- |
308
- | `conf` | `ConfigData` | Merged configuration |
309
- | `subvars` | `SubVarSet` | Global substitution variables |
310
- | `ast_exec_stack` | `list[ExecFrame]` | Unified execution stack (scopes + IF/LOOP/BATCH/INCLUDE) |
311
- | `ast_scripts` | `dict[str, ScriptBlock]` | Named scripts from `BEGIN/END SCRIPT` (AST registry) |
312
- | `last_command` | `ScriptCmd \| None` | Most-recently-executed statement; powers `current_script_line()` |
313
- | `dbs` | `DatabasePool` | Open database connections |
314
- | `metacommandlist` | `MetaCommandList` | Metacommand dispatch table |
315
- | `conditionallist` | `MetaCommandList` | Conditional predicate dispatch table |
316
- | `counters` | `CounterVars` | Auto-incrementing counters |
317
- | `filewriter` | `FileWriter` | This run's background file-writing thread |
318
- | `exec_log` | `Logger` | Execution log |
343
+ | Variable | Type | Purpose |
344
+ | ----------------- | ---------------------------- | ---------------------------------------------------------------- |
345
+ | `conf` | `ConfigData` | Merged configuration |
346
+ | `subvars` | `SubVarSet` | Global substitution variables |
347
+ | `ast_exec_stack` | `list[ExecFrame]` | Unified execution stack (scopes + IF/LOOP/BATCH/INCLUDE) |
348
+ | `ast_scripts` | `dict[str, ScriptBlock]` | Named scripts from `BEGIN/END SCRIPT` (AST registry) |
349
+ | `last_command` | `ExecutingStatement \| None` | Most-recently-executed statement; powers `current_script_line()` |
350
+ | `dbs` | `DatabasePool` | Open database connections |
351
+ | `metacommandlist` | `MetaCommandList` | Metacommand dispatch table |
352
+ | `conditionallist` | `MetaCommandList` | Conditional predicate dispatch table |
353
+ | `counters` | `CounterVars` | Auto-incrementing counters |
354
+ | `filewriter` | `FileWriter` | This run's background file-writing thread |
355
+ | `exec_log` | `Logger` | Execution log |
319
356
 
320
357
  ______________________________________________________________________
321
358
 
@@ -328,7 +365,7 @@ ______________________________________________________________________
328
365
  1. System-wide (platform-dependent)
329
366
  1. User home directory
330
367
  1. Script file directory
331
- 1. Current working directory
368
+ 1. Current working directory (or `start_dir`, when the caller passes one)
332
369
 
333
370
  It exposes all recognized options as attributes (`db_type`, `server`, `db`, `db_file`, `username`, `script_encoding`, `output_encoding`, etc.).
334
371
 
@@ -300,8 +300,8 @@ The options below belong to `run`: `execsql run -tl script.sql mydb.sqlite`.
300
300
  `--version` and `-o`/`--online-help` work on their own (`execsql --version`)
301
301
  and anywhere on a `run` command line.
302
302
  `format` has its own options, described in the [formatter guide](../guides/formatter.md);
303
- `lint`'s are in the [lint rules reference](../reference/lint.md); `lsp`'s (`--check`) in
304
- [Editor Support](../guides/editors.md#install); `config`, `list` and `init` are described
303
+ `lint`'s are in the [lint rules reference](../reference/lint.md); `lsp`'s (`--check`,
304
+ `--log-level`, `--log-file`) in [Editor Support](../guides/editors.md#troubleshooting); `config`, `list` and `init` are described
305
305
  [above](#config_command).
306
306
 
307
307
  ### Connection options
@@ -479,7 +479,7 @@ Valid encoding names can be displayed with `execsql list encodings`. See also [C
479
479
  }
480
480
  ```
481
481
 
482
- Files and connections are recorded as each metacommand succeeds, after variable substitution, so paths are the ones used (`out/west.csv`, not `out/!!region!!.csv`); `INCLUDE`d scripts count as files read. When a run fails, `exit_status` is its exit code and `errors` holds the message, its `type`, `source`, `line` and the failing `command`. `variables` lists the names set with `-a` and `--var`; their values are never written, for the same reason the log hides them, and neither are passwords.
482
+ Files and connections are recorded as each metacommand succeeds, after variable substitution, so paths are the ones used (`out/west.csv`, not `out/!!region!!.csv`); `INCLUDE`d scripts count as files read. When a run fails, `exit_status` is its exit code and `errors` holds the message, its `type`, `source`, `line` and the failing `command`. `variables` lists the names set with `-a` and `--var`, not their values. A password (from `--dsn`, a prompt or the keyring), a `SUB_DECRYPT` result, or a common secret shape (a URL's password, `password=...`, an API token) that ends up in a path, a connection target or an error message is written as `***`. Values given with `-a` and `--var` are kept where a path uses them, as in `out/west.csv`, although the log masks them: keep a secret out of `-a` and `--var` if the manifest is collected.
483
483
 
484
484
  The path is checked before the run starts: if *FILE* cannot be written (its folder is a file, or not writable), `execsql run` exits 2 before any SQL runs.
485
485
 
@@ -101,7 +101,7 @@ underlined line). A fix is offered only when applying it clears the finding.
101
101
  Format Document (VS Code: Shift-Alt-F, or `editor.formatOnSave`) runs
102
102
  [`execsql format`](formatter.md) on the editor's text, with the
103
103
  `[format]` settings of the workspace's configuration (`indent`, `sql`,
104
- `leading_comma`), so the editor, the command line and the `execsql-format`
104
+ `leading_comma`, and [`rewrite_sql`](formatter.md#layout-only)), so the editor, the command line and the `execsql-format`
105
105
  pre-commit hook agree. The editor's own tab-size setting is not used. Only
106
106
  whole documents are formatted, not selections: a statement's indentation
107
107
  depends on the IF, LOOP and SCRIPT blocks around it.
@@ -148,13 +148,18 @@ loads/ (no execsql.conf)
148
148
  an unknown metacommand is reported in `loads/*.sql` but not in
149
149
  `reports/*.sql`. Adding or removing a folder takes effect at once.
150
150
 
151
- The server reads each folder's `execsql.conf` again when it changes, and
152
- lints every open script again when a `.sql` file in the workspace changes or
153
- is saved, so a script sees the variables an edited `INCLUDE` file now defines.
154
- An included file that is open in the editor is read as you have it, saved or
155
- not. This needs an editor that reports file changes to the server (VS Code and
156
- Neovim do); otherwise, and after changing a configuration file outside the
157
- workspace, restart the server.
151
+ The server reads each folder's `execsql.conf` again when it changes (and lints
152
+ every open script with the new settings), and lints an open script again when a
153
+ file it `INCLUDE`s is created, deleted or saved, so a missing-file finding
154
+ clears once the file exists. Completion, hover and go-to-definition always use
155
+ the included files' current text, so a script sees the variables an edited
156
+ `INCLUDE` file now defines. An included file that is open in the editor is read
157
+ as you have it, saved or not. This needs an editor that reports file changes to the server: VS Code
158
+ does, and Neovim does on macOS and Windows. Elsewhere (Neovim on Linux, most
159
+ other clients) saving a script in the editor still relints the scripts that
160
+ include it, but an edit to `execsql.conf`, or a change made outside the editor
161
+ (a `git checkout`, another tool), is picked up only after restarting the server
162
+ (Neovim: `:LspRestart`).
158
163
 
159
164
  The server only reads: it never connects to a database or runs a script, and
160
165
  nothing in the workspace can make it run code. The only code it loads besides
@@ -182,7 +187,8 @@ The setting is a command name looked up in PATH or an absolute path; a relative
182
187
  path is refused. The extension never looks for `execsql` in the open folder,
183
188
  and starts the server from your home directory.
184
189
  After upgrading execsql, run **execsql: Restart Language Server** from the
185
- Command Palette. The extension also highlights execsql syntax; that works
190
+ Command Palette. The server's log is in **View → Output → execsql**
191
+ ([Troubleshooting](#troubleshooting)). The extension also highlights execsql syntax; that works
186
192
  without the server.
187
193
 
188
194
  In a folder you have not marked as trusted
@@ -227,3 +233,45 @@ Any editor with a language server client can use it: configure a server for
227
233
  the `sql` language whose command is `execsql lsp`, run over stdio. Sublime Text
228
234
  (the LSP package), Emacs (eglot or lsp-mode), Zed and JetBrains IDEs (the LSP4IJ
229
235
  plugin) all work this way.
236
+
237
+ ## Troubleshooting { #troubleshooting }
238
+
239
+ **Where the server's log is.** The server writes its log to stderr, which the
240
+ editor keeps:
241
+
242
+ | Editor | Where |
243
+ | ------- | ------------------------------------------------------------------------------------- |
244
+ | VS Code | **View → Output**, then choose **execsql** in the list. Start failures are there too. |
245
+ | Neovim | `:LspLog` (`~/.local/state/nvim/lsp.log`) |
246
+ | Helix | `:log-open` |
247
+
248
+ **How much it logs.** `execsql lsp --log-level` (or the `EXECSQL_LSP_LOG_LEVEL`
249
+ environment variable) takes `error`, `warning` (the default), `info` or `debug`:
250
+
251
+ - `info` adds a startup record and each workspace folder's settings, which is
252
+ what a bug report needs:
253
+
254
+ ```text
255
+ INFO execsql.lsp.server: execsql lsp 2.x.y; Python 3.12.7 at /home/me/.local/share/uv/tools/execsql2/bin/python; pygls 2.x.y; formatter available
256
+ INFO execsql.lsp.server: workspace folders: /home/me/etl
257
+ INFO execsql.lsp.server: settings for /home/me/etl: config files /home/me/etl/execsql.conf; lint select all, ignore V; format {...}
258
+ ```
259
+
260
+ - `debug` adds every message between the editor and the server, including the
261
+ scripts' text.
262
+
263
+ The VS Code extension logs at `info` (setting **execsql.server.logLevel**). In
264
+ another editor, add the option to the server command, e.g. in Neovim
265
+ `cmd = { "execsql", "lsp", "--log-level", "info" }`. An editor that does not
266
+ keep the server's stderr can use `--log-file PATH` to append the log to a file.
267
+
268
+ **Tracing the protocol in VS Code.** Set **execsql.trace.server** to `messages`
269
+ (or `verbose`, which adds each message's content); the trace appears in the same
270
+ Output channel.
271
+
272
+ **Reporting a problem.** [Open an issue](https://github.com/geocoug/execsql/issues)
273
+ with:
274
+
275
+ 1. The output of `execsql --version` and `execsql lsp --check`.
276
+ 1. The server log at `info`, from start-up to the problem.
277
+ 1. A small script that shows it, if you can share one.