execsql2 2.23.1__tar.gz → 2.25.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/.github/dependabot.yml +48 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/.github/workflows/ci-cd.yml +77 -7
- {execsql2-2.23.1 → execsql2-2.25.0}/.pre-commit-config.yaml +1 -0
- execsql2-2.25.0/.pre-commit-hooks.yaml +17 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/CHANGELOG.md +114 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/CONTRIBUTING.md +4 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/PKG-INFO +122 -63
- {execsql2-2.23.1 → execsql2-2.25.0}/README.md +118 -59
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/about/divergence.md +110 -52
- execsql2-2.25.0/docs/api/index.md +119 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/adding_db_adapters.md +18 -20
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/adding_metacommands.md +10 -10
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/architecture.md +30 -36
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/releasing.md +35 -25
- execsql2-2.25.0/docs/getting-started/installation.md +84 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/getting-started/requirements.md +5 -30
- execsql2-2.25.0/docs/getting-started/syntax.md +519 -0
- execsql2-2.25.0/docs/guides/debugging.md +121 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/examples.md +20 -16
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/formatter.md +83 -35
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/logging.md +10 -10
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/usage.md +2 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/reference/configuration.md +68 -6
- execsql2-2.25.0/docs/reference/lint.md +373 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/reference/metacommands.md +71 -21
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/reference/security.md +26 -5
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/reference/substitution_vars.md +2 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/extras/plugin-template/README.md +2 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +2 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/extras/plugin-template/tests/test_plugin.py.example +3 -2
- execsql2-2.25.0/extras/vscode-execsql/.vscodeignore +3 -0
- execsql2-2.25.0/extras/vscode-execsql/LICENSE.txt +12 -0
- execsql2-2.25.0/extras/vscode-execsql/icon.png +0 -0
- execsql2-2.25.0/extras/vscode-execsql/package.json +46 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/justfile +21 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/pyproject.toml +34 -7
- {execsql2-2.23.1 → execsql2-2.25.0}/scripts/benchmarks/run_benchmarks.py +1 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/scripts/generate_vscode_grammar.py +6 -6
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/api.py +169 -160
- execsql2-2.25.0/src/execsql/cli/__init__.py +83 -0
- execsql2-2.25.0/src/execsql/cli/application.py +309 -0
- execsql2-2.25.0/src/execsql/cli/commands/__init__.py +13 -0
- execsql2-2.25.0/src/execsql/cli/commands/config.py +205 -0
- execsql2-2.25.0/src/execsql/cli/commands/format.py +100 -0
- execsql2-2.25.0/src/execsql/cli/commands/init.py +135 -0
- execsql2-2.25.0/src/execsql/cli/commands/lint.py +225 -0
- execsql2-2.25.0/src/execsql/cli/commands/listing.py +81 -0
- execsql2-2.25.0/src/execsql/cli/commands/run.py +459 -0
- execsql2-2.25.0/src/execsql/cli/dispatch.py +66 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/cli/dsn.py +11 -4
- execsql2-2.25.0/src/execsql/cli/help.py +302 -0
- execsql2-2.25.0/src/execsql/cli/lint.py +1186 -0
- execsql2-2.25.0/src/execsql/cli/options.py +108 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/cli/run.py +96 -32
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/config.py +256 -173
- execsql2-2.25.0/src/execsql/config_validation.py +282 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/data/execsql.conf.template +38 -5
- execsql2-2.25.0/src/execsql/data/script_header.sql +23 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/access.py +29 -8
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/base.py +40 -8
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/dsn.py +13 -4
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/duckdb.py +3 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/factory.py +13 -4
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/firebird.py +21 -7
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/mysql.py +37 -16
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/oracle.py +49 -16
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/postgres.py +30 -6
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/sqlite.py +7 -9
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/sqlserver.py +25 -8
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/debug/repl.py +51 -193
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exceptions.py +9 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/delimited.py +87 -28
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/xlsx.py +24 -9
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/zip.py +1 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/format.py +115 -76
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/gui/desktop.py +1 -3
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/gui/tui.py +2 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/base.py +35 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/csv.py +3 -1
- execsql2-2.25.0/src/execsql/interactive.py +232 -0
- execsql2-2.25.0/src/execsql/manifest.py +200 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/conditions.py +7 -8
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/control.py +2 -3
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/data.py +4 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/debug.py +2 -4
- execsql2-2.25.0/src/execsql/metacommands/effects.py +124 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/io_fileops.py +62 -37
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/io_import.py +0 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/prompt.py +2 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/upsert.py +5 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/models.py +3 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/parser.py +14 -5
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/plugins.py +24 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/__init__.py +0 -9
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/ast.py +1 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/engine.py +46 -104
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/executor.py +162 -39
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/parser.py +167 -118
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/state.py +34 -11
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/state.pyi +11 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/types.py +22 -13
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/auth.py +169 -24
- execsql2-2.25.0/src/execsql/utils/color.py +18 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/datetime.py +55 -17
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/errors.py +82 -10
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/fileio.py +404 -117
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/gui.py +3 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/mail.py +37 -12
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/README.md +1 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/test_cli.py +111 -63
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/test_cli_e2e.py +48 -15
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/test_cli_run.py +42 -41
- execsql2-2.25.0/tests/cli/test_cli_surface.py +232 -0
- execsql2-2.25.0/tests/cli/test_commands.py +589 -0
- execsql2-2.25.0/tests/cli/test_config_validate.py +294 -0
- execsql2-2.25.0/tests/cli/test_dispatch.py +456 -0
- execsql2-2.25.0/tests/cli/test_error_location.py +32 -0
- execsql2-2.25.0/tests/cli/test_init.py +119 -0
- execsql2-2.25.0/tests/cli/test_lint.py +1192 -0
- execsql2-2.25.0/tests/cli/test_lint_fixtures.py +161 -0
- execsql2-2.25.0/tests/cli/test_log_exit_record.py +71 -0
- execsql2-2.25.0/tests/cli/test_manifest.py +172 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/test_ping.py +3 -3
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/test_profile.py +8 -5
- execsql2-2.25.0/tests/cli/test_sigterm.py +105 -0
- execsql2-2.25.0/tests/cli/test_undeclared_imports.py +45 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/conftest.py +51 -1
- execsql2-2.25.0/tests/data/formatter_shapes/escapes_and_literals.sql +58 -0
- execsql2-2.25.0/tests/data/formatter_shapes/substitution_and_metacommands.sql +43 -0
- execsql2-2.25.0/tests/data/formatter_shapes/unparsable_sql.sql +41 -0
- execsql2-2.25.0/tests/data/lint/conditions_and_blocks.sql +222 -0
- execsql2-2.25.0/tests/data/lint/does_not_parse.sql +39 -0
- execsql2-2.25.0/tests/data/lint/every_metacommand.sql +289 -0
- execsql2-2.25.0/tests/data/lint/invalid.sql +134 -0
- execsql2-2.25.0/tests/db/test_copy_new.py +125 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_db_adapters_mocked.py +9 -13
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_db_adapters_mocked_extra.py +43 -3
- execsql2-2.25.0/tests/db/test_factory_postgres_encoding.py +27 -0
- execsql2-2.25.0/tests/db/test_import_atomic.py +100 -0
- execsql2-2.25.0/tests/db/test_import_replacement_quoted.py +22 -0
- execsql2-2.25.0/tests/db/test_import_short_rows.py +60 -0
- execsql2-2.25.0/tests/db/test_import_timezones.py +68 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_mysql_inprocess.py +1 -4
- execsql2-2.25.0/tests/db/test_new_table_checks.py +152 -0
- execsql2-2.25.0/tests/db/test_oracle_driver.py +80 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_postgres_inprocess.py +0 -4
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_sqlite_extra.py +11 -11
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_sqlserver_inprocess.py +25 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_transactions.py +12 -15
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_delimited.py +0 -18
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_xlsx.py +1 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_xlsx.py +69 -2
- execsql2-2.25.0/tests/importers/test_csv_blank_lines.py +108 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_csv_edge_cases.py +36 -9
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/conftest.py +1 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/test_dsn.py +1 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/test_mysql.py +73 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/test_postgres.py +129 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/test_sqlite.py +1 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_breakpoint.py +1 -101
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_conditions_extra.py +2 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands.py +5 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_data.py +7 -7
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_pg_upsert.py +1 -1
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_row_count.py +8 -5
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/test_sql_scripts.py +4 -2
- execsql2-2.25.0/tests/security/test_log_secrets.py +214 -0
- execsql2-2.25.0/tests/test_api_errors.py +106 -0
- execsql2-2.25.0/tests/test_api_filewriter.py +345 -0
- execsql2-2.25.0/tests/test_api_isolation.py +92 -0
- execsql2-2.25.0/tests/test_api_subprocess.py +76 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_ast_parser.py +124 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_bundled_templates.py +3 -3
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_config.py +2 -12
- execsql2-2.25.0/tests/test_date_inference.py +113 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_debug_repl.py +2 -171
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_engine.py +52 -81
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_error_messages.py +3 -3
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_executor.py +4 -3
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_executor_inprocess.py +52 -18
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_format.py +37 -15
- execsql2-2.25.0/tests/test_interactive.py +260 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_mail.py +8 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_models.py +2 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_registry.py +22 -6
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_script.py +0 -49
- execsql2-2.25.0/tests/test_tooling_versions.py +38 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_types.py +57 -10
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_auth.py +32 -13
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_auth_extra.py +5 -2
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_datetime.py +64 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_errors.py +22 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_fileio_extra.py +129 -19
- execsql2-2.25.0/tests/utils/test_keyring_rules.py +289 -0
- execsql2-2.25.0/tests/utils/test_mail_tls.py +192 -0
- execsql2-2.25.0/uv.lock +4177 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/zensical.toml +2 -1
- execsql2-2.23.1/.github/dependabot.yml +0 -21
- execsql2-2.23.1/.pre-commit-hooks.yaml +0 -9
- execsql2-2.23.1/docs/api/index.md +0 -85
- execsql2-2.23.1/docs/getting-started/installation.md +0 -45
- execsql2-2.23.1/docs/getting-started/syntax.md +0 -270
- execsql2-2.23.1/docs/guides/debugging.md +0 -110
- execsql2-2.23.1/extras/vscode-execsql/package.json +0 -24
- execsql2-2.23.1/src/execsql/cli/__init__.py +0 -650
- execsql2-2.23.1/src/execsql/cli/help.py +0 -151
- execsql2-2.23.1/src/execsql/cli/lint.py +0 -506
- execsql2-2.23.1/tests/cli/test_lint.py +0 -329
- execsql2-2.23.1/tests/test_api_filewriter.py +0 -158
- execsql2-2.23.1/uv.lock +0 -3471
- {execsql2-2.23.1 → execsql2-2.25.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/.gitignore +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/.python-version +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/.readthedocs.yaml +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/LICENSE.txt +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/NOTICE +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/SECURITY.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/about/contributors.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/about/copyright.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/api/cli.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/api/db.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/api/exporters.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/api/importers.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/api/metacommands.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/adding_exporters.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/adding_importers.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/documentation.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/encoding.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/sql_syntax.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/using_scripts.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/Compare_planets.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/actions.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/actions2.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/checkboxes.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/connect.b64 +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/connect.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/create_conf.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/data_error1_screenshot.jpg +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/entry_form.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/execsql_console.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/execsql_logo_01.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/fatals.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/logo_small.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/pause_terminal.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/pause_terminal_sm.b64 +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/pause_terminal_sm.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/prompt_compare.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/set_build_commands.jpg +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/unit_conversions.b64 +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/unit_conversions_029.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/unmatched.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/vim_execsql_highlight.png +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/docs/index.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/extras/plugin-template/pyproject.toml +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/extras/vscode-execsql/README.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/scripts/benchmarks/README.md +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/scripts/benchmarks/results/.gitignore +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/__main__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/data/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/tiers.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/debug/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/base.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/duckdb.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/feather.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/html.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/json.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/latex.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/markdown.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/ods.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/parquet.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/pretty.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/protocol.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/raw.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/sqlite.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/templates.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/values.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/xls.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/xml.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/yaml.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/gui/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/gui/base.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/gui/console.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/feather.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/json.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/ods.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/xls.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/connect.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/dispatch.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/io.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/io_export.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/io_write.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/script_ext.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/system.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/py.typed +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/control.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/variables.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/crypto.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/numeric.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/regex.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/strings.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/timer.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/config_settings.sqlite +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/example_config_prompt.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/make_config_db.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/md_compare.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/md_glossary.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/md_upsert.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/pg_compare.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/pg_glossary.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/pg_upsert.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/script_template.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/ss_compare.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/ss_glossary.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/templates/ss_upsert.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/data/formatter_shapes/comment_anchoring.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_access_windows.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_base.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_dsn.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_duckdb.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_factory.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_mysql_case_folding.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_postgres.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_roundtrip_adapters.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_sqlite.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_tiers.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/conftest.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_base.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_db.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_duckdb_exporter.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_exporters.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_feather.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_html_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_html_latex.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_json.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_json_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_latex_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_markdown.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_ods.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_ods_export.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_parquet.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_pretty_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_raw_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_columnar.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_dbfile.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_delimited.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_json.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_latex_xml.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_markup.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_ods.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_pretty_raw.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_template.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_values.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_sqlite_exporter.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_templates.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_templates_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_values_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_xls_xlsx.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_xml.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_yaml.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_zip.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_backends.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_backends_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_compare_stats.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_compute_row_diffs.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_desktop_dialogs.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_format_table.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_tui_pilot.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_tui_pilot_complex.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_utils_gui_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/conftest.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_base_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_csv_importer.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_feather_importer.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_json_importer.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_ods_importer.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_roundtrip_csv.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_xls_importer.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/test_duckdb.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/live_db.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_assert.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_connect.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_io_export.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_io_import.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_connect.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_io.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_script_ext.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_system.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_system_extra.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_prompt.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_show_scripts.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/audit_lint_bad.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/audit_smoke/sample.json +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/audit_smoke/sample.jsonl +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/audit_smoke.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/config_runtime.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/control_flow.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/counters_and_locals.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/error_handling.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/import_options/has_comments.csv +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/import_options.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/includes/helper.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/includes.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/io_formats.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/multi_db.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/parquet_feather_roundtrip.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/parse_only/parse_tree.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/predicates.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/scripts.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/smoke.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/subroutine_loops.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/subvars_advanced.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/template_export/greeting.tmpl +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/template_export.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/timer.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/transactions.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/write_create_table.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/xlsx_ods_roundtrip.sql +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_env_detection.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_expansion_bomb.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_import_regex_hardening.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_log_redaction.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_odbc_injection.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_path_containment.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_substitution_injection.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_zip_bomb.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_api.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_api_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_ast.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_config_data.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_config_extended.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_exceptions.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_package.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_parser.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_parser_params.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_plugins.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_state.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/__init__.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_crypto.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_encodedfile_context.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_errors_extra.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_fileio.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_numeric.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_regex.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_strings.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_timer.py +0 -0
- {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_timer_extra.py +0 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Dependabot keeps the SHA-pinned GitHub Actions in ci-cd.yml up to
|
|
2
|
+
# date. The audit's B22 finding (F059) called out that pinning to
|
|
3
|
+
# major-version tags (e.g. `actions/checkout@v6`) is supply-chain
|
|
4
|
+
# exposure — an attacker who compromises the repo can retag any v6.x
|
|
5
|
+
# release to point at malicious code and every consumer pulls it on
|
|
6
|
+
# the next run. Pinning to a 40-char SHA closes that hole, but the
|
|
7
|
+
# pins must be refreshed when upstream ships a real new release;
|
|
8
|
+
# Dependabot files a PR with the new SHA and a CHANGELOG link.
|
|
9
|
+
version: 2
|
|
10
|
+
updates:
|
|
11
|
+
- package-ecosystem: github-actions
|
|
12
|
+
directory: /
|
|
13
|
+
schedule:
|
|
14
|
+
interval: weekly
|
|
15
|
+
groups:
|
|
16
|
+
actions-minor-and-patch:
|
|
17
|
+
patterns:
|
|
18
|
+
- "*"
|
|
19
|
+
update-types:
|
|
20
|
+
- minor
|
|
21
|
+
- patch
|
|
22
|
+
# Python packages in uv.lock (the development environment; users resolve
|
|
23
|
+
# their own versions from pyproject.toml). ruff is bumped through the
|
|
24
|
+
# pre-commit entry below: tests/test_tooling_versions.py requires the
|
|
25
|
+
# uv.lock ruff to equal the pre-commit rev, so on that PR run
|
|
26
|
+
# `uv lock --upgrade-package ruff==<new version>` and push.
|
|
27
|
+
- package-ecosystem: uv
|
|
28
|
+
directory: /
|
|
29
|
+
schedule:
|
|
30
|
+
interval: weekly
|
|
31
|
+
ignore:
|
|
32
|
+
- dependency-name: ruff
|
|
33
|
+
groups:
|
|
34
|
+
python-minor-and-patch:
|
|
35
|
+
patterns:
|
|
36
|
+
- "*"
|
|
37
|
+
update-types:
|
|
38
|
+
- minor
|
|
39
|
+
- patch
|
|
40
|
+
# Hook revs in .pre-commit-config.yaml.
|
|
41
|
+
- package-ecosystem: pre-commit
|
|
42
|
+
directory: /
|
|
43
|
+
schedule:
|
|
44
|
+
interval: weekly
|
|
45
|
+
groups:
|
|
46
|
+
pre-commit-hooks:
|
|
47
|
+
patterns:
|
|
48
|
+
- "*"
|
|
@@ -24,7 +24,13 @@ jobs:
|
|
|
24
24
|
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
25
25
|
with:
|
|
26
26
|
python-version: "3.13"
|
|
27
|
-
|
|
27
|
+
# The ruff that pre-commit runs, so the two jobs cannot disagree;
|
|
28
|
+
# tests/test_tooling_versions.py keeps uv.lock on the same version.
|
|
29
|
+
- name: Install the ruff pinned in .pre-commit-config.yaml
|
|
30
|
+
run: |
|
|
31
|
+
version=$(grep -A1 'astral-sh/ruff-pre-commit' .pre-commit-config.yaml | grep -oP 'rev: v\K[0-9.]+')
|
|
32
|
+
echo "ruff $version"
|
|
33
|
+
python -m pip install "ruff==$version"
|
|
28
34
|
- run: ruff check src/ tests/
|
|
29
35
|
- run: ruff format --check src/ tests/
|
|
30
36
|
|
|
@@ -35,13 +41,56 @@ jobs:
|
|
|
35
41
|
contents: read
|
|
36
42
|
steps:
|
|
37
43
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
44
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
45
|
+
with:
|
|
46
|
+
python-version: "3.13"
|
|
47
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
48
|
+
# The environment `just setup` builds: mypy and the packages it
|
|
49
|
+
# type-checks against come from uv.lock, so CI and local runs agree.
|
|
50
|
+
# --locked also fails the job when uv.lock is out of date.
|
|
51
|
+
- run: uv sync --locked --all-extras
|
|
52
|
+
- run: uv run --no-sync mypy src/execsql/
|
|
53
|
+
|
|
54
|
+
formatter-corpus:
|
|
55
|
+
name: formatter-corpus
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
permissions:
|
|
58
|
+
contents: read
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
38
61
|
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
39
62
|
with:
|
|
40
63
|
python-version: "3.13"
|
|
41
64
|
cache: "pip"
|
|
42
65
|
- run: python -m pip install --upgrade pip
|
|
43
66
|
- run: python -m pip install ".[dev]"
|
|
44
|
-
|
|
67
|
+
# Every formatter bug to date came from real SQL containing a
|
|
68
|
+
# construct the project's own scripts lack. This gate runs those
|
|
69
|
+
# checks under their own name so a corpus failure is legible
|
|
70
|
+
# without reading a 6,000-test log.
|
|
71
|
+
- run: pytest tests/test_format.py -k corpus --no-cov -q
|
|
72
|
+
|
|
73
|
+
typer-floor:
|
|
74
|
+
name: typer-floor
|
|
75
|
+
runs-on: ubuntu-latest
|
|
76
|
+
permissions:
|
|
77
|
+
contents: read
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
80
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
81
|
+
with:
|
|
82
|
+
python-version: "3.10"
|
|
83
|
+
cache: "pip"
|
|
84
|
+
- run: python -m pip install --upgrade pip
|
|
85
|
+
# Help rendering and flag parsing lean on Typer internals that
|
|
86
|
+
# move between releases, and every other job runs the newest
|
|
87
|
+
# Typer. Install the declared minimum, read from pyproject.toml so
|
|
88
|
+
# the two cannot drift, and run the CLI tests against it.
|
|
89
|
+
- run: |
|
|
90
|
+
floor=$(grep -oP '"typer>=\K[0-9.]+' pyproject.toml)
|
|
91
|
+
echo "Typer floor: $floor"
|
|
92
|
+
python -m pip install ".[dev]" "typer==$floor"
|
|
93
|
+
- run: pytest tests/cli --no-cov -q
|
|
45
94
|
|
|
46
95
|
pre-commit:
|
|
47
96
|
name: pre-commit
|
|
@@ -213,7 +262,7 @@ jobs:
|
|
|
213
262
|
- name: Install dependencies
|
|
214
263
|
run: |
|
|
215
264
|
python -m pip install --upgrade pip
|
|
216
|
-
python -m pip install ".[dev,postgres,mysql,mssql]"
|
|
265
|
+
python -m pip install ".[dev,postgres,mysql,mssql,upsert]"
|
|
217
266
|
- name: Run subprocess integration tests
|
|
218
267
|
run: |
|
|
219
268
|
python -m pytest tests/integration/test_postgres.py tests/integration/test_mysql.py -v --override-ini="addopts="
|
|
@@ -289,7 +338,7 @@ jobs:
|
|
|
289
338
|
build:
|
|
290
339
|
name: Build distribution 📦
|
|
291
340
|
runs-on: ubuntu-latest
|
|
292
|
-
needs: [ lint, typecheck, pre-commit, docs, tests, integration-tests ]
|
|
341
|
+
needs: [ lint, typecheck, pre-commit, formatter-corpus, typer-floor, docs, tests, integration-tests ]
|
|
293
342
|
# Deliberately NOT gated on tags: packaging breaks must surface on a PR,
|
|
294
343
|
# not at release time. Only publish/generate-release below are tag-gated.
|
|
295
344
|
permissions:
|
|
@@ -301,6 +350,16 @@ jobs:
|
|
|
301
350
|
with:
|
|
302
351
|
python-version: "3.13"
|
|
303
352
|
cache: "pip"
|
|
353
|
+
- name: Check the tag matches the package version
|
|
354
|
+
# A tag on a commit whose pyproject.toml has another version
|
|
355
|
+
# would build, and release, the wrong version under the tag.
|
|
356
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
357
|
+
run: |
|
|
358
|
+
version="$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")"
|
|
359
|
+
if [ "${GITHUB_REF_NAME#v}" != "$version" ]; then
|
|
360
|
+
echo "::error::Tag $GITHUB_REF_NAME does not match project.version $version in pyproject.toml"
|
|
361
|
+
exit 1
|
|
362
|
+
fi
|
|
304
363
|
- name: Build sdist + wheel
|
|
305
364
|
run: |
|
|
306
365
|
python -m pip install --upgrade pip
|
|
@@ -339,11 +398,12 @@ jobs:
|
|
|
339
398
|
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
340
399
|
with:
|
|
341
400
|
packages-dir: dist
|
|
342
|
-
skip-existing: true
|
|
343
401
|
|
|
344
402
|
generate-release:
|
|
345
403
|
name: Generate GitHub Release
|
|
346
|
-
|
|
404
|
+
# After the PyPI upload, so a release is never announced for a
|
|
405
|
+
# version that pip cannot install.
|
|
406
|
+
needs: [ publish ]
|
|
347
407
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
348
408
|
runs-on: ubuntu-latest
|
|
349
409
|
permissions:
|
|
@@ -356,11 +416,21 @@ jobs:
|
|
|
356
416
|
with:
|
|
357
417
|
name: ${{ github.event.repository.name }}
|
|
358
418
|
path: dist/
|
|
419
|
+
- name: Detect pre-release tag
|
|
420
|
+
id: tag
|
|
421
|
+
# PEP 440 pre-release suffix (a1, b2, rc1) on the tag -> mark the
|
|
422
|
+
# GitHub Release as a pre-release so it never becomes "latest".
|
|
423
|
+
run: |
|
|
424
|
+
if [[ "${GITHUB_REF_NAME#v}" =~ (a|b|rc)[0-9]+$ ]]; then
|
|
425
|
+
echo "prerelease=true" >> "$GITHUB_OUTPUT"
|
|
426
|
+
else
|
|
427
|
+
echo "prerelease=false" >> "$GITHUB_OUTPUT"
|
|
428
|
+
fi
|
|
359
429
|
- name: Create release
|
|
360
430
|
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
|
|
361
431
|
with:
|
|
362
432
|
draft: false
|
|
363
|
-
prerelease:
|
|
433
|
+
prerelease: ${{ steps.tag.outputs.prerelease }}
|
|
364
434
|
generate_release_notes: true
|
|
365
435
|
files: |
|
|
366
436
|
dist/*
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
- id: execsql-format
|
|
2
|
+
name: execsql-format
|
|
3
|
+
description: Format execsql SQL scripts — normalize metacommand indentation and uppercase keywords.
|
|
4
|
+
entry: execsql format
|
|
5
|
+
language: python
|
|
6
|
+
types: [file]
|
|
7
|
+
files: \.sql$
|
|
8
|
+
args: [--in-place]
|
|
9
|
+
additional_dependencies: ["sqlglot>=25.0,<31"]
|
|
10
|
+
|
|
11
|
+
- id: execsql-lint
|
|
12
|
+
name: execsql-lint
|
|
13
|
+
description: Statically check execsql SQL scripts without a database — unclosed blocks, undefined or unused variables, missing INCLUDE targets, unreachable code.
|
|
14
|
+
entry: execsql lint
|
|
15
|
+
language: python
|
|
16
|
+
types: [file]
|
|
17
|
+
files: \.sql$
|
|
@@ -13,6 +13,119 @@ ______________________________________________________________________
|
|
|
13
13
|
|
|
14
14
|
______________________________________________________________________
|
|
15
15
|
|
|
16
|
+
## [2.25.0] - 2026-10-09
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **`execsql lint` rule `P002` (`split-dollar-quote`):** reports a `$$ ... $$` function or `DO` body that is not between `BEGIN SQL` and `END SQL`, which execsql would send in pieces at the first line ending in `;`.
|
|
21
|
+
- **`execsql lint` rule `P003` (`unknown-metacommand`):** reports a misspelled or malformed metacommand, such as `SUBSTITUTE x 1` for `SUB x 1`, or `EXPORT t TOO out.csv`, that `execsql run` would stop at with `Unknown metacommand`.
|
|
22
|
+
- **`execsql lint` rule `P004` (`unknown-condition`):** reports a condition with an unknown test, such as `IF(hasrowz(t))`, or one that cannot be parsed, such as `ASSERT !!flag!! = TRUE`, in `IF`, `ELSEIF`, `ANDIF`, `ORIF`, `LOOP`, `EXECUTE SCRIPT ... WHILE`, `ASSERT` and `WAIT_UNTIL`.
|
|
23
|
+
- **`[email] ca_file` and `verify_certificate` settings** for the SMTP server's TLS certificate: trust an internal CA, or turn verification off for a test relay.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **`EMAIL` over TLS verifies the server certificate.** With `use_ssl` or `use_tls`, a mail server whose certificate is untrusted or does not match `host` stops the `EMAIL` metacommand before the password is sent. For a relay with an internal certificate, set `[email] ca_file`; to turn the check off, set `verify_certificate = No`.
|
|
28
|
+
- **A `--dsn` / `execsql.run(dsn=...)` user, password or database is percent-decoded**, so `@`, `:`, `/`, `?`, `#` and `%` can be given encoded (`p%40ss`). A password that contains `%` followed by two hex digits must now be written with `%25`.
|
|
29
|
+
- **A relative `WRITE ... TO` path after `CD`** lands in the new directory, as `EXPORT` output already did. Use an absolute path to keep writing to the directory execsql started in.
|
|
30
|
+
- **A locked output file can delay the end of a run.** At the end of a script and before `SYSTEM_CMD`, the CLI waits up to `outfile_open_timeout` (default 600 s) for a `WRITE` / `EXPORT` file another process has locked; if it stays locked, the run fails naming the file and how many lines were lost. Lower `outfile_open_timeout` for unattended runs.
|
|
31
|
+
- **Output that cannot be written fails the run.** When writing a `WRITE`, `EXPORT` or `TEE` file fails (a full disk, a network share that drops), its output is lost, other files are still written, and the run ends with an error naming the file: exit status 1, or `success=False` from `execsql.run()`. A target that can never be opened, such as a directory, fails at once.
|
|
32
|
+
- **Error messages from the database or a driver** show just the error, such as `OperationalError: table t already exists`, without a path into execsql's source. `execsql.log` records where in execsql the error was raised, for bug reports.
|
|
33
|
+
- **`execsql lint` on a script with block-structure errors** reports every unmatched or unclosed `IF`, `LOOP`, `BEGIN BATCH`, `BEGIN SCRIPT` and `BEGIN SQL` as a `P001` on its own line, and runs every other rule on the rest of the script.
|
|
34
|
+
- **Faster start-up:** every `execsql` command and `import execsql` start about 0.7 s sooner.
|
|
35
|
+
|
|
36
|
+
### Removed
|
|
37
|
+
|
|
38
|
+
- **`execsql.utils.fileio` writer globals:** `filewriter`, `fw_input` and `fw_output` are gone, and `FileWriter` no longer takes queue arguments. Code that started a writer by hand before calling `execsql.run()` (the workaround for [#46](https://github.com/geocoug/execsql/issues/46) before 2.23.0) can drop it.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- **Output lost when a script halts is reported.** A `WRITE`, `TEE` or `ON ERROR_HALT WRITE` file still locked when the script halts gets up to 10 seconds; output still lost is reported on the console, in the log, in the `--manifest` file and in `execsql.run()`'s errors.
|
|
43
|
+
- **SIGTERM** (`kill`, `timeout`, `docker stop`, a cancelled CI job) ends a `run` like Ctrl-C: the open transaction is rolled back, a running `SYSTEM_CMD` is stopped, and `execsql.log` gets an `exit` record of type `terminated` (exit status 143).
|
|
44
|
+
- **`execsql.log` `exit` record** is written for a run that ends with an error, a `HALT` or a cancelled prompt (type `error` or `halt`, with the message). Ctrl-C is recorded as `interrupted`.
|
|
45
|
+
- **`execsql.log` `run_db_file` record** names the database file for SQLite, DuckDB and Access runs.
|
|
46
|
+
- **`execsql.log` no longer shows `-a` values** in the `run` record; it gives how many there were.
|
|
47
|
+
- **Passwords in `execsql.log`** from a `--dsn` URL, the `[email]` section, the password prompt or keyring, `PROMPT ENTER_SUB ... PASSWORD`, `PROMPT CREDENTIALS` and `SUB_DECRYPT` are replaced with `***`, such as in SQL logged with `LOG_SQL ON` or a `SYSTEM_CMD` line.
|
|
48
|
+
- **Stored passwords (keyring) are saved only after the connection succeeds**, so a mistyped password is no longer stored.
|
|
49
|
+
- **A stored password is deleted, and you are prompted again, only when the server rejects it.** A timeout, a closed port or a missing database keeps it, so an unattended run no longer stops at a prompt.
|
|
50
|
+
- **Keyring entries are named with the server's port** (`execsql/PostgreSQL/host:5432/db`), so two servers on one host no longer share a password. An entry stored without the port is still used on the default port, and renamed once it works.
|
|
51
|
+
- **Oracle (`-t o`, `oracle://`) connects with the `oracledb` driver** that `execsql2[oracle]` installs.
|
|
52
|
+
- **`-n` with `-e` on PostgreSQL** creates the database with the given encoding, as `CONNECT TO POSTGRESQL(..., ENCODING=..., NEW)` does. PostgreSQL refuses an encoding other than its template database's (usually UTF8), so `-n -e LATIN1` on such a server stops with PostgreSQL's error.
|
|
53
|
+
- **`-d` / `--directories`** rejects a value other than `0`, `1`, `t`, `f`, `y` or `n` (exit 2), as upstream did, so `-d script.sql` names the bad value.
|
|
54
|
+
- **`access_use_numeric`** (config section `input`) works again: with `Yes`, `IMPORT` and `COPY` create MS-Access decimal columns as `NUMERIC(precision,scale)` instead of `DOUBLE`.
|
|
55
|
+
- **`IMPORT ... TO NEW` and `COPY ... TO NEW` onto a table that already exists** stop with `Table <name> already exists` before creating anything, on every DBMS. A name without a schema counts only in the schema the table would be created in (on MySQL, the current database).
|
|
56
|
+
- **`IMPORT` / `COPY ... TO REPLACEMENT` of a table whose name needs quoting** (a space, a hyphen, ...) replaces it on SQLite, SQL Server, Oracle, Firebird and Access, and a schema-qualified name such as `staging.t` is dropped correctly on SQL Server, Oracle and Firebird.
|
|
57
|
+
- **`COPY` and `COPY QUERY` copy text values as written:** a text column of `1`/`0`, dates or numbers is no longer created as boolean, timestamp or numeric by `NEW` / `REPLACEMENT`, and `1` copied into a text column stays `1`.
|
|
58
|
+
- **`COPY ... TO NEW` / `REPLACEMENT` no longer holds every source row in memory.**
|
|
59
|
+
- **`IMPORT` / `COPY` into DuckDB that fails part-way keeps no rows**, as on SQLite and PostgreSQL, so a re-run no longer duplicates them.
|
|
60
|
+
- **`IMPORT` of a data line with fewer values than the header** loads the missing values as NULL on every DBMS.
|
|
61
|
+
- **`IMPORT` of a delimited file with a blank line** imports the rows after it. The blank line itself is a row of NULLs, or dropped with `CONFIG EMPTY_ROWS NO`; blank lines at the end of the file are ignored.
|
|
62
|
+
- **PostgreSQL `IMPORT` of a quoted file with a blank line** no longer fails with `missing data for column`.
|
|
63
|
+
- **`IMPORT ... TO NEW` / `REPLACEMENT` type inference** no longer takes `1-2`, `5/6`, `March 5`, `Jan` or `Monday` for a date; such a column is created as text. A date must give the year (`2024-01-05`, `1/5/2024`), or a two-digit year month-first (`1/5/24`).
|
|
64
|
+
- **`IMPORT ... TO NEW` / `REPLACEMENT` of a timestamp column mixing values with and without a UTC offset** creates the column as text and keeps every value as written, instead of converting with the importing machine's time zone.
|
|
65
|
+
- **MySQL `IMPORT` of values with backslashes:** `C:\new\tbl`, `\N` and regular expressions load as written, and a file whose path contains a backslash imports.
|
|
66
|
+
- **`EXPORT ... AS XLSX`** writes text that starts with `=` as text, not as a formula.
|
|
67
|
+
- **`execsql.run()` from a script without an `if __name__ == "__main__":` guard** no longer runs the script's SQL twice on macOS and Windows.
|
|
68
|
+
- **Concurrent `execsql.run()` calls** each write files through their own writer, so two threads both get complete output, and a run that halts does not discard another run's output.
|
|
69
|
+
- **Repeated `execsql.run()` calls in one process** no longer pile up exit hooks or duplicate plugin metacommands.
|
|
70
|
+
- **`execsql.run()` cleans up when it returns:** its temp files are removed, and a run interrupted with Ctrl-C closes the connection it opened.
|
|
71
|
+
- **`execsql.run()` with `--manifest`** no longer records into a manifest that belongs to another run in the same thread.
|
|
72
|
+
- **`execsql.run()` error details:** a run halted by a failed SQL statement or metacommand reports that error (and the failed statement in `ScriptError.sql`), a `HALT` reports its exit status, and `result.errors` lists errors in the order they happened.
|
|
73
|
+
- **`execsql.run()` setup failures** (an unreadable script, a missing or invalid `config_file`, a `dsn` that cannot be parsed or opened) return `success=False` with an error whose `source` is the script, `<config>` or `<connect>`, instead of raising.
|
|
74
|
+
- **`execsql lint` `V001` (`undefined-variable`)** no longer reports variables set by `PROMPT ENTER_SUB`, `ASK ... SUB`, `PROMPT ASK ... SUB`, `PROMPT OPENFILE` / `SAVEFILE` / `DIRECTORY SUB`, `PROMPT CREDENTIALS`, `SUB_TEMPFILE` and the keys of `SUB_QUERYSTRING`.
|
|
75
|
+
- **`execsql lint` `V001`** reports a user variable named like a system variable without its `$` (`!!date_tag!!`), and a `SUB` variable written with a `$` (`!!$region!!`).
|
|
76
|
+
- **`execsql lint` `V002` (`unused-variable`)** no longer reports a variable read only by `sub_defined(...)` or `sub_empty(...)`.
|
|
77
|
+
- **`execsql lint` `F001`** no longer calls `IF(1=1)`, `IF(1=0)` or `IF(0=1)` a constant condition; `execsql run` rejects them, and lint reports them as `P004`.
|
|
78
|
+
- **Install hints in error messages** name the right extra: `formats` for XLSX (not `excel`), and none for Textual, which execsql2 includes.
|
|
79
|
+
- **Documentation:** install instructions use `uv tool install` / `pipx install` and quote every extra (`"execsql2[postgres]"`); `SERVE` and `allow_serve` are described correctly (`SERVE` opens no network port); the 2.17.0 `PG_UPSERT` migration note's `ASSERT !!$PG_UPSERT_QA_PASSED!! = TRUE`, which always fails, is corrected to `ASSERT IS_TRUE(!!$PG_UPSERT_QA_PASSED!!) "QA failed"`.
|
|
80
|
+
|
|
81
|
+
______________________________________________________________________
|
|
82
|
+
|
|
83
|
+
## [2.24.0] - 2026-10-01
|
|
84
|
+
|
|
85
|
+
### Added
|
|
86
|
+
|
|
87
|
+
- **Commands:** `execsql run`, `format`, `lint`, `config`, `list` and `init`. `format` and `lint` take files or directories and need no database, so a whole script library can be linted at once. See [Commands](https://execsql2.readthedocs.io/en/latest/getting-started/syntax/#commands).
|
|
88
|
+
- **`run`:** `--manifest FILE` writes a JSON record of the run (files read and written, connections, statement counts and any error), even when the run fails. `--var NAME=VALUE` sets `!!NAME!!` from the command line.
|
|
89
|
+
- **`lint`:** every issue has a rule code (`V001`, `F002`, …) that `--select` and `--ignore` filter on. `--output-format json|concise|github`, `--statistics`, and `--strict` to fail on warnings. New checks for a `SUB` variable nothing reads, an `IF` whose condition never changes, and statements after `HALT`. See the [lint rules reference](https://execsql2.readthedocs.io/en/latest/reference/lint/).
|
|
90
|
+
- **`execsql-lint` pre-commit hook**, alongside `execsql-format`.
|
|
91
|
+
- **`format`:** `--diff` shows what would change without writing. `--sql` and `--no-leading-comma` override the config for one run.
|
|
92
|
+
- **`format` and `lint`:** read a script from stdin with `-`, and take `-f`/`--script-encoding` and `--config`.
|
|
93
|
+
- **`[format]` and `[lint]` config sections** set project defaults; a command-line flag wins.
|
|
94
|
+
- **`config`:** lists every option with its value, its default and the file that set it, with passwords shown as `***`. `--validate` reports every problem in every config file with its file and line. `--init` prints the config template.
|
|
95
|
+
- **`init`:** creates `execsql.conf`, a starter script and the pre-commit hooks. Existing files are kept unless you pass `--force`.
|
|
96
|
+
- **`list`:** `metacommands`, `encodings`, `plugins` and `keywords`, as text or JSON.
|
|
97
|
+
- **`PG_UPSERT` character-length check:** a staging value longer than its `varchar(n)` or `char(n)` base column fails QA and appears in the `EXPORT_FAILURES` fix sheet.
|
|
98
|
+
|
|
99
|
+
### Deprecated
|
|
100
|
+
|
|
101
|
+
- Running a script without a command (`execsql script.sql myserver mydb`) prints a warning and stops working in execsql2 3.0. Put `run` first: `execsql run script.sql myserver mydb`. `-m`, `-y`, `--list-plugins`, `--dump-keywords`, `--init-config` and `--ping` without a command warn the same way and name their replacement; see [Flags that became commands](https://execsql2.readthedocs.io/en/latest/getting-started/syntax/#former_flags). After `run` they still work without a warning, but `execsql run --help` no longer lists them.
|
|
102
|
+
|
|
103
|
+
### Removed
|
|
104
|
+
|
|
105
|
+
- `--lint`: use `execsql lint`. `execsql run --lint` now exits with status 2 without running the script, so update CI steps and hooks that call it.
|
|
106
|
+
- The `execsql-format` command: use `execsql format`, which takes the same options. Pre-commit users need no change, because the hook id is still `execsql-format`. Shell scripts, Makefiles and CI steps that call `execsql-format` must be updated.
|
|
107
|
+
- `SqlStmt`, `MetacommandStmt` and `ScriptCmd` from `execsql.script`. Only Python code that imports them is affected; scripts are not.
|
|
108
|
+
|
|
109
|
+
### Changed
|
|
110
|
+
|
|
111
|
+
- **`PG_UPSERT` QA follows `METHOD` and `EXCLUDE`:** all three modes check only the staging rows the load would write, so pass `PG_UPSERT QA` the same `METHOD` and `EXCLUDE` as the load that follows it. `CHECK ... METHOD update` treats a missing `NOT NULL` column as a warning. The `upsert` extra now requires pg-upsert 1.25.0 or newer. See [QA follows METHOD and EXCLUDE](https://execsql2.readthedocs.io/en/latest/reference/metacommands/#pg_upsert_qa_method).
|
|
112
|
+
- **`PG_UPSERT` QA can fail where it passed before:** it now catches a unique key that collides with an existing base row, a foreign key parent that is not in `TABLES`, and an excluded `NOT NULL` column on an inserted row, all of which used to fail during the load.
|
|
113
|
+
- A script named exactly like a command (`run`, `format`, `lint`, `config`, `list` or `init`, with no extension) must be run as `execsql run NAME`.
|
|
114
|
+
- `execsql format --encoding` is now `-f`/`--script-encoding`, matching `run`. `--encoding` still works.
|
|
115
|
+
- The debug REPL (`BREAKPOINT`, `--debug`) runs metacommands and blocks as well as SQL, as if they were the next lines of the script where it paused: a `SUB` stays set when the script resumes, and SQL is committed as the script's own SQL would be. See [Debugging](https://execsql2.readthedocs.io/en/latest/guides/debugging/).
|
|
116
|
+
- CLI help is plain text, colored on a terminal (`NO_COLOR` or `EXECSQL_NO_COLOR` turns color off), and uses the terminal's full width. `execsql` with no arguments prints it and exits with status 2.
|
|
117
|
+
- Lint output groups issues under each file in line order, with one summary line. A script that fails to parse is reported on one line with its line number.
|
|
118
|
+
- Error messages name the fix: a missing SQLite or DuckDB file suggests `-n`/`--new-db`, and a config file error names the file and line and suggests `execsql config --validate`.
|
|
119
|
+
- Requires Typer 0.26 or newer (previously 0.12).
|
|
120
|
+
|
|
121
|
+
### Fixed
|
|
122
|
+
|
|
123
|
+
- `execsql format` without the `[formatter]` extra says sqlglot is needed and how to install it, instead of an uncaught `ImportError`.
|
|
124
|
+
- `-h` works as a short form of `--help`, as it did in upstream execsql.
|
|
125
|
+
- The debug REPL's `.set VAR VALUE` keeps the value's case instead of lowercasing it, and `.vars all` lists environment variables instead of looking up a variable named `all`.
|
|
126
|
+
|
|
127
|
+
______________________________________________________________________
|
|
128
|
+
|
|
16
129
|
## [2.23.1] - 2026-09-29
|
|
17
130
|
|
|
18
131
|
### Added
|
|
@@ -352,7 +465,7 @@ ______________________________________________________________________
|
|
|
352
465
|
|
|
353
466
|
### Changed
|
|
354
467
|
|
|
355
|
-
- **Behavior change.** `PG_UPSERT`, `PG_UPSERT QA`, and `PG_UPSERT CHECK` no longer raise a metacommand error when QA checks fail. The outcome is reported via `$PG_UPSERT_QA_PASSED`, `$PG_UPSERT_TABLE_QA_PASSED`, and `$PG_UPSERT_RESULT_JSON`, so the script controls flow with `IF` or `ASSERT`. `EXPORT_FAILURES` still runs and the upsert is still skipped on QA failure. Migration: add `ASSERT !!$PG_UPSERT_QA_PASSED!!
|
|
468
|
+
- **Behavior change.** `PG_UPSERT`, `PG_UPSERT QA`, and `PG_UPSERT CHECK` no longer raise a metacommand error when QA checks fail. The outcome is reported via `$PG_UPSERT_QA_PASSED`, `$PG_UPSERT_TABLE_QA_PASSED`, and `$PG_UPSERT_RESULT_JSON`, so the script controls flow with `IF` or `ASSERT`. `EXPORT_FAILURES` still runs and the upsert is still skipped on QA failure. Migration: add `ASSERT IS_TRUE(!!$PG_UPSERT_QA_PASSED!!) "QA failed"` at the call site to preserve the previous halt-on-failure behavior. (Corrected after release: this note first gave an `=` comparison, which is not a valid condition and fails on every run.)
|
|
356
469
|
|
|
357
470
|
### Fixed
|
|
358
471
|
|
|
@@ -98,6 +98,10 @@ git push origin <branch> --follow-tags
|
|
|
98
98
|
|
|
99
99
|
Pre-releases are published to PyPI but are not installed by default — `pip install execsql2` will not pick them up unless `--pre` is passed.
|
|
100
100
|
|
|
101
|
+
The GitHub Release for a pre-release tag is marked as a pre-release. Promote to the final version with the same recipe and the final version string (`just bump-pre 2.0.0`). `just bump-patch` from `2.0.0rc1` would skip ahead to `2.0.1`.
|
|
102
|
+
|
|
103
|
+
Always preview a bump first: `uv run bump-my-version bump --new-version 2.0.0a1 patch --dry-run -v` should print `New version will be '2.0.0a1'`.
|
|
104
|
+
|
|
101
105
|
### CI/CD pipeline (`ci-cd.yml`)
|
|
102
106
|
|
|
103
107
|
Triggered on pushes to `main`, any `v*.*.*` tag, and pull requests.
|