execsql2 2.16.8__tar.gz → 2.16.13__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.
- {execsql2-2.16.8 → execsql2-2.16.13}/CHANGELOG.md +61 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/PKG-INFO +1 -1
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/about/divergence.md +31 -14
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/guides/formatter.md +54 -15
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/reference/metacommands.md +111 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +1 -1
- {execsql2-2.16.8 → execsql2-2.16.13}/pyproject.toml +3 -3
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/debug/repl.py +59 -0
- execsql2-2.16.13/src/execsql/format.py +657 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/debug.py +89 -1
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/dispatch.py +18 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/script/ast.py +43 -6
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/script/executor.py +28 -13
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/script/parser.py +135 -6
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/fileio.py +9 -1
- execsql2-2.16.13/tests/metacommands/test_show_scripts.py +154 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_ast.py +26 -3
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_ast_parser.py +75 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_executor.py +358 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_format.py +749 -0
- execsql2-2.16.13/tests/test_parser_params.py +56 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/uv.lock +1 -1
- execsql2-2.16.8/src/execsql/format.py +0 -382
- {execsql2-2.16.8 → execsql2-2.16.13}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/.github/workflows/ci-cd.yml +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/.gitignore +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/.pre-commit-config.yaml +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/.pre-commit-hooks.yaml +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/.python-version +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/.readthedocs.yaml +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/CONTRIBUTING.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/LICENSE.txt +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/NOTICE +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/README.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/SECURITY.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/about/contributors.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/about/copyright.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/api/cli.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/api/db.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/api/exporters.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/api/importers.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/api/index.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/api/metacommands.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/dev/adding_db_adapters.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/dev/adding_exporters.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/dev/adding_importers.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/dev/adding_metacommands.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/dev/architecture.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/getting-started/installation.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/getting-started/requirements.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/getting-started/syntax.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/guides/debugging.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/guides/documentation.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/guides/encoding.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/guides/examples.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/guides/logging.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/guides/sql_syntax.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/guides/usage.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/guides/using_scripts.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/Compare_planets.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/actions.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/actions2.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/checkboxes.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/connect.b64 +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/connect.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/create_conf.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/data_error1_screenshot.jpg +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/entry_form.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/execsql_console.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/execsql_logo_01.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/fatals.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/logo_small.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/pause_terminal.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/pause_terminal_sm.b64 +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/pause_terminal_sm.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/prompt_compare.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/set_build_commands.jpg +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/unit_conversions.b64 +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/unit_conversions_029.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/unmatched.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/images/vim_execsql_highlight.png +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/index.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/reference/configuration.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/reference/security.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/docs/reference/substitution_vars.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/extras/plugin-template/README.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/extras/plugin-template/pyproject.toml +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/extras/plugin-template/tests/test_plugin.py.example +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/extras/vscode-execsql/README.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/extras/vscode-execsql/package.json +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/justfile +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/scripts/generate_vscode_grammar.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/__main__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/api.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/cli/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/cli/dsn.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/cli/help.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/cli/lint.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/cli/lint_ast.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/cli/run.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/config.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/access.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/base.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/dsn.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/duckdb.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/factory.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/firebird.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/mysql.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/oracle.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/postgres.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/sqlite.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/db/sqlserver.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/debug/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exceptions.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/base.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/delimited.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/duckdb.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/feather.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/html.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/json.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/latex.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/markdown.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/ods.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/parquet.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/pretty.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/protocol.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/raw.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/sqlite.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/templates.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/values.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/xls.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/xlsx.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/xml.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/yaml.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/exporters/zip.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/gui/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/gui/base.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/gui/console.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/gui/desktop.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/gui/tui.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/importers/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/importers/base.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/importers/csv.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/importers/feather.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/importers/json.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/importers/ods.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/importers/xls.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/conditions.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/connect.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/control.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/data.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/io.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/io_export.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/io_fileops.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/io_import.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/io_write.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/prompt.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/script_ext.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/system.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/metacommands/upsert.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/models.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/parser.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/plugins.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/py.typed +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/script/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/script/control.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/script/engine.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/script/variables.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/state.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/types.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/auth.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/crypto.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/datetime.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/errors.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/gui.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/mail.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/numeric.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/regex.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/strings.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/src/execsql/utils/timer.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/README.md +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/config_settings.sqlite +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/example_config_prompt.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/execsql.conf +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/make_config_db.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/md_compare.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/md_glossary.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/md_upsert.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/pg_compare.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/pg_glossary.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/pg_upsert.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/script_template.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/ss_compare.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/ss_glossary.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/templates/ss_upsert.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/cli/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/cli/test_cli.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/cli/test_cli_e2e.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/cli/test_cli_run.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/cli/test_lint.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/cli/test_ping.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/cli/test_profile.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/conftest.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/db/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/db/test_base.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/db/test_db_adapters_mocked.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/db/test_dsn.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/db/test_duckdb.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/db/test_factory.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/db/test_postgres.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/db/test_sqlite.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/db/test_sqlite_extra.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_base.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_db.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_delimited.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_duckdb_exporter.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_exporters.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_feather.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_html_extended.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_html_latex.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_json.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_json_extended.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_latex_extended.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_markdown.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_ods.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_parquet.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_pretty_extended.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_raw_extended.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_sqlite_exporter.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_templates.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_templates_extended.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_values_extended.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_xls_xlsx.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_xlsx.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_xml.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_yaml.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/exporters/test_zip.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/gui/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/gui/test_backends.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/gui/test_compare_stats.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/gui/test_compute_row_diffs.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/importers/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/importers/test_base_extended.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/importers/test_csv_edge_cases.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/importers/test_csv_importer.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/importers/test_feather_importer.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/importers/test_json_importer.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/importers/test_ods_importer.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/importers/test_xls_importer.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/integration/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/integration/conftest.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/integration/test_dsn.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/integration/test_duckdb.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/integration/test_mysql.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/integration/test_postgres.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/integration/test_sqlite.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_assert.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_breakpoint.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_connect.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_io_export.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_io_import.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_metacommands.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_metacommands_connect.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_metacommands_data.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_metacommands_extended.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_metacommands_io.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_metacommands_script_ext.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_metacommands_system.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_metacommands_system_extra.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_pg_upsert.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/metacommands/test_row_count.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/scripts/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/scripts/fixtures/control_flow.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/scripts/fixtures/parse_only/parse_tree.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/scripts/fixtures/smoke.sql +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/scripts/test_sql_scripts.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_api.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_config.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_config_data.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_config_extended.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_debug_repl.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_engine.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_error_messages.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_exceptions.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_mail.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_models.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_package.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_parser.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_plugins.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_registry.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_script.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_state.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/test_types.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/__init__.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_auth.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_auth_extra.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_crypto.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_datetime.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_errors.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_errors_extra.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_fileio.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_fileio_extra.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_numeric.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_regex.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_strings.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_timer.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/tests/utils/test_timer_extra.py +0 -0
- {execsql2-2.16.8 → execsql2-2.16.13}/zensical.toml +0 -0
|
@@ -13,6 +13,67 @@ ______________________________________________________________________
|
|
|
13
13
|
|
|
14
14
|
______________________________________________________________________
|
|
15
15
|
|
|
16
|
+
## [2.16.13] - 2026-05-01
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- `execsql-format`: The `--indent` flag now controls SQL indentation in addition to metacommand indentation. Previously only metacommand depth was affected; now sqlglot's `pad` and `indent` parameters follow the same value (default 4).
|
|
21
|
+
- `execsql-format`: New `--leading-comma` flag places commas at the start of lines instead of the end (e.g., ` , col2` instead of `col1,`).
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- `execsql-format`: Fixed SQL corruption when formatting scripts with comments interleaved within multi-line SQL statements (e.g., `SELECT` with comment lines between columns, `CASE` with comments before `WHEN` clauses). Previously, the formatter split statements at comment boundaries and sent each fragment to sqlglot independently, which produced broken output (commas became semicolons, CASE expressions were split apart, content was silently dropped). The formatter now uses a marker-based round-trip: comments are replaced with inline markers before formatting so sqlglot sees the complete statement, then markers are restored to their original `--` comment style and position in the output. Comments that sqlglot's AST drops (e.g., inside CASE expressions) are detected and re-inserted at the best matching position using token-based heuristics.
|
|
26
|
+
- `execsql-format`: Fixed `/* */` block comments containing `-- !x!` metacommand markers being incorrectly processed as real metacommands. This caused the block comment to be broken apart, with `*/` becoming `* /` and commented-out code being mangled. The formatter now tracks block comment boundaries and skips metacommand processing inside them.
|
|
27
|
+
- `execsql-format`: Fixed blank lines within multi-line SQL statements (e.g., between column groups in a large `SELECT`) incorrectly splitting the statement into separate formatting blocks, causing each fragment to be formatted independently and producing invalid SQL.
|
|
28
|
+
- `execsql-format`: Added safety checks to the sqlglot formatting pass — if sqlglot produces more statements than the input contained or drops significant content, the formatter now falls back to the original text instead of emitting corrupted SQL.
|
|
29
|
+
|
|
30
|
+
______________________________________________________________________
|
|
31
|
+
|
|
32
|
+
## [2.16.12] - 2026-05-01
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Lowered coverage threshold from 90% to 89% — SCRIPT introspection code is tested via subprocess integration tests which don't contribute to in-process coverage, and Windows CI skips TTY/POSIX tests that contribute ~1% on other platforms.
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- Unit tests for `_parse_param_defs`, `_format_script_signature`, `_format_script_source`, and `SHOW SCRIPTS`/`SHOW SCRIPT` handlers.
|
|
41
|
+
- Parser coverage tests for default parameters and docstring extraction.
|
|
42
|
+
|
|
43
|
+
______________________________________________________________________
|
|
44
|
+
|
|
45
|
+
## [2.16.11] - 2026-05-01
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- Multi-line `/* */` block comment docstrings in `BEGIN SCRIPT` blocks now capture all lines correctly. Previously, the doc collection guard ran on block comment continuation lines, classified them as "non-comment", and stopped doc collection before the block comment handler could process them.
|
|
50
|
+
|
|
51
|
+
### Added
|
|
52
|
+
|
|
53
|
+
- 12 parser tests covering default parameters and docstring extraction (single-line, multi-line, block comments, empty separators, metacommand termination, required-after-optional validation).
|
|
54
|
+
|
|
55
|
+
______________________________________________________________________
|
|
56
|
+
|
|
57
|
+
## [2.16.10] - 2026-05-01
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
|
|
61
|
+
- EXECUTE SCRIPT with a variable-substituted target name (e.g., `EXECUTE SCRIPT !!#script_name!!`) now works correctly. Previously, the parser's regex only accepted literal word characters as the script identifier, causing variable targets to fall through to the dispatch table and fail with "EXECUTE SCRIPT should be handled by the AST executor." The parser now recognizes `!!var!!` substitution patterns as valid script identifiers.
|
|
62
|
+
|
|
63
|
+
______________________________________________________________________
|
|
64
|
+
|
|
65
|
+
## [2.16.9] - 2026-05-01
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
|
|
69
|
+
- `SHOW SCRIPTS` metacommand lists all registered SCRIPT definitions with parameter signatures and source locations.
|
|
70
|
+
- `SHOW SCRIPT <name>` metacommand shows detail for a single SCRIPT (parameters, source file and line range, docstring).
|
|
71
|
+
- `.scripts` REPL command lists all registered scripts; `.scripts <name>` shows detail for one script.
|
|
72
|
+
- Default parameter values for SCRIPT definitions: `BEGIN SCRIPT load(schema, table, batch=1000)`. Parameters with defaults can be omitted at call site; the default value is used automatically. Required parameters must precede optional parameters (like Python).
|
|
73
|
+
- Automatic docstring extraction for SCRIPT blocks. Comments (`--` or `/* */`) immediately following `BEGIN SCRIPT` are captured as documentation. A blank line terminates the docstring. Docstrings are displayed by `SHOW SCRIPT`, `SHOW SCRIPTS`, and `.scripts` in the debug REPL.
|
|
74
|
+
|
|
75
|
+
______________________________________________________________________
|
|
76
|
+
|
|
16
77
|
## [2.16.8] - 2026-04-30
|
|
17
78
|
|
|
18
79
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.16.
|
|
3
|
+
Version: 2.16.13
|
|
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
|
|
@@ -52,6 +52,21 @@ ______________________________________________________________________
|
|
|
52
52
|
| `CONFIG LOG_SQL` | Enable SQL query audit logging — writes executed SQL to the log file. |
|
|
53
53
|
| `PG_UPSERT` | QA-checked, FK-dependency-ordered upserts from staging to base schema on PostgreSQL. Integrates [pg-upsert](https://pg-upsert.readthedocs.io/) as an optional dependency. Three modes: full pipeline, QA-only, and schema check. Supports `EXPORT_FAILURES`, `EXPORT_FORMAT`, `EXPORT_MAX_ROWS`, and `STRICT_COLUMNS` keywords. `STRICT_COLUMNS` forces all missing columns to be errors (requires `pg-upsert>=1.22.0`). |
|
|
54
54
|
| `IMPORT … FROM JSON` | Import a JSON file (array of objects or NDJSON) into a database table. Nested objects are flattened with dot-separated column names; arrays are stored as JSON strings. |
|
|
55
|
+
| `SHOW SCRIPTS` | List all registered SCRIPT definitions with parameter signatures and source locations. Includes scripts from INCLUDEEd files. |
|
|
56
|
+
| `SHOW SCRIPT <name>` | Show detail for a single registered SCRIPT: name, parameters (with defaults), source file/line range, and docstring. |
|
|
57
|
+
|
|
58
|
+
### SCRIPT Enhancements
|
|
59
|
+
|
|
60
|
+
| Feature | Description |
|
|
61
|
+
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
62
|
+
| Default parameters | `BEGIN SCRIPT load(schema, table, batch=1000)` — parameters with defaults can be omitted at call site. Required parameters must precede optional parameters. |
|
|
63
|
+
| Docstrings | Comments (`--` or `/* */`) immediately following `BEGIN SCRIPT` are captured as documentation. A blank line terminates the docstring. Displayed by `SHOW SCRIPT`, `SHOW SCRIPTS`, and `.scripts` REPL command. |
|
|
64
|
+
|
|
65
|
+
### Bug Fixes
|
|
66
|
+
|
|
67
|
+
| Fix | Description |
|
|
68
|
+
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
69
|
+
| Variable EXECUTE SCRIPT targets | `EXECUTE SCRIPT !!#var!!` now works — the parser accepts substitution variable patterns as script identifiers, and the executor resolves them at runtime. |
|
|
55
70
|
|
|
56
71
|
### Conditional Tests
|
|
57
72
|
|
|
@@ -78,9 +93,9 @@ New options in `execsql.conf`:
|
|
|
78
93
|
|
|
79
94
|
### Tools
|
|
80
95
|
|
|
81
|
-
| Tool | Description
|
|
82
|
-
| ---------------- |
|
|
83
|
-
| `execsql-format` | Standalone CLI for normalizing metacommand indentation and uppercasing SQL keywords. Supports `--check` and `--
|
|
96
|
+
| Tool | Description |
|
|
97
|
+
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
98
|
+
| `execsql-format` | Standalone CLI for normalizing metacommand indentation and uppercasing SQL keywords. Supports `--check`, `--in-place`, `--indent N` (controls both metacommand and SQL indentation), and `--leading-comma` (commas at start of lines) modes. Also available as a [pre-commit hook](../guides/formatter.md). |
|
|
84
99
|
|
|
85
100
|
### GUI
|
|
86
101
|
|
|
@@ -131,17 +146,19 @@ execsql2 adds a full interactive debugging system that has no equivalent in upst
|
|
|
131
146
|
|
|
132
147
|
**REPL commands** (all dot-prefixed to avoid collisions with variable names and SQL):
|
|
133
148
|
|
|
134
|
-
| Command | Description
|
|
135
|
-
| ---------------------- |
|
|
136
|
-
| `.continue` / `.c` | Resume normal script execution
|
|
137
|
-
| `.abort` / `.q` | Halt the script with exit status 1
|
|
138
|
-
| `.vars` / `.v` | List all user, system, local, and counter variables (grouped by type)
|
|
139
|
-
| `.vars all` / `.v all` | Include environment variables (`&`) in the listing
|
|
140
|
-
| `.next` / `.n` | Execute the next statement, then pause again (step mode)
|
|
141
|
-
| `.where` / `.w` | Show the current script file, line number, and upcoming statement text
|
|
142
|
-
| `.stack` | Show the command-list stack (script name, cursor position, nesting depth)
|
|
143
|
-
| `.set VAR VAL` / `.s` | Set or update a substitution variable; prints confirmation on success
|
|
144
|
-
| `.
|
|
149
|
+
| Command | Description |
|
|
150
|
+
| ---------------------- | --------------------------------------------------------------------------- |
|
|
151
|
+
| `.continue` / `.c` | Resume normal script execution |
|
|
152
|
+
| `.abort` / `.q` | Halt the script with exit status 1 |
|
|
153
|
+
| `.vars` / `.v` | List all user, system, local, and counter variables (grouped by type) |
|
|
154
|
+
| `.vars all` / `.v all` | Include environment variables (`&`) in the listing |
|
|
155
|
+
| `.next` / `.n` | Execute the next statement, then pause again (step mode) |
|
|
156
|
+
| `.where` / `.w` | Show the current script file, line number, and upcoming statement text |
|
|
157
|
+
| `.stack` | Show the command-list stack (script name, cursor position, nesting depth) |
|
|
158
|
+
| `.set VAR VAL` / `.s` | Set or update a substitution variable; prints confirmation on success |
|
|
159
|
+
| `.scripts` | List all registered SCRIPT definitions with parameters and source locations |
|
|
160
|
+
| `.scripts NAME` | Show detail for a specific SCRIPT (parameters, source file/line range) |
|
|
161
|
+
| `.help` / `.h` | Show available commands |
|
|
145
162
|
|
|
146
163
|
**Non-prefixed input** is interpreted as either a variable lookup or ad-hoc SQL:
|
|
147
164
|
|
|
@@ -24,13 +24,14 @@ By default, formatted output is written to stdout. Use `--in-place` to overwrite
|
|
|
24
24
|
|
|
25
25
|
### Options { #options }
|
|
26
26
|
|
|
27
|
-
| Option | Default | Description
|
|
28
|
-
| ------------------ | -------- |
|
|
29
|
-
| `FILE_OR_DIR` | required | One or more files or directories to format. Directories are searched recursively for `*.sql` files.
|
|
30
|
-
| `--check` | off | Exit with code 1 if any file would be reformatted. Does not write any changes. Useful in CI.
|
|
31
|
-
| `-i`, `--in-place` | off | Modify files in place instead of writing to stdout.
|
|
32
|
-
| `--no-sql` | off | Skip SQL reformatting via sqlglot. Only normalizes metacommand indentation and keyword casing.
|
|
33
|
-
| `--indent N` | `4` |
|
|
27
|
+
| Option | Default | Description |
|
|
28
|
+
| ------------------ | -------- | -------------------------------------------------------------------------------------------------------------- |
|
|
29
|
+
| `FILE_OR_DIR` | required | One or more files or directories to format. Directories are searched recursively for `*.sql` files. |
|
|
30
|
+
| `--check` | off | Exit with code 1 if any file would be reformatted. Does not write any changes. Useful in CI. |
|
|
31
|
+
| `-i`, `--in-place` | off | Modify files in place instead of writing to stdout. |
|
|
32
|
+
| `--no-sql` | off | Skip SQL reformatting via sqlglot. Only normalizes metacommand indentation and keyword casing. |
|
|
33
|
+
| `--indent N` | `4` | Spaces per indent level. Controls both metacommand block depth and SQL indentation (columns, subqueries, etc). |
|
|
34
|
+
| `--leading-comma` | off | Place commas at the start of lines instead of the end (e.g. ` , col2` instead of `col1,`). |
|
|
34
35
|
|
|
35
36
|
## What Gets Formatted { #what-gets-formatted }
|
|
36
37
|
|
|
@@ -64,11 +65,28 @@ Metacommands that open a block (`IF`, `LOOP`, `BEGIN SCRIPT`, `BEGIN BATCH`, `BE
|
|
|
64
65
|
|
|
65
66
|
### SQL block formatting { #sql-formatting }
|
|
66
67
|
|
|
67
|
-
SQL statements between metacommands are re-indented to match the current block depth and reformatted using [sqlglot](https://sqlglot.com/) in PostgreSQL dialect with pretty-printing enabled.
|
|
68
|
+
SQL statements between metacommands are re-indented to match the current block depth and reformatted using [sqlglot](https://sqlglot.com/) in PostgreSQL dialect with pretty-printing enabled.
|
|
68
69
|
|
|
69
|
-
|
|
70
|
+
The `--indent` flag controls SQL indentation in addition to metacommand depth. For example, `--indent 4` (the default) produces 4-space indented column lists, subqueries, and CASE branches. `--indent 2` gives a more compact style.
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
#### Comment handling
|
|
73
|
+
|
|
74
|
+
Comments interleaved within SQL statements (e.g. `--` comments between SELECT columns, or inside CASE expressions) are preserved through formatting using a marker-based round-trip:
|
|
75
|
+
|
|
76
|
+
1. Each comment line is replaced with a unique inline marker attached to the next SQL line.
|
|
77
|
+
1. sqlglot formats the complete statement (no fragmentation).
|
|
78
|
+
1. Markers are restored to their original `--` comment style and position.
|
|
79
|
+
1. Comments that sqlglot's AST drops (e.g. inside CASE WHEN) are detected and re-inserted at the best matching position.
|
|
80
|
+
|
|
81
|
+
Block comments (`/* */`) that contain `-- !x!` metacommand markers (e.g. commented-out code blocks) are recognized and passed through without metacommand processing.
|
|
82
|
+
|
|
83
|
+
#### Variable preservation
|
|
84
|
+
|
|
85
|
+
execsql substitution variables (`!!varname!!`, `!{varname}!`) are replaced with valid SQL identifiers before formatting, then restored afterward, so the formatter does not corrupt them — including in schema-qualified names (`!!staging!!.!!table!!`), CASE expressions, JOIN conditions, and string concatenation.
|
|
86
|
+
|
|
87
|
+
#### Fallback behavior
|
|
88
|
+
|
|
89
|
+
If sqlglot cannot parse a SQL statement, or if safety checks detect that formatting would corrupt the SQL (e.g. statement count changes, significant content loss), the original text is preserved unchanged.
|
|
72
90
|
|
|
73
91
|
Use `--no-sql` to skip SQL reformatting entirely and only normalize metacommands.
|
|
74
92
|
|
|
@@ -112,6 +130,22 @@ Exit code is `0` if all files are already formatted, `1` if any file would chang
|
|
|
112
130
|
execsql-format --indent 2 --in-place myscript.sql
|
|
113
131
|
```
|
|
114
132
|
|
|
133
|
+
### Use leading commas
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
execsql-format --leading-comma --in-place myscript.sql
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
This places commas at the start of each line instead of the end:
|
|
140
|
+
|
|
141
|
+
```sql
|
|
142
|
+
SELECT
|
|
143
|
+
a
|
|
144
|
+
, b
|
|
145
|
+
, c
|
|
146
|
+
FROM t;
|
|
147
|
+
```
|
|
148
|
+
|
|
115
149
|
### Skip SQL reformatting
|
|
116
150
|
|
|
117
151
|
Format only metacommand indentation and casing, leaving SQL statements untouched:
|
|
@@ -143,13 +177,14 @@ select id,name,created_at from users where active = true order by name;
|
|
|
143
177
|
-- !x! IF(EQUAL(!!schema!!, "public"))
|
|
144
178
|
-- !x! WRITE "Checking public schema..."
|
|
145
179
|
SELECT
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
180
|
+
id,
|
|
181
|
+
name,
|
|
182
|
+
created_at
|
|
149
183
|
FROM users
|
|
150
184
|
WHERE
|
|
151
|
-
|
|
152
|
-
ORDER BY
|
|
185
|
+
active = TRUE
|
|
186
|
+
ORDER BY
|
|
187
|
+
name;
|
|
153
188
|
-- !x! ENDIF
|
|
154
189
|
```
|
|
155
190
|
|
|
@@ -180,6 +215,10 @@ The hook runs on `*.sql` files. Pass any CLI options via `args`:
|
|
|
180
215
|
# Custom indent width
|
|
181
216
|
- id: execsql-format
|
|
182
217
|
args: [--in-place, --indent, "2"]
|
|
218
|
+
|
|
219
|
+
# Leading commas
|
|
220
|
+
- id: execsql-format
|
|
221
|
+
args: [--in-place, --leading-comma]
|
|
183
222
|
```
|
|
184
223
|
|
|
185
224
|
## Exit Codes { #exit-codes }
|
|
@@ -141,6 +141,8 @@ All REPL commands are dot-prefixed to avoid ambiguity with variable names and SQ
|
|
|
141
141
|
| `.vars all` | Include environment variables (`&`) in the listing |
|
|
142
142
|
| `.next` or `.n` | Execute the next script statement, then pause again (step mode) |
|
|
143
143
|
| `.stack` | Show the command-list stack: script name, cursor index, and nesting depth |
|
|
144
|
+
| `.scripts` | List all registered SCRIPT definitions with parameters and source locations |
|
|
145
|
+
| `.scripts NAME` | Show detail for a specific SCRIPT (parameters, source file/line range) |
|
|
144
146
|
| `.help` | Show the list of available REPL commands |
|
|
145
147
|
|
|
146
148
|
**Variable inspection and SQL (no dot prefix):**
|
|
@@ -219,6 +221,10 @@ BEGIN SCRIPT <script_name>
|
|
|
219
221
|
BEGIN SCRIPT <script_name> WITH PARAMETERS (param1[, param2[,..]])
|
|
220
222
|
```
|
|
221
223
|
|
|
224
|
+
```
|
|
225
|
+
BEGIN SCRIPT <script_name>(param1, param2=default_value)
|
|
226
|
+
```
|
|
227
|
+
|
|
222
228
|
```
|
|
223
229
|
END SCRIPT [script_name]
|
|
224
230
|
```
|
|
@@ -232,6 +238,56 @@ If the WITH PARAMETERS clause is used, the parameter names specified must be ass
|
|
|
232
238
|
|
|
233
239
|
The "WITH" and "PARAMETERS" keywords are both optional.
|
|
234
240
|
|
|
241
|
+
### Default parameter values
|
|
242
|
+
|
|
243
|
+
Parameters can have default values using `param=value` syntax. Parameters with defaults are optional at the call site — if omitted, the default value is used. Required parameters (no default) must precede optional parameters.
|
|
244
|
+
|
|
245
|
+
```sql
|
|
246
|
+
-- !x! BEGIN SCRIPT load_data(schema, table, batch_size=1000, dry_run=false)
|
|
247
|
+
INSERT INTO !!#table!! SELECT * FROM staging LIMIT !!#batch_size!!;
|
|
248
|
+
-- !x! END SCRIPT
|
|
249
|
+
|
|
250
|
+
-- All of these are valid:
|
|
251
|
+
-- !x! EXECUTE SCRIPT load_data(schema=public, table=users)
|
|
252
|
+
-- !x! EXECUTE SCRIPT load_data(schema=public, table=users, batch_size=500)
|
|
253
|
+
-- !x! EXECUTE SCRIPT load_data(schema=public, table=users, batch_size=500, dry_run=true)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
A required parameter after an optional parameter is a parse error:
|
|
257
|
+
|
|
258
|
+
```sql
|
|
259
|
+
-- Parse error: required parameter 'table' after optional parameter 'batch'
|
|
260
|
+
-- !x! BEGIN SCRIPT bad(schema, batch=1000, table)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Docstrings
|
|
264
|
+
|
|
265
|
+
Comments (`--` or `/* */`) immediately following the BEGIN SCRIPT line are captured as the script's docstring. A blank line terminates the docstring. Docstrings are displayed by [SHOW SCRIPT](#show_script), [SHOW SCRIPTS](#show_scripts), and the `.scripts` REPL command.
|
|
266
|
+
|
|
267
|
+
```sql
|
|
268
|
+
-- !x! BEGIN SCRIPT load_data(schema, table)
|
|
269
|
+
-- Load data from staging into the target table.
|
|
270
|
+
-- Parameters:
|
|
271
|
+
-- schema - Target schema name
|
|
272
|
+
-- table - Target table name
|
|
273
|
+
|
|
274
|
+
-- !x! SUB ~batch 1000
|
|
275
|
+
INSERT INTO !!#table!! SELECT * FROM staging;
|
|
276
|
+
-- !x! END SCRIPT
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Block comments are also valid:
|
|
280
|
+
|
|
281
|
+
```sql
|
|
282
|
+
-- !x! BEGIN SCRIPT load_data(schema, table)
|
|
283
|
+
/* Load data from staging into the target table. */
|
|
284
|
+
|
|
285
|
+
INSERT INTO !!#table!! SELECT * FROM staging;
|
|
286
|
+
-- !x! END SCRIPT
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Other notes
|
|
290
|
+
|
|
235
291
|
If a script name is provided with the END SCRIPT metacommand, it must match the name used in the corresponding BEGIN SCRIPT metacommand. If it does not, *execsql* will halt with an error message.
|
|
236
292
|
|
|
237
293
|
A BEGIN/END SCRIPT block can be used in ways similar to a separate script file that is included with the [INCLUDE](#include) metacommand. Both allow the same code to be executed repeatedly, either at different locations in the main script or recursively to perform looping.
|
|
@@ -2697,6 +2753,61 @@ Assigns the value of the specified numeric expression to the counter. The next t
|
|
|
2697
2753
|
The numeric expression may consist of the simple algebraic operations of addition, subtraction, multiplication, and division. Parentheses may be used to control evaluation order. Numeric values used in the expression may be integers or floating-point numbers, but the result will be reduced to an integer before assignment to the counter variable.
|
|
2698
2754
|
|
|
2699
2755
|
|
|
2756
|
+
## SHOW SCRIPTS { #show_scripts }
|
|
2757
|
+
|
|
2758
|
+
```
|
|
2759
|
+
SHOW SCRIPTS
|
|
2760
|
+
```
|
|
2761
|
+
|
|
2762
|
+
Lists all registered SCRIPT definitions with their parameter signatures and source locations. This is useful for discovering what scripts are available at runtime, especially when scripts are loaded from INCLUDEEd files whose paths are determined dynamically.
|
|
2763
|
+
|
|
2764
|
+
**Example output:**
|
|
2765
|
+
|
|
2766
|
+
```
|
|
2767
|
+
Registered scripts (3):
|
|
2768
|
+
|
|
2769
|
+
load_data(schema, table, batch_size=1000) pipeline.sql:15-42
|
|
2770
|
+
cleanup() init.sql:10-25
|
|
2771
|
+
validate(schema, table) pipeline.sql:62-80
|
|
2772
|
+
```
|
|
2773
|
+
|
|
2774
|
+
Default parameter values are shown in the signature. Use `SHOW SCRIPT <name>` for full detail including docstrings.
|
|
2775
|
+
|
|
2776
|
+
If no scripts are registered, prints `No scripts registered.`
|
|
2777
|
+
|
|
2778
|
+
## SHOW SCRIPT { #show_script }
|
|
2779
|
+
|
|
2780
|
+
```
|
|
2781
|
+
SHOW SCRIPT <name>
|
|
2782
|
+
```
|
|
2783
|
+
|
|
2784
|
+
Shows detail for a single registered SCRIPT definition, including its parameter list (with required/optional status and defaults), source file/line range, and docstring.
|
|
2785
|
+
|
|
2786
|
+
**Example:**
|
|
2787
|
+
|
|
2788
|
+
```sql
|
|
2789
|
+
-- !x! SHOW SCRIPT load_data
|
|
2790
|
+
```
|
|
2791
|
+
|
|
2792
|
+
**Example output:**
|
|
2793
|
+
|
|
2794
|
+
```
|
|
2795
|
+
Script: load_data(schema, table, batch_size=1000)
|
|
2796
|
+
Source: pipeline.sql:15-42
|
|
2797
|
+
Parameters:
|
|
2798
|
+
schema (required)
|
|
2799
|
+
table (required)
|
|
2800
|
+
batch_size (optional, default: 1000)
|
|
2801
|
+
|
|
2802
|
+
Load data from staging into the target table.
|
|
2803
|
+
```
|
|
2804
|
+
|
|
2805
|
+
If the script is not found, prints `No script named '<name>' is registered.`
|
|
2806
|
+
|
|
2807
|
+
!!! tip
|
|
2808
|
+
In the debug REPL, use `.scripts` to list all scripts or `.scripts <name>` to show detail for one script.
|
|
2809
|
+
|
|
2810
|
+
|
|
2700
2811
|
## SUB { #subcmd }
|
|
2701
2812
|
|
|
2702
2813
|
```
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
},
|
|
94
94
|
"action-keywords": {
|
|
95
95
|
"comment": "sub, write, execute script, export, etc.",
|
|
96
|
-
"match": "(?i)\\b(reset\\s+dialog_canceled|write\\s+create_table|export_metadata|pg_upsert\\s+check|sub_querystring|execute\\s+script|append\\s+script|extend\\s+script|reset\\s+counter|export\\s+query|pg_upsert\\s+qa|sub_tempfile|write\\s+script|import_file|set\\s+counter|sub_decrypt|sub_encrypt|autocommit|breakpoint|copy\\s+query|disconnect|select_sub|sub_append|system_cmd|pg_upsert|pg_vacuum|sub_empty|sub_local|connect|include|max_int|rm_file|subdata|sub_add|sub_ini|assert|export|import|rm_sub|debug|email|serve|write|copy|log|run|sub|use|zip|cd)\\b",
|
|
96
|
+
"match": "(?i)\\b(reset\\s+dialog_canceled|write\\s+create_table|export_metadata|pg_upsert\\s+check|sub_querystring|execute\\s+script|append\\s+script|extend\\s+script|reset\\s+counter|export\\s+query|pg_upsert\\s+qa|show\\s+scripts|sub_tempfile|write\\s+script|import_file|set\\s+counter|show\\s+script|sub_decrypt|sub_encrypt|autocommit|breakpoint|copy\\s+query|disconnect|select_sub|sub_append|system_cmd|pg_upsert|pg_vacuum|sub_empty|sub_local|connect|include|max_int|rm_file|subdata|sub_add|sub_ini|assert|export|import|rm_sub|debug|email|serve|write|copy|log|run|sub|use|zip|cd)\\b",
|
|
97
97
|
"name": "keyword.other.execsql"
|
|
98
98
|
},
|
|
99
99
|
"config-event-keywords": {
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "execsql2"
|
|
7
|
-
version = "2.16.
|
|
7
|
+
version = "2.16.13"
|
|
8
8
|
description = "Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = { file = "LICENSE.txt" }
|
|
@@ -165,7 +165,7 @@ skip-magic-trailing-comma = false
|
|
|
165
165
|
line-ending = "auto"
|
|
166
166
|
|
|
167
167
|
[tool.bumpversion]
|
|
168
|
-
current_version = "2.16.
|
|
168
|
+
current_version = "2.16.13"
|
|
169
169
|
commit = true
|
|
170
170
|
tag = true
|
|
171
171
|
tag_name = "v{new_version}"
|
|
@@ -188,7 +188,7 @@ addopts = [
|
|
|
188
188
|
"--cov=execsql",
|
|
189
189
|
"--cov-branch",
|
|
190
190
|
"--cov-report=xml",
|
|
191
|
-
"--cov-fail-under=
|
|
191
|
+
"--cov-fail-under=89",
|
|
192
192
|
"--strict-markers",
|
|
193
193
|
"--strict-config",
|
|
194
194
|
"--color=yes",
|
|
@@ -111,6 +111,8 @@ _HELP_COMMANDS = [
|
|
|
111
111
|
(".where", ".w", "Show the current script location and upcoming statement"),
|
|
112
112
|
(".stack", "", "Show the command-list stack (script name, line, depth)"),
|
|
113
113
|
(".set VAR VAL", ".s", "Set or update a substitution variable"),
|
|
114
|
+
(".scripts", "", "List all registered SCRIPT definitions"),
|
|
115
|
+
(".scripts NAME", "", "Show detail for a specific SCRIPT"),
|
|
114
116
|
(".help", ".h", "Show this help text"),
|
|
115
117
|
]
|
|
116
118
|
|
|
@@ -290,6 +292,12 @@ def _handle_dot_command(line: str) -> None:
|
|
|
290
292
|
varname = parts[0]
|
|
291
293
|
value = parts[1] if len(parts) > 1 else ""
|
|
292
294
|
_set_var(varname, value)
|
|
295
|
+
elif cmd.startswith("scripts"):
|
|
296
|
+
rest = cmd[7:].strip()
|
|
297
|
+
if rest:
|
|
298
|
+
_print_script_detail(rest)
|
|
299
|
+
else:
|
|
300
|
+
_print_scripts()
|
|
293
301
|
else:
|
|
294
302
|
_write(f" {_c(_RED, 'Unknown command:')} {line!r}. Type '.help' for available commands.\n")
|
|
295
303
|
|
|
@@ -507,3 +515,54 @@ def _set_var(varname: str, value: str) -> None:
|
|
|
507
515
|
else:
|
|
508
516
|
subvars.add_substitution(varname, value)
|
|
509
517
|
_write(f" {_c(_CYAN, varname)} {_c(_DIM, '=')} {value}\n")
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
def _print_scripts() -> None:
|
|
521
|
+
"""Print all registered SCRIPT definitions."""
|
|
522
|
+
from execsql.metacommands.debug import _format_script_signature, _format_script_source
|
|
523
|
+
|
|
524
|
+
scripts = _state.ast_scripts
|
|
525
|
+
if not scripts:
|
|
526
|
+
_write(" (no scripts registered)\n\n")
|
|
527
|
+
return
|
|
528
|
+
_write_rule(f" {_c(_BOLD + _YELLOW, 'Scripts')} {_c(_DIM, f'({len(scripts)})')} ")
|
|
529
|
+
sigs = {name: _format_script_signature(name, block.param_defs) for name, block in scripts.items()}
|
|
530
|
+
max_sig = max(len(s) for s in sigs.values())
|
|
531
|
+
for name, block in scripts.items():
|
|
532
|
+
sig = sigs[name]
|
|
533
|
+
src = _format_script_source(block.span)
|
|
534
|
+
_write(f" {_c(_CYAN, sig):<{max_sig + len(_CYAN) + len(_RESET)}} {_c(_DIM, src)}\n")
|
|
535
|
+
_write("\n")
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def _print_script_detail(name: str) -> None:
|
|
539
|
+
"""Print detail for a single SCRIPT definition."""
|
|
540
|
+
from execsql.metacommands.debug import _format_script_signature, _format_script_source
|
|
541
|
+
|
|
542
|
+
script_name = name.lower()
|
|
543
|
+
scripts = _state.ast_scripts
|
|
544
|
+
if script_name not in scripts:
|
|
545
|
+
_write(f" {_c(_RED, 'No script named')} {_c(_CYAN, repr(script_name))} {_c(_RED, 'is registered.')}\n")
|
|
546
|
+
return
|
|
547
|
+
block = scripts[script_name]
|
|
548
|
+
sig = _format_script_signature(block.name, block.param_defs)
|
|
549
|
+
src = _format_script_source(block.span)
|
|
550
|
+
_write_rule(f" {_c(_BOLD + _YELLOW, 'Script')} {_c(_DIM, '──')} {_c(_CYAN, sig)} ")
|
|
551
|
+
_write(f" {_c(_BOLD, 'Source:')} {src}\n")
|
|
552
|
+
if block.param_defs:
|
|
553
|
+
_write(f" {_c(_BOLD, 'Parameters:')}\n")
|
|
554
|
+
max_name = max(len(p.name) for p in block.param_defs)
|
|
555
|
+
for p in block.param_defs:
|
|
556
|
+
if p.default is not None:
|
|
557
|
+
_write(
|
|
558
|
+
f" {_c(_CYAN, p.name):<{max_name + len(_CYAN) + len(_RESET)}} {_c(_DIM, f'(optional, default: {p.default})')}\n",
|
|
559
|
+
)
|
|
560
|
+
else:
|
|
561
|
+
_write(f" {_c(_CYAN, p.name):<{max_name + len(_CYAN) + len(_RESET)}} {_c(_DIM, '(required)')}\n")
|
|
562
|
+
else:
|
|
563
|
+
_write(f" {_c(_BOLD, 'Parameters:')} (none)\n")
|
|
564
|
+
if block.doc:
|
|
565
|
+
_write("\n")
|
|
566
|
+
for doc_line in block.doc.split("\n"):
|
|
567
|
+
_write(f" {_c(_DIM, doc_line)}\n")
|
|
568
|
+
_write("\n")
|