execsql2 2.25.0__tar.gz → 2.26.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.
- {execsql2-2.25.0 → execsql2-2.26.0}/.github/dependabot.yml +5 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/.github/workflows/ci-cd.yml +1 -1
- {execsql2-2.25.0 → execsql2-2.26.0}/.pre-commit-hooks.yaml +4 -1
- {execsql2-2.25.0 → execsql2-2.26.0}/CHANGELOG.md +22 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/PKG-INFO +5 -5
- {execsql2-2.25.0 → execsql2-2.26.0}/README.md +1 -1
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/about/divergence.md +8 -8
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/guides/formatter.md +29 -1
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/reference/configuration.md +3 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/reference/lint.md +3 -2
- {execsql2-2.25.0 → execsql2-2.26.0}/pyproject.toml +3 -3
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/commands/format.py +10 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/lint.py +86 -26
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/config.py +2 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/data/execsql.conf.template +3 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/format.py +106 -21
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_cli_surface.py +1 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_commands.py +8 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_lint.py +73 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_format.py +54 -0
- execsql2-2.26.0/tests/test_tooling_versions.py +65 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/uv.lock +2 -2
- execsql2-2.25.0/tests/test_tooling_versions.py +0 -38
- {execsql2-2.25.0 → execsql2-2.26.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/.gitignore +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/.pre-commit-config.yaml +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/.python-version +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/.readthedocs.yaml +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/CONTRIBUTING.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/LICENSE.txt +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/NOTICE +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/SECURITY.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/about/contributors.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/about/copyright.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/api/cli.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/api/db.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/api/exporters.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/api/importers.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/api/index.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/api/metacommands.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/dev/adding_db_adapters.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/dev/adding_exporters.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/dev/adding_importers.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/dev/adding_metacommands.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/dev/architecture.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/dev/releasing.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/getting-started/installation.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/getting-started/requirements.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/getting-started/syntax.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/guides/debugging.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/guides/documentation.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/guides/encoding.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/guides/examples.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/guides/logging.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/guides/sql_syntax.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/guides/usage.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/guides/using_scripts.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/Compare_planets.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/actions.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/actions2.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/checkboxes.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/connect.b64 +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/connect.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/create_conf.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/data_error1_screenshot.jpg +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/entry_form.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/execsql_console.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/execsql_logo_01.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/fatals.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/logo_small.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/pause_terminal.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/pause_terminal_sm.b64 +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/pause_terminal_sm.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/prompt_compare.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/set_build_commands.jpg +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/unit_conversions.b64 +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/unit_conversions_029.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/unmatched.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/images/vim_execsql_highlight.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/index.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/reference/metacommands.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/reference/security.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/docs/reference/substitution_vars.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/extras/plugin-template/README.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/extras/plugin-template/pyproject.toml +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/extras/plugin-template/tests/test_plugin.py.example +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/extras/vscode-execsql/.vscodeignore +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/extras/vscode-execsql/LICENSE.txt +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/extras/vscode-execsql/README.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/extras/vscode-execsql/icon.png +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/extras/vscode-execsql/package.json +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/justfile +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/scripts/benchmarks/README.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/scripts/benchmarks/results/.gitignore +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/scripts/benchmarks/run_benchmarks.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/scripts/generate_vscode_grammar.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/__main__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/api.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/application.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/commands/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/commands/config.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/commands/init.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/commands/lint.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/commands/listing.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/commands/run.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/dispatch.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/dsn.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/help.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/options.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/cli/run.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/config_validation.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/data/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/data/script_header.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/access.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/base.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/dsn.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/duckdb.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/factory.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/firebird.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/mysql.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/oracle.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/postgres.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/sqlite.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/sqlserver.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/db/tiers.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/debug/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/debug/repl.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exceptions.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/base.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/delimited.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/duckdb.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/feather.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/html.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/json.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/latex.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/markdown.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/ods.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/parquet.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/pretty.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/protocol.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/raw.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/sqlite.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/templates.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/values.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/xls.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/xlsx.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/xml.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/yaml.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/exporters/zip.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/gui/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/gui/base.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/gui/console.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/gui/desktop.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/gui/tui.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/importers/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/importers/base.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/importers/csv.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/importers/feather.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/importers/json.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/importers/ods.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/importers/xls.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/interactive.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/manifest.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/conditions.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/connect.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/control.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/data.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/debug.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/dispatch.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/effects.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/io.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/io_export.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/io_fileops.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/io_import.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/io_write.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/prompt.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/script_ext.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/system.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/metacommands/upsert.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/models.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/parser.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/plugins.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/py.typed +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/script/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/script/ast.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/script/control.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/script/engine.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/script/executor.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/script/parser.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/script/variables.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/state.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/state.pyi +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/types.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/auth.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/color.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/crypto.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/datetime.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/errors.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/fileio.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/gui.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/mail.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/numeric.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/regex.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/strings.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/src/execsql/utils/timer.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/README.md +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/config_settings.sqlite +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/example_config_prompt.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/make_config_db.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/md_compare.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/md_glossary.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/md_upsert.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/pg_compare.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/pg_glossary.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/pg_upsert.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/script_template.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/ss_compare.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/ss_glossary.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/templates/ss_upsert.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_cli.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_cli_e2e.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_cli_run.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_config_validate.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_dispatch.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_error_location.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_init.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_lint_fixtures.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_log_exit_record.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_manifest.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_ping.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_profile.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_sigterm.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/cli/test_undeclared_imports.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/conftest.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/data/formatter_shapes/comment_anchoring.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/data/formatter_shapes/escapes_and_literals.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/data/formatter_shapes/substitution_and_metacommands.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/data/formatter_shapes/unparsable_sql.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/data/lint/conditions_and_blocks.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/data/lint/does_not_parse.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/data/lint/every_metacommand.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/data/lint/invalid.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_access_windows.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_base.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_copy_new.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_db_adapters_mocked.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_db_adapters_mocked_extra.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_dsn.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_duckdb.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_factory.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_factory_postgres_encoding.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_import_atomic.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_import_replacement_quoted.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_import_short_rows.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_import_timezones.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_mysql_case_folding.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_mysql_inprocess.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_new_table_checks.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_oracle_driver.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_postgres.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_postgres_inprocess.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_roundtrip_adapters.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_sqlite.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_sqlite_extra.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_sqlserver_inprocess.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_tiers.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/db/test_transactions.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/conftest.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_base.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_db.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_delimited.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_duckdb_exporter.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_exporters.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_feather.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_html_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_html_latex.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_json.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_json_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_latex_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_markdown.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_ods.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_ods_export.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_parquet.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_pretty_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_raw_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_roundtrip_columnar.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_roundtrip_dbfile.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_roundtrip_delimited.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_roundtrip_json.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_roundtrip_latex_xml.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_roundtrip_markup.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_roundtrip_ods.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_roundtrip_pretty_raw.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_roundtrip_template.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_roundtrip_values.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_roundtrip_xlsx.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_sqlite_exporter.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_templates.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_templates_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_values_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_xls_xlsx.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_xlsx.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_xml.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_yaml.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/exporters/test_zip.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/gui/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/gui/test_backends.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/gui/test_backends_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/gui/test_compare_stats.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/gui/test_compute_row_diffs.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/gui/test_desktop_dialogs.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/gui/test_format_table.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/gui/test_tui_pilot.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/gui/test_tui_pilot_complex.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/gui/test_utils_gui_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/importers/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/importers/conftest.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/importers/test_base_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/importers/test_csv_blank_lines.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/importers/test_csv_edge_cases.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/importers/test_csv_importer.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/importers/test_feather_importer.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/importers/test_json_importer.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/importers/test_ods_importer.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/importers/test_roundtrip_csv.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/importers/test_xls_importer.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/integration/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/integration/conftest.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/integration/test_dsn.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/integration/test_duckdb.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/integration/test_mysql.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/integration/test_postgres.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/integration/test_sqlite.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/live_db.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_assert.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_breakpoint.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_conditions_extra.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_connect.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_io_export.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_io_import.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_metacommands.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_metacommands_connect.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_metacommands_data.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_metacommands_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_metacommands_io.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_metacommands_script_ext.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_metacommands_system.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_metacommands_system_extra.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_pg_upsert.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_prompt.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_row_count.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/metacommands/test_show_scripts.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/audit_lint_bad.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/audit_smoke/sample.json +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/audit_smoke/sample.jsonl +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/audit_smoke.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/config_runtime.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/control_flow.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/counters_and_locals.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/error_handling.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/import_options/has_comments.csv +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/import_options.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/includes/helper.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/includes.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/io_formats.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/multi_db.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/parquet_feather_roundtrip.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/parse_only/parse_tree.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/predicates.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/scripts.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/smoke.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/subroutine_loops.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/subvars_advanced.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/template_export/greeting.tmpl +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/template_export.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/timer.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/transactions.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/write_create_table.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/fixtures/xlsx_ods_roundtrip.sql +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/scripts/test_sql_scripts.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/security/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/security/test_env_detection.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/security/test_expansion_bomb.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/security/test_import_regex_hardening.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/security/test_log_redaction.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/security/test_log_secrets.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/security/test_odbc_injection.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/security/test_path_containment.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/security/test_substitution_injection.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/security/test_zip_bomb.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_api.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_api_errors.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_api_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_api_filewriter.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_api_isolation.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_api_subprocess.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_ast.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_ast_parser.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_bundled_templates.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_config.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_config_data.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_config_extended.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_date_inference.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_debug_repl.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_engine.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_error_messages.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_exceptions.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_executor.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_executor_inprocess.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_interactive.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_mail.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_models.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_package.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_parser.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_parser_params.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_plugins.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_registry.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_script.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_state.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/test_types.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/__init__.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_auth.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_auth_extra.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_crypto.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_datetime.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_encodedfile_context.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_errors.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_errors_extra.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_fileio.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_fileio_extra.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_keyring_rules.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_mail_tls.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_numeric.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_regex.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_strings.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_timer.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/tests/utils/test_timer_extra.py +0 -0
- {execsql2-2.25.0 → execsql2-2.26.0}/zensical.toml +0 -0
|
@@ -28,8 +28,13 @@ updates:
|
|
|
28
28
|
directory: /
|
|
29
29
|
schedule:
|
|
30
30
|
interval: weekly
|
|
31
|
+
# sqlglot is pinned (pyproject formatter extra, .pre-commit-hooks.yaml):
|
|
32
|
+
# its output changes between releases, so a bump is deliberate. Bump all
|
|
33
|
+
# three together, `uv lock --upgrade-package sqlglot==<new>`, and run the
|
|
34
|
+
# formatter corpus (CLAUDE.md) before merging.
|
|
31
35
|
ignore:
|
|
32
36
|
- dependency-name: ruff
|
|
37
|
+
- dependency-name: sqlglot
|
|
33
38
|
groups:
|
|
34
39
|
python-minor-and-patch:
|
|
35
40
|
patterns:
|
|
@@ -57,7 +57,7 @@ jobs:
|
|
|
57
57
|
permissions:
|
|
58
58
|
contents: read
|
|
59
59
|
steps:
|
|
60
|
-
- uses: actions/checkout@
|
|
60
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
61
61
|
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
62
62
|
with:
|
|
63
63
|
python-version: "3.13"
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
types: [file]
|
|
7
7
|
files: \.sql$
|
|
8
8
|
args: [--in-place]
|
|
9
|
-
|
|
9
|
+
# One sqlglot: its output changes between releases, so an unpinned hook
|
|
10
|
+
# formats differently depending on when its env was built (#72). Keep equal
|
|
11
|
+
# to the formatter extra and uv.lock (tests/test_tooling_versions.py).
|
|
12
|
+
additional_dependencies: ["sqlglot==30.21.0"]
|
|
10
13
|
|
|
11
14
|
- id: execsql-lint
|
|
12
15
|
name: execsql-lint
|
|
@@ -13,6 +13,28 @@ ______________________________________________________________________
|
|
|
13
13
|
|
|
14
14
|
______________________________________________________________________
|
|
15
15
|
|
|
16
|
+
## [2.26.0] - 2026-10-09
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **`execsql format --rewrite-sql`** (`[format] rewrite_sql`): accept sqlglot's rewrites of SQL text, such as `x::int` as `CAST(x AS INT)`.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- **`execsql format` changes only layout and keyword case by default:** a statement sqlglot would rewrite (`x::int` as `CAST(x AS INT)`, an alias gaining `AS`, `BTRIM` as `TRIM`) is kept as written. Pass `--rewrite-sql`, or set `rewrite_sql = Yes` under `[format]`, for the previous behavior.
|
|
25
|
+
- **`execsql format` and the `execsql-format` pre-commit hook use one sqlglot release:** the `[formatter]` extra requires sqlglot 30.21.x and the hook installs 30.21.0, so a script formats the same everywhere. The first run after upgrading can reformat files formatted with an older sqlglot, such as `BTRIM(x)` written as `TRIM(x)`; see [sqlglot version](https://execsql2.readthedocs.io/en/latest/guides/formatter/#sqlglot-version).
|
|
26
|
+
|
|
27
|
+
______________________________________________________________________
|
|
28
|
+
|
|
29
|
+
## [2.25.1] - 2026-10-09
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- **`execsql lint` `V001` / `V002` and nested variable names:** `!!N_!!CHECK_GROUP!!_CHECKS!!` no longer reports `!!N_!!` and `!!_CHECKS!!` as undefined; the inner `!!CHECK_GROUP!!` is checked, and counts as used.
|
|
34
|
+
- **`execsql lint` and `SUB_INI`:** a script whose `SUB_INI` names a FIFO or device (`/dev/zero`) no longer hangs lint, and an INI file that does not parse no longer stops it.
|
|
35
|
+
|
|
36
|
+
______________________________________________________________________
|
|
37
|
+
|
|
16
38
|
## [2.25.0] - 2026-10-09
|
|
17
39
|
|
|
18
40
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.26.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
|
|
@@ -58,7 +58,7 @@ Requires-Dist: psycopg[binary]<4,>=3.1; extra == 'all'
|
|
|
58
58
|
Requires-Dist: pymysql>=1.1; extra == 'all'
|
|
59
59
|
Requires-Dist: pyodbc>=5.0; extra == 'all'
|
|
60
60
|
Requires-Dist: pyyaml>=6.0; extra == 'all'
|
|
61
|
-
Requires-Dist: sqlglot
|
|
61
|
+
Requires-Dist: sqlglot<30.22,>=30.21.0; extra == 'all'
|
|
62
62
|
Requires-Dist: tables>=3.10; extra == 'all'
|
|
63
63
|
Requires-Dist: tkintermapview>=1.29; extra == 'all'
|
|
64
64
|
Requires-Dist: xlrd>=2.0; extra == 'all'
|
|
@@ -92,7 +92,7 @@ Requires-Dist: pre-commit>=3.5.0; extra == 'dev'
|
|
|
92
92
|
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
93
93
|
Requires-Dist: pyyaml>=6.0; extra == 'dev'
|
|
94
94
|
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
95
|
-
Requires-Dist: sqlglot
|
|
95
|
+
Requires-Dist: sqlglot<30.22,>=30.21.0; extra == 'dev'
|
|
96
96
|
Requires-Dist: tables>=3.10; extra == 'dev'
|
|
97
97
|
Requires-Dist: tox-uv>=1.13.1; extra == 'dev'
|
|
98
98
|
Requires-Dist: twine>=6.1.0; extra == 'dev'
|
|
@@ -112,7 +112,7 @@ Requires-Dist: pyyaml>=6.0; extra == 'formats'
|
|
|
112
112
|
Requires-Dist: tables>=3.10; extra == 'formats'
|
|
113
113
|
Requires-Dist: xlrd>=2.0; extra == 'formats'
|
|
114
114
|
Provides-Extra: formatter
|
|
115
|
-
Requires-Dist: sqlglot
|
|
115
|
+
Requires-Dist: sqlglot<30.22,>=30.21.0; extra == 'formatter'
|
|
116
116
|
Provides-Extra: map
|
|
117
117
|
Requires-Dist: tkintermapview>=1.29; extra == 'map'
|
|
118
118
|
Provides-Extra: mssql
|
|
@@ -451,7 +451,7 @@ execsql format --no-sql --in-place scripts/
|
|
|
451
451
|
```yaml
|
|
452
452
|
repos:
|
|
453
453
|
- repo: https://github.com/geocoug/execsql
|
|
454
|
-
rev: v2.
|
|
454
|
+
rev: v2.26.0
|
|
455
455
|
hooks:
|
|
456
456
|
- id: execsql-format
|
|
457
457
|
- id: execsql-lint
|
|
@@ -128,14 +128,14 @@ command, naming their replacement (`execsql run --ping` for `--ping`). The one e
|
|
|
128
128
|
today — a script named exactly like a command — is recorded under
|
|
129
129
|
[Changed Behavior](#cli-interface).
|
|
130
130
|
|
|
131
|
-
| Command | Description
|
|
132
|
-
| ---------------- |
|
|
133
|
-
| `execsql run` | The explicit spelling of the upstream positional form. Identical behavior.
|
|
134
|
-
| `execsql format` | The formatter, reached through the main command. It replaced the standalone `execsql-format` console script, which was removed. The published pre-commit hook **id** is still `execsql-format`, so downstream `.pre-commit-config.yaml` files need no change — only the hook's internal `entry` moved. Formatter for normalizing metacommand indentation and uppercasing SQL keywords. Supports `--check`, `--in-place`, `--indent N` (controls both metacommand and SQL indentation), `--leading-comma` (commas at start of lines), `--no-sql` (skip SQL reformatting), `-f`/`--script-encoding` (formerly `--encoding`, still accepted), and `--config`; `-` formats stdin to stdout. Also available as a [pre-commit hook](../guides/formatter.md) — the published hook defaults to `args: [--in-place]` so downstream consumers get formatting on commit without extra wiring. SQL reformatting (the optional sqlglot pass) requires the `[formatter]` extra as of 2.19.0; `--no-sql` works without it. |
|
|
135
|
-
| `execsql lint` | Static checks over files *and directories*, walking directories recursively for `*.sql`; `-` reads stdin. Scripts are read with `-f`/`--script-encoding` or `[encoding] script` from config, like `run`. Every issue carries a [rule code](../reference/lint.md#rules); `--select` / `--ignore` choose rules, `--output-format json` feeds tools, and `--statistics` counts issues per rule. It replaced the `--lint` flag, which checked only the one script it was given.
|
|
136
|
-
| `execsql config` | List every config option with its current value, default, and the file that set it, resolved as a run would (pass a script to include its directory's `execsql.conf`). Passwords are masked. `--init` prints the template (replaces `--init-config`). `--validate` reports every problem in every config file a run reads, with file and line: invalid values and unparsable files as errors, unknown or misplaced sections and keys as warnings — upstream stopped at the first bad value and ignored unknown names silently.
|
|
137
|
-
| `execsql list` | `metacommands`, `encodings`, `plugins` or `keywords`, as text or JSON. Replaces `-m`, `-y`, `--list-plugins` and `--dump-keywords`; `-m` and `-y` are upstream flags and keep working as hidden aliases, deprecated when used without a command.
|
|
138
|
-
| `execsql init` | Set up a project: `execsql.conf` from the template, a script with a header (from the upstream script template), and the `execsql-format` / `execsql-lint` pre-commit hooks. Never overwrites without `--force`, and never rewrites an existing `.pre-commit-config.yaml`.
|
|
131
|
+
| Command | Description |
|
|
132
|
+
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
133
|
+
| `execsql run` | The explicit spelling of the upstream positional form. Identical behavior. |
|
|
134
|
+
| `execsql format` | The formatter, reached through the main command. It replaced the standalone `execsql-format` console script, which was removed. The published pre-commit hook **id** is still `execsql-format`, so downstream `.pre-commit-config.yaml` files need no change — only the hook's internal `entry` moved. Formatter for normalizing metacommand indentation and uppercasing SQL keywords. Supports `--check`, `--in-place`, `--indent N` (controls both metacommand and SQL indentation), `--leading-comma` (commas at start of lines), `--no-sql` (skip SQL reformatting), `--rewrite-sql` (accept sqlglot's rewrites of SQL text; off by default, so only layout changes), `-f`/`--script-encoding` (formerly `--encoding`, still accepted), and `--config`; `-` formats stdin to stdout. Also available as a [pre-commit hook](../guides/formatter.md) — the published hook defaults to `args: [--in-place]` so downstream consumers get formatting on commit without extra wiring. SQL reformatting (the optional sqlglot pass) requires the `[formatter]` extra as of 2.19.0; `--no-sql` works without it. |
|
|
135
|
+
| `execsql lint` | Static checks over files *and directories*, walking directories recursively for `*.sql`; `-` reads stdin. Scripts are read with `-f`/`--script-encoding` or `[encoding] script` from config, like `run`. Every issue carries a [rule code](../reference/lint.md#rules); `--select` / `--ignore` choose rules, `--output-format json` feeds tools, and `--statistics` counts issues per rule. It replaced the `--lint` flag, which checked only the one script it was given. |
|
|
136
|
+
| `execsql config` | List every config option with its current value, default, and the file that set it, resolved as a run would (pass a script to include its directory's `execsql.conf`). Passwords are masked. `--init` prints the template (replaces `--init-config`). `--validate` reports every problem in every config file a run reads, with file and line: invalid values and unparsable files as errors, unknown or misplaced sections and keys as warnings — upstream stopped at the first bad value and ignored unknown names silently. |
|
|
137
|
+
| `execsql list` | `metacommands`, `encodings`, `plugins` or `keywords`, as text or JSON. Replaces `-m`, `-y`, `--list-plugins` and `--dump-keywords`; `-m` and `-y` are upstream flags and keep working as hidden aliases, deprecated when used without a command. |
|
|
138
|
+
| `execsql init` | Set up a project: `execsql.conf` from the template, a script with a header (from the upstream script template), and the `execsql-format` / `execsql-lint` pre-commit hooks. Never overwrites without `--force`, and never rewrites an existing `.pre-commit-config.yaml`. |
|
|
139
139
|
|
|
140
140
|
Formatter correctness notes added in the 2.19.x line:
|
|
141
141
|
|
|
@@ -80,6 +80,7 @@ one run.
|
|
|
80
80
|
| `--sql`, `--no-sql` | `[format] sql`, else `--sql` | Reformat SQL via sqlglot, or skip it and only normalize metacommand indentation and keyword casing. `--no-sql` works without the `[formatter]` extra. |
|
|
81
81
|
| `--indent N` | `[format] indent`, else `4` | Spaces per indent level. Controls both metacommand block depth and SQL indentation (columns, subqueries, etc). |
|
|
82
82
|
| `--leading-comma`, `--no-leading-comma` | `[format] leading_comma`, else off | Place commas at the start of lines instead of the end (e.g. ` , col2` instead of `col1,`). |
|
|
83
|
+
| `--rewrite-sql`, `--no-rewrite-sql` | `[format] rewrite_sql`, else off | Also let sqlglot rewrite SQL text (`x::int` as `CAST(x AS INT)`, an alias with `AS`). Off, a statement sqlglot would rewrite is kept as written. See [Layout only](#layout-only). |
|
|
83
84
|
| `-f`, `--script-encoding NAME` | config, else `utf-8` | Text encoding used to read and write SQL files. Pass `cp1252`, `latin-1`, `shift_jis`, etc. for files saved by non-UTF-8 editors. Without it, `[encoding] script` from a [config file](../reference/configuration.md#configuration) applies. The old spelling `--encoding` still works. |
|
|
84
85
|
| `--config FILE` | — | An extra config file to read `[encoding] script` from. Config files are read once, from the system, user and working-directory locations plus this file — not from each script's directory. |
|
|
85
86
|
|
|
@@ -121,6 +122,33 @@ SQL statements between metacommands are re-indented to match the current block d
|
|
|
121
122
|
|
|
122
123
|
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.
|
|
123
124
|
|
|
125
|
+
#### sqlglot version { #sqlglot-version }
|
|
126
|
+
|
|
127
|
+
The SQL layout comes from sqlglot, and sqlglot's output changes between its releases. So that the same script formats the same way on every machine, in CI and in the pre-commit hook, execsql2 pins it: the `[formatter]` extra requires sqlglot 30.21.x and the `execsql-format` hook installs exactly 30.21.0. A new execsql2 release may move the pin; its changelog says so, and the first run after upgrading can reformat files whose content did not change.
|
|
128
|
+
|
|
129
|
+
Conditions joined by `AND` / `OR` go on one line when their combined text is at most 120 characters, and one per line otherwise. sqlglot measures the conditions without the indentation and the spaces between them, so a joined line can run a few characters past 120.
|
|
130
|
+
|
|
131
|
+
#### Layout only, or rewrite { #layout-only }
|
|
132
|
+
|
|
133
|
+
sqlglot does more than lay SQL out: it writes the SQL it parsed in its own preferred form. By default the formatter changes only layout and keyword case. A statement sqlglot would also rewrite is kept exactly as written, while the statements around it are still formatted.
|
|
134
|
+
|
|
135
|
+
| You wrote | sqlglot writes |
|
|
136
|
+
| --------------------------- | ------------------------------------- |
|
|
137
|
+
| `x::int` | `CAST(x AS INT)` |
|
|
138
|
+
| `count(*) n` | `COUNT(*) AS n` |
|
|
139
|
+
| `integer`, `numeric(10,2)` | `INT`, `DECIMAL(10, 2)` |
|
|
140
|
+
| `BTRIM(x)`, `LTRIM(x, 'a')` | `TRIM(x)`, `TRIM(LEADING 'a' FROM x)` |
|
|
141
|
+
| `a != b` | `a <> b` |
|
|
142
|
+
|
|
143
|
+
Each pair means the same to PostgreSQL. To accept sqlglot's form, so every statement is formatted, pass `--rewrite-sql` or set it in a config file:
|
|
144
|
+
|
|
145
|
+
```ini
|
|
146
|
+
[format]
|
|
147
|
+
rewrite_sql = Yes
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
With it on, the rewrites a statement gets can change when the pinned sqlglot changes (see above). Turning it off later does not undo rewrites already written; it only stops new ones.
|
|
151
|
+
|
|
124
152
|
#### Comment handling
|
|
125
153
|
|
|
126
154
|
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:
|
|
@@ -233,7 +261,7 @@ select id,name,created_at from users where active = true order by name;
|
|
|
233
261
|
```yaml
|
|
234
262
|
repos:
|
|
235
263
|
- repo: https://github.com/geocoug/execsql
|
|
236
|
-
rev: v2.
|
|
264
|
+
rev: v2.26.0
|
|
237
265
|
hooks:
|
|
238
266
|
- id: execsql-format
|
|
239
267
|
- id: execsql-lint # optional: fail the commit on lint errors
|
|
@@ -405,6 +405,9 @@ the command line always wins. A run ignores this section.
|
|
|
405
405
|
`sql`
|
|
406
406
|
: Reformat SQL with sqlglot (needs the `[formatter]` extra). `No` normalizes metacommands only. Default: Yes. Equivalent to `--sql` / `--no-sql`.
|
|
407
407
|
|
|
408
|
+
`rewrite_sql`
|
|
409
|
+
: Also let sqlglot rewrite SQL text, such as `x::int` as `CAST(x AS INT)` or an alias with `AS`. With `No`, a statement sqlglot would rewrite is kept as written (see [Layout only](../guides/formatter.md#layout-only)). Default: No. Equivalent to `--rewrite-sql` / `--no-rewrite-sql`.
|
|
410
|
+
|
|
408
411
|
## Section `lint` { #config_lint }
|
|
409
412
|
|
|
410
413
|
Rule selection for [`execsql lint`](lint.md#config). A run ignores this section.
|
|
@@ -158,7 +158,7 @@ The `execsql-lint` [pre-commit](https://pre-commit.com/) hook runs `execsql lint
|
|
|
158
158
|
```yaml
|
|
159
159
|
repos:
|
|
160
160
|
- repo: https://github.com/geocoug/execsql
|
|
161
|
-
rev: v2.
|
|
161
|
+
rev: v2.26.0
|
|
162
162
|
hooks:
|
|
163
163
|
- id: execsql-lint
|
|
164
164
|
args: [--ignore, V002] # optional: any execsql lint option
|
|
@@ -313,7 +313,7 @@ A `!!variable!!` is referenced, but nothing in the script defines it. At run tim
|
|
|
313
313
|
|
|
314
314
|
A definition is any metacommand in the same file that sets a variable:
|
|
315
315
|
|
|
316
|
-
- the SUB family: `SUB`, `SUB_EMPTY`, `SUB_ADD`, `SUB_APPEND`, `SUBDATA`, `SUB_LOCAL`, `SUB_TEMPFILE`, `SUB_ENCRYPT`, `SUB_DECRYPT`, the keys of `SUB_QUERYSTRING`, and the keys of a `SUB_INI` file that
|
|
316
|
+
- the SUB family: `SUB`, `SUB_EMPTY`, `SUB_ADD`, `SUB_APPEND`, `SUBDATA`, `SUB_LOCAL`, `SUB_TEMPFILE`, `SUB_ENCRYPT`, `SUB_DECRYPT`, the keys of `SUB_QUERYSTRING`, and the keys of a `SUB_INI` file that lint can read (a regular file of at most 1 MiB that parses as INI);
|
|
317
317
|
- the prompts that store an answer: `PROMPT ENTER_SUB`, `ASK ... SUB`, `PROMPT ASK ... SUB` (with or without `COMPARE`), `PROMPT OPENFILE SUB`, `PROMPT SAVEFILE SUB` and `PROMPT DIRECTORY SUB` (every variable named after `SUB`), and both variables of `PROMPT CREDENTIALS`.
|
|
318
318
|
|
|
319
319
|
Definitions inside `BEGIN SCRIPT` blocks that the file runs with `EXECUTE SCRIPT` count too, and so does a definition that comes after the first use.
|
|
@@ -324,6 +324,7 @@ Not reported:
|
|
|
324
324
|
|
|
325
325
|
- System variables (`!!$DATE_TAG!!`, `!!$DB_NAME!!`, …), `!!$ARG_n!!` set with `-a`, and `!!$COUNTER_n!!`.
|
|
326
326
|
- References with the `&` (environment), `@` (column), `~` (local), `#` and `+` prefixes, which resolve only at run time.
|
|
327
|
+
- A name built from another variable, such as `!!N_!!CHECK_GROUP!!_CHECKS!!`. execsql substitutes `!!CHECK_GROUP!!` first, so the outer name is only known at run time. Lint checks the inner variable: if `CHECK_GROUP` is undefined, `!!CHECK_GROUP!!` is reported, not the fragments `!!N_!!` and `!!_CHECKS!!`.
|
|
327
328
|
|
|
328
329
|
Variables defined somewhere lint cannot see are reported: in a configuration file, on the command line other than as `$ARG_n`, or in a file pulled in with `INCLUDE` (lint does not read `INCLUDE`d files for definitions). If that is how a library works, `--ignore V001` for those scripts.
|
|
329
330
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "execsql2"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.26.0"
|
|
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" }
|
|
@@ -71,7 +71,7 @@ auth-plaintext = ["keyring>=25.0", "keyrings.alt>=5.0"]
|
|
|
71
71
|
auth-encrypted = ["keyring>=25.0", "keyrings.alt>=5.0", "pycryptodome>=3.20"]
|
|
72
72
|
upsert = ["pg-upsert>=1.25.0"]
|
|
73
73
|
map = ["tkintermapview>=1.29"]
|
|
74
|
-
formatter = ["sqlglot>=
|
|
74
|
+
formatter = ["sqlglot>=30.21.0,<30.22"] # pinned: output changes between sqlglot releases (#72)
|
|
75
75
|
# Convenience groups
|
|
76
76
|
all-db = [
|
|
77
77
|
"psycopg[binary]>=3.1,<4",
|
|
@@ -177,7 +177,7 @@ skip-magic-trailing-comma = false
|
|
|
177
177
|
line-ending = "auto"
|
|
178
178
|
|
|
179
179
|
[tool.bumpversion]
|
|
180
|
-
current_version = "2.
|
|
180
|
+
current_version = "2.26.0"
|
|
181
181
|
commit = true
|
|
182
182
|
tag = true
|
|
183
183
|
tag_name = "v{new_version}"
|
|
@@ -51,6 +51,15 @@ def format_cmd(
|
|
|
51
51
|
help="Commas at the start of lines instead of the end. Default: [format] leading_comma, else off.",
|
|
52
52
|
show_default=False,
|
|
53
53
|
),
|
|
54
|
+
rewrite_sql: bool | None = typer.Option(
|
|
55
|
+
None,
|
|
56
|
+
"--rewrite-sql/--no-rewrite-sql",
|
|
57
|
+
help=(
|
|
58
|
+
"Also let sqlglot rewrite SQL text (x::int as CAST(x AS INT), BTRIM as TRIM, an alias with AS); "
|
|
59
|
+
"without it such a statement is kept as written. Default: [format] rewrite_sql, else off."
|
|
60
|
+
),
|
|
61
|
+
show_default=False,
|
|
62
|
+
),
|
|
54
63
|
script_encoding: ScriptEncodingOpt = None,
|
|
55
64
|
# The old spelling of --script-encoding, kept working but out of --help.
|
|
56
65
|
encoding: str | None = typer.Option(None, "--encoding", metavar="NAME", hidden=True),
|
|
@@ -92,6 +101,7 @@ def format_cmd(
|
|
|
92
101
|
no_sql=no_sql,
|
|
93
102
|
indent=conf.format_indent if indent is None else indent,
|
|
94
103
|
leading_comma=conf.format_leading_comma if leading_comma is None else leading_comma,
|
|
104
|
+
rewrite_sql=conf.format_rewrite_sql if rewrite_sql is None else rewrite_sql,
|
|
95
105
|
encoding=script_encoding or encoding or _configured_script_encoding(conf) or "utf-8",
|
|
96
106
|
),
|
|
97
107
|
)
|
|
@@ -243,6 +243,12 @@ _RX_PROMPT_CREDENTIALS = re.compile(
|
|
|
243
243
|
)
|
|
244
244
|
|
|
245
245
|
_RX_VAR_REF = re.compile(r"!!([$@&~#+]?\w+)!!", re.I)
|
|
246
|
+
# Every candidate reference, including one nested in another's name
|
|
247
|
+
# (``!!N_!!GROUP!!_CHECKS!!``), which _RX_VAR_REF's left-to-right scan skips.
|
|
248
|
+
_RX_VAR_REF_ANY = re.compile(r"(?=!!([$@&~#+]?\w+)!!)")
|
|
249
|
+
# Stands for a substituted value in _unresolved_var_refs: a word character
|
|
250
|
+
# (so an enclosing name still matches) that no script name contains.
|
|
251
|
+
_SUBSTITUTED = "ª"
|
|
246
252
|
|
|
247
253
|
|
|
248
254
|
# ---------------------------------------------------------------------------
|
|
@@ -424,54 +430,108 @@ def _extract_var_definition(
|
|
|
424
430
|
_read_ini_vars(ini_file, ini_section, script_dir, defined)
|
|
425
431
|
|
|
426
432
|
|
|
433
|
+
# Larger than any real SUB_INI file; lint reads no more than this.
|
|
434
|
+
_MAX_INI_BYTES = 1024 * 1024
|
|
435
|
+
|
|
436
|
+
|
|
427
437
|
def _read_ini_vars(
|
|
428
438
|
ini_file: str,
|
|
429
439
|
section: str,
|
|
430
440
|
script_dir: Path | None,
|
|
431
441
|
defined_vars: set[str],
|
|
432
442
|
) -> None:
|
|
433
|
-
"""Read an INI file and register its section keys as defined variables.
|
|
443
|
+
"""Read an INI file and register its section keys as defined variables.
|
|
444
|
+
|
|
445
|
+
Only a regular file up to :data:`_MAX_INI_BYTES` is read, so a script
|
|
446
|
+
naming a FIFO or a device (``/dev/zero``) cannot hang lint or the
|
|
447
|
+
language server; a file that is unreadable or not valid INI defines
|
|
448
|
+
nothing.
|
|
449
|
+
"""
|
|
434
450
|
from configparser import ConfigParser
|
|
451
|
+
from configparser import Error as ConfigError
|
|
435
452
|
|
|
436
453
|
p = Path(ini_file)
|
|
437
454
|
if not p.is_absolute() and script_dir is not None:
|
|
438
455
|
p = script_dir / p
|
|
439
456
|
|
|
440
|
-
if not p.exists():
|
|
441
|
-
return
|
|
442
|
-
|
|
443
457
|
cp = ConfigParser()
|
|
444
|
-
|
|
458
|
+
try:
|
|
459
|
+
if not p.is_file() or p.stat().st_size > _MAX_INI_BYTES:
|
|
460
|
+
return
|
|
461
|
+
cp.read_string(p.read_text(encoding="utf-8"), source=str(p))
|
|
462
|
+
except (OSError, UnicodeDecodeError, ConfigError):
|
|
463
|
+
return
|
|
445
464
|
if cp.has_section(section):
|
|
446
465
|
for key, _value in cp.items(section):
|
|
447
466
|
defined_vars.add(key.upper())
|
|
448
467
|
|
|
449
468
|
|
|
450
|
-
def
|
|
451
|
-
raw_name
|
|
452
|
-
source: str,
|
|
453
|
-
line_no: int,
|
|
454
|
-
defined_vars: set[str],
|
|
455
|
-
issues: list[_Issue],
|
|
456
|
-
) -> None:
|
|
457
|
-
"""Emit a warning if *raw_name* looks like an undefined user variable."""
|
|
458
|
-
if not raw_name:
|
|
459
|
-
return
|
|
460
|
-
|
|
469
|
+
def _is_known_var(raw_name: str, defined_vars: set[str]) -> bool:
|
|
470
|
+
"""Whether execsql may substitute *raw_name* (as written, with its sigil) at run time."""
|
|
461
471
|
sigil = raw_name[0] if raw_name[0] in ("$", "@", "&", "~", "#", "+") else ""
|
|
462
472
|
name = raw_name[len(sigil) :]
|
|
463
473
|
|
|
464
474
|
# Skip non-$ sigil prefixes — resolved at runtime
|
|
465
475
|
if sigil in ("@", "&", "~", "#", "+"):
|
|
466
|
-
return
|
|
476
|
+
return True
|
|
467
477
|
|
|
468
478
|
if sigil == "$":
|
|
469
479
|
# System variables: $ARG_N is set with -a/--assign-arg, $COUNTER_N by
|
|
470
480
|
# CounterVars, the rest by execsql itself. A SUB cannot define one.
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
481
|
+
return bool(re.match(r"^(?:ARG|COUNTER)_\d+$", name, re.I)) or name.upper() in _get_builtin_vars()
|
|
482
|
+
# User variables, defined by a SUB-family metacommand or a prompt.
|
|
483
|
+
return name.upper() in defined_vars
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
def _unresolved_var_refs(text: str, defined_vars: set[str]) -> list[str]:
|
|
487
|
+
"""The variable names in *text* that execsql would leave unsubstituted, as written.
|
|
488
|
+
|
|
489
|
+
execsql substitutes a known variable wherever ``!!name!!`` appears and
|
|
490
|
+
repeats until nothing changes, so a variable written inside another's
|
|
491
|
+
name (``!!N_!!GROUP!!_CHECKS!!``) is replaced first, and the outer name
|
|
492
|
+
is only known at run time: it is not checked. Here each known variable
|
|
493
|
+
is replaced by a placeholder character, a name holding one counts as
|
|
494
|
+
known, and that repeats until nothing is replaced.
|
|
495
|
+
|
|
496
|
+
In a run of unknown candidates that share delimiters, the inner ones
|
|
497
|
+
(every second, from the second) are reported: with ``GROUP`` undefined,
|
|
498
|
+
``!!N_!!GROUP!!_CHECKS!!`` reports ``GROUP``, not the fragments ``N_``
|
|
499
|
+
and ``_CHECKS``.
|
|
500
|
+
"""
|
|
501
|
+
while True:
|
|
502
|
+
parts: list[str] = []
|
|
503
|
+
end = 0
|
|
504
|
+
for m in _RX_VAR_REF_ANY.finditer(text):
|
|
505
|
+
name = m.group(1)
|
|
506
|
+
if m.start() >= end and (_SUBSTITUTED in name or _is_known_var(name, defined_vars)):
|
|
507
|
+
parts += [text[end : m.start()], _SUBSTITUTED]
|
|
508
|
+
end = m.start() + len(name) + 4
|
|
509
|
+
if not parts:
|
|
510
|
+
break
|
|
511
|
+
text = "".join([*parts, text[end:]])
|
|
512
|
+
|
|
513
|
+
unresolved: list[str] = []
|
|
514
|
+
run: list[str] = []
|
|
515
|
+
end = -1
|
|
516
|
+
for m in _RX_VAR_REF_ANY.finditer(text):
|
|
517
|
+
if run and m.start() != end - 2: # not sharing the previous candidate's closing !!
|
|
518
|
+
unresolved.extend(run if len(run) == 1 else run[1::2])
|
|
519
|
+
run = []
|
|
520
|
+
run.append(m.group(1))
|
|
521
|
+
end = m.start() + len(m.group(1)) + 4
|
|
522
|
+
unresolved.extend(run if len(run) == 1 else run[1::2])
|
|
523
|
+
return unresolved
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
def _check_var_ref(
|
|
527
|
+
raw_name: str,
|
|
528
|
+
source: str,
|
|
529
|
+
line_no: int,
|
|
530
|
+
defined_vars: set[str],
|
|
531
|
+
issues: list[_Issue],
|
|
532
|
+
) -> None:
|
|
533
|
+
"""Emit a warning if *raw_name* looks like an undefined user variable."""
|
|
534
|
+
if not raw_name or _is_known_var(raw_name, defined_vars):
|
|
475
535
|
return
|
|
476
536
|
|
|
477
537
|
issues.append(
|
|
@@ -735,7 +795,7 @@ def _collect_var_references(nodes: list[Node], seen: set[str]) -> None:
|
|
|
735
795
|
"""Record every variable read anywhere beneath *nodes*: ``!!var!!``, or ``sub_defined(var)`` / ``sub_empty(var)``."""
|
|
736
796
|
for node in nodes:
|
|
737
797
|
for text in _referencing_text(node):
|
|
738
|
-
for m in
|
|
798
|
+
for m in _RX_VAR_REF_ANY.finditer(text):
|
|
739
799
|
seen.add(m.group(1).lstrip("$@&~#+").upper())
|
|
740
800
|
for m in _RX_VAR_TEST.finditer(text):
|
|
741
801
|
seen.add(m.group(1).lstrip("$@&~#+").upper())
|
|
@@ -826,14 +886,14 @@ def _lint_nodes(
|
|
|
826
886
|
|
|
827
887
|
# -- Variable references in SQL --
|
|
828
888
|
if isinstance(node, SqlStatement):
|
|
829
|
-
for
|
|
830
|
-
_check_var_ref(
|
|
889
|
+
for name in _unresolved_var_refs(node.text, defined_vars):
|
|
890
|
+
_check_var_ref(name, src, lno, defined_vars, issues)
|
|
831
891
|
|
|
832
892
|
# -- Metacommand checks --
|
|
833
893
|
elif isinstance(node, MetaCommandStatement):
|
|
834
894
|
_check_metacommand(node, issues)
|
|
835
|
-
for
|
|
836
|
-
_check_var_ref(
|
|
895
|
+
for name in _unresolved_var_refs(node.command, defined_vars):
|
|
896
|
+
_check_var_ref(name, src, lno, defined_vars, issues)
|
|
837
897
|
|
|
838
898
|
# -- IncludeDirective checks --
|
|
839
899
|
elif isinstance(node, IncludeDirective):
|
|
@@ -379,6 +379,7 @@ class ConfigData:
|
|
|
379
379
|
self._get_int(cp, self._FORMAT_SECTION, "indent", "format_indent")
|
|
380
380
|
self._get_bool(cp, self._FORMAT_SECTION, "leading_comma", "format_leading_comma")
|
|
381
381
|
self._get_bool(cp, self._FORMAT_SECTION, "sql", "format_sql")
|
|
382
|
+
self._get_bool(cp, self._FORMAT_SECTION, "rewrite_sql", "format_rewrite_sql")
|
|
382
383
|
self._get_str(cp, self._LINT_SECTION, "select", "lint_select")
|
|
383
384
|
self._get_str(cp, self._LINT_SECTION, "ignore", "lint_ignore")
|
|
384
385
|
self._get_bool(cp, self._LINT_SECTION, "strict", "lint_strict")
|
|
@@ -555,6 +556,7 @@ class ConfigData:
|
|
|
555
556
|
self.format_indent = 4
|
|
556
557
|
self.format_leading_comma = False
|
|
557
558
|
self.format_sql = True
|
|
559
|
+
self.format_rewrite_sql = False
|
|
558
560
|
self.lint_select: str | None = None
|
|
559
561
|
self.lint_ignore: str | None = None
|
|
560
562
|
self.lint_strict = False
|
|
@@ -369,6 +369,9 @@
|
|
|
369
369
|
#leading_comma=No
|
|
370
370
|
# Reformat SQL with sqlglot (needs the [formatter] extra). No = metacommands only.
|
|
371
371
|
#sql=Yes
|
|
372
|
+
# Also let sqlglot rewrite SQL text: x::int as CAST(x AS INT), BTRIM as TRIM,
|
|
373
|
+
# an alias with AS. No = a statement it would rewrite is kept as written.
|
|
374
|
+
#rewrite_sql=No
|
|
372
375
|
|
|
373
376
|
|
|
374
377
|
[lint]
|