execsql2 2.21.1__tar.gz → 2.22.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.21.1 → execsql2-2.22.0}/.github/workflows/ci-cd.yml +63 -14
- {execsql2-2.21.1 → execsql2-2.22.0}/.pre-commit-config.yaml +12 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/CHANGELOG.md +23 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/CONTRIBUTING.md +20 -8
- {execsql2-2.21.1 → execsql2-2.22.0}/PKG-INFO +3 -3
- {execsql2-2.21.1 → execsql2-2.22.0}/README.md +2 -2
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/about/divergence.md +44 -40
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/dev/architecture.md +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/getting-started/installation.md +2 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/guides/formatter.md +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/guides/sql_syntax.md +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/reference/configuration.md +3 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/reference/metacommands.md +9 -5
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/reference/security.md +14 -2
- {execsql2-2.21.1 → execsql2-2.22.0}/justfile +2 -2
- {execsql2-2.21.1 → execsql2-2.22.0}/pyproject.toml +11 -2
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/api.py +21 -4
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/cli/run.py +37 -17
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/config.py +37 -22
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/data/execsql.conf.template +6 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/access.py +6 -5
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/base.py +23 -5
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/dsn.py +2 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/duckdb.py +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/mysql.py +6 -8
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/sqlite.py +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exceptions.py +14 -11
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/base.py +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/delimited.py +22 -16
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/duckdb.py +6 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/feather.py +2 -2
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/json.py +5 -3
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/latex.py +2 -2
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/markdown.py +1 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/ods.py +7 -3
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/parquet.py +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/raw.py +8 -8
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/sqlite.py +11 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/templates.py +2 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/xls.py +10 -10
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/xml.py +1 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/yaml.py +1 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/zip.py +9 -7
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/format.py +6 -6
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/gui/console.py +3 -3
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/gui/desktop.py +28 -10
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/gui/tui.py +8 -6
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/importers/base.py +14 -8
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/importers/csv.py +8 -3
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/importers/xls.py +1 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/conditions.py +14 -14
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/connect.py +2 -2
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/control.py +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/data.py +2 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/io_export.py +4 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/io_fileops.py +85 -39
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/io_import.py +1 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/io_write.py +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/prompt.py +24 -22
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/system.py +14 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/models.py +56 -17
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/parser.py +8 -8
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/plugins.py +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/script/engine.py +4 -4
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/script/executor.py +67 -28
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/script/parser.py +13 -12
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/script/variables.py +4 -2
- execsql2-2.22.0/src/execsql/state.pyi +122 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/types.py +31 -26
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/auth.py +6 -2
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/datetime.py +3 -3
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/errors.py +7 -5
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/fileio.py +77 -31
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/gui.py +15 -11
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/mail.py +9 -2
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/numeric.py +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/regex.py +9 -9
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/cli/test_cli_run.py +45 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_mysql_case_folding.py +18 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_postgres.py +46 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_duckdb_exporter.py +29 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_feather.py +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_latex_extended.py +10 -7
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_parquet.py +8 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_sqlite_exporter.py +38 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/importers/test_base_extended.py +19 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/importers/test_csv_importer.py +8 -25
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/integration/test_postgres.py +51 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_metacommands_fileops_extra.py +102 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_metacommands_system.py +66 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/security/test_log_redaction.py +45 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_api.py +33 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_config_data.py +26 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_models.py +106 -4
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_types.py +2 -3
- {execsql2-2.21.1 → execsql2-2.22.0}/uv.lock +1 -1
- {execsql2-2.21.1 → execsql2-2.22.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/.github/dependabot.yml +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/.gitignore +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/.pre-commit-hooks.yaml +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/.python-version +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/.readthedocs.yaml +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/LICENSE.txt +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/NOTICE +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/SECURITY.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/about/contributors.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/about/copyright.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/api/cli.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/api/db.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/api/exporters.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/api/importers.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/api/index.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/api/metacommands.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/dev/adding_db_adapters.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/dev/adding_exporters.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/dev/adding_importers.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/dev/adding_metacommands.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/dev/releasing.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/getting-started/requirements.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/getting-started/syntax.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/guides/debugging.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/guides/documentation.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/guides/encoding.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/guides/examples.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/guides/logging.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/guides/usage.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/guides/using_scripts.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/Compare_planets.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/actions.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/actions2.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/checkboxes.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/connect.b64 +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/connect.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/create_conf.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/data_error1_screenshot.jpg +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/entry_form.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/execsql_console.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/execsql_logo_01.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/fatals.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/logo_small.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/pause_terminal.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/pause_terminal_sm.b64 +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/pause_terminal_sm.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/prompt_compare.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/set_build_commands.jpg +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/unit_conversions.b64 +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/unit_conversions_029.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/unmatched.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/images/vim_execsql_highlight.png +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/index.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/docs/reference/substitution_vars.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/extras/plugin-template/README.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/extras/plugin-template/pyproject.toml +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/extras/plugin-template/tests/test_plugin.py.example +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/extras/vscode-execsql/README.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/extras/vscode-execsql/package.json +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/scripts/generate_vscode_grammar.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/__main__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/cli/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/cli/dsn.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/cli/help.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/cli/lint.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/data/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/factory.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/firebird.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/oracle.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/postgres.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/db/sqlserver.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/debug/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/debug/repl.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/html.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/pretty.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/protocol.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/values.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/exporters/xlsx.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/gui/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/gui/base.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/importers/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/importers/feather.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/importers/json.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/importers/ods.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/debug.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/dispatch.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/io.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/script_ext.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/metacommands/upsert.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/py.typed +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/script/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/script/ast.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/script/control.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/state.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/crypto.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/strings.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/src/execsql/utils/timer.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/README.md +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/config_settings.sqlite +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/example_config_prompt.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/make_config_db.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/md_compare.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/md_glossary.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/md_upsert.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/pg_compare.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/pg_glossary.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/pg_upsert.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/script_template.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/ss_compare.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/ss_glossary.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/templates/ss_upsert.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/cli/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/cli/test_cli.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/cli/test_cli_e2e.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/cli/test_lint.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/cli/test_ping.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/cli/test_profile.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/conftest.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_access_windows.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_base.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_db_adapters_mocked.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_db_adapters_mocked_extra.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_dsn.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_duckdb.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_factory.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_mysql_inprocess.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_postgres_inprocess.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_sqlite.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_sqlite_extra.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/db/test_sqlserver_inprocess.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_base.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_db.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_delimited.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_exporters.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_html_extended.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_html_latex.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_json.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_json_extended.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_markdown.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_ods.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_ods_export.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_pretty_extended.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_raw_extended.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_templates.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_templates_extended.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_values_extended.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_xls_xlsx.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_xlsx.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_xml.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_yaml.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/exporters/test_zip.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/gui/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/gui/test_backends.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/gui/test_backends_extended.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/gui/test_compare_stats.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/gui/test_compute_row_diffs.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/gui/test_desktop_dialogs.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/gui/test_tui_pilot.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/gui/test_tui_pilot_complex.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/gui/test_utils_gui_extended.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/importers/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/importers/test_csv_edge_cases.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/importers/test_feather_importer.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/importers/test_json_importer.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/importers/test_ods_importer.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/importers/test_xls_importer.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/integration/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/integration/conftest.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/integration/test_dsn.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/integration/test_duckdb.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/integration/test_mysql.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/integration/test_sqlite.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_assert.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_breakpoint.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_conditions_extra.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_connect.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_io_export.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_io_import.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_metacommands.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_metacommands_connect.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_metacommands_data.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_metacommands_extended.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_metacommands_io.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_metacommands_script_ext.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_metacommands_system_extra.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_pg_upsert.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_prompt.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_row_count.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/metacommands/test_show_scripts.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/audit_lint_bad.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/audit_smoke/sample.json +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/audit_smoke/sample.jsonl +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/audit_smoke.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/config_runtime.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/control_flow.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/counters_and_locals.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/error_handling.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/import_options/has_comments.csv +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/import_options.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/includes/helper.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/includes.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/io_formats.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/multi_db.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/parquet_feather_roundtrip.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/parse_only/parse_tree.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/predicates.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/scripts.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/smoke.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/subroutine_loops.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/subvars_advanced.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/template_export/greeting.tmpl +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/template_export.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/timer.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/transactions.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/write_create_table.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/fixtures/xlsx_ods_roundtrip.sql +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/scripts/test_sql_scripts.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/security/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/security/test_env_detection.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/security/test_expansion_bomb.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/security/test_import_regex_hardening.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/security/test_odbc_injection.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/security/test_path_containment.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/security/test_substitution_injection.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/security/test_zip_bomb.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_api_extended.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_ast.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_ast_parser.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_bundled_templates.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_config.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_config_extended.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_debug_repl.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_engine.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_error_messages.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_exceptions.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_executor.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_executor_inprocess.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_format.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_mail.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_package.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_parser.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_parser_params.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_plugins.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_registry.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_script.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/test_state.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/__init__.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_auth.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_auth_extra.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_crypto.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_datetime.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_encodedfile_context.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_errors.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_errors_extra.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_fileio.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_fileio_extra.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_numeric.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_regex.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_strings.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_timer.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/tests/utils/test_timer_extra.py +0 -0
- {execsql2-2.21.1 → execsql2-2.22.0}/zensical.toml +0 -0
|
@@ -20,14 +20,63 @@ jobs:
|
|
|
20
20
|
permissions:
|
|
21
21
|
contents: read
|
|
22
22
|
steps:
|
|
23
|
-
- uses: actions/checkout@
|
|
24
|
-
- uses: actions/setup-python@
|
|
23
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
24
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
25
25
|
with:
|
|
26
26
|
python-version: "3.13"
|
|
27
27
|
- run: python -m pip install ruff
|
|
28
28
|
- run: ruff check src/ tests/
|
|
29
29
|
- run: ruff format --check src/ tests/
|
|
30
30
|
|
|
31
|
+
typecheck:
|
|
32
|
+
name: typecheck
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
permissions:
|
|
35
|
+
contents: read
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
38
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
39
|
+
with:
|
|
40
|
+
python-version: "3.13"
|
|
41
|
+
cache: "pip"
|
|
42
|
+
- run: python -m pip install --upgrade pip
|
|
43
|
+
- run: python -m pip install ".[dev]"
|
|
44
|
+
- run: mypy src/execsql/
|
|
45
|
+
|
|
46
|
+
pre-commit:
|
|
47
|
+
name: pre-commit
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
permissions:
|
|
50
|
+
contents: read
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
53
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
54
|
+
with:
|
|
55
|
+
python-version: "3.13"
|
|
56
|
+
cache: "pip"
|
|
57
|
+
- run: python -m pip install --upgrade pip
|
|
58
|
+
- run: python -m pip install ".[dev]"
|
|
59
|
+
# mypy runs in the dedicated typecheck job; the local hook needs uv
|
|
60
|
+
- run: pre-commit run --all-files
|
|
61
|
+
env:
|
|
62
|
+
SKIP: mypy
|
|
63
|
+
|
|
64
|
+
docs:
|
|
65
|
+
name: docs
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
permissions:
|
|
68
|
+
contents: read
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
71
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
72
|
+
with:
|
|
73
|
+
python-version: "3.13"
|
|
74
|
+
cache: "pip"
|
|
75
|
+
- run: python -m pip install --upgrade pip
|
|
76
|
+
- run: python -m pip install ".[dev]"
|
|
77
|
+
- run: cp CHANGELOG.md docs/about/change_log.md
|
|
78
|
+
- run: zensical build
|
|
79
|
+
|
|
31
80
|
tests:
|
|
32
81
|
strategy:
|
|
33
82
|
fail-fast: false
|
|
@@ -48,13 +97,13 @@ jobs:
|
|
|
48
97
|
contents: read
|
|
49
98
|
steps:
|
|
50
99
|
- name: Check out repository code
|
|
51
|
-
uses: actions/checkout@
|
|
100
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
52
101
|
- name: Setup Python ${{ matrix.python-version }}
|
|
53
|
-
uses: actions/setup-python@
|
|
102
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
54
103
|
with:
|
|
55
104
|
python-version: ${{ matrix.python-version }}
|
|
56
105
|
- name: Cache pip dependencies
|
|
57
|
-
uses: actions/cache@
|
|
106
|
+
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
|
58
107
|
with:
|
|
59
108
|
path: ~/.cache/pip
|
|
60
109
|
key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{
|
|
@@ -139,9 +188,9 @@ jobs:
|
|
|
139
188
|
--health-interval 10s --health-timeout 5s --health-retries 20
|
|
140
189
|
steps:
|
|
141
190
|
- name: Check out repository code
|
|
142
|
-
uses: actions/checkout@
|
|
191
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
143
192
|
- name: Setup Python ${{ matrix.python-version }}
|
|
144
|
-
uses: actions/setup-python@
|
|
193
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
145
194
|
with:
|
|
146
195
|
python-version: ${{ matrix.python-version }}
|
|
147
196
|
- name: Install tkinter (Ubuntu)
|
|
@@ -187,8 +236,8 @@ jobs:
|
|
|
187
236
|
permissions:
|
|
188
237
|
contents: read
|
|
189
238
|
steps:
|
|
190
|
-
- uses: actions/checkout@
|
|
191
|
-
- uses: actions/setup-python@
|
|
239
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
240
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
192
241
|
with:
|
|
193
242
|
python-version: ${{ matrix.python-version }}
|
|
194
243
|
- name: Install Microsoft Access Database Engine 2016 (x64)
|
|
@@ -233,14 +282,14 @@ jobs:
|
|
|
233
282
|
build:
|
|
234
283
|
name: Build distribution 📦
|
|
235
284
|
runs-on: ubuntu-latest
|
|
236
|
-
needs: [ lint, tests, integration-tests ]
|
|
285
|
+
needs: [ lint, typecheck, pre-commit, docs, tests, integration-tests ]
|
|
237
286
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
238
287
|
permissions:
|
|
239
288
|
contents: read
|
|
240
289
|
steps:
|
|
241
|
-
- uses: actions/checkout@
|
|
290
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
242
291
|
- name: Set up Python
|
|
243
|
-
uses: actions/setup-python@
|
|
292
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
244
293
|
with:
|
|
245
294
|
python-version: "3.13"
|
|
246
295
|
cache: "pip"
|
|
@@ -288,14 +337,14 @@ jobs:
|
|
|
288
337
|
contents: write
|
|
289
338
|
steps:
|
|
290
339
|
- name: Checkout
|
|
291
|
-
uses: actions/checkout@
|
|
340
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
292
341
|
- name: Download dist
|
|
293
342
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
294
343
|
with:
|
|
295
344
|
name: ${{ github.event.repository.name }}
|
|
296
345
|
path: dist/
|
|
297
346
|
- name: Create release
|
|
298
|
-
uses: softprops/action-gh-release@
|
|
347
|
+
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
|
|
299
348
|
with:
|
|
300
349
|
draft: false
|
|
301
350
|
prerelease: false
|
|
@@ -80,3 +80,15 @@ repos:
|
|
|
80
80
|
rev: v0.25
|
|
81
81
|
hooks:
|
|
82
82
|
- id: validate-pyproject
|
|
83
|
+
# Static type checking — same command as `just typecheck`, run in the
|
|
84
|
+
# project environment so results match local and CI. Whole-program run
|
|
85
|
+
# (pass_filenames: false) because mypy cannot check files in isolation.
|
|
86
|
+
# The CI pre-commit job sets SKIP=mypy; CI has a dedicated typecheck gate.
|
|
87
|
+
- repo: local
|
|
88
|
+
hooks:
|
|
89
|
+
- id: mypy
|
|
90
|
+
name: mypy
|
|
91
|
+
entry: uv run mypy src/execsql/
|
|
92
|
+
language: system
|
|
93
|
+
pass_filenames: false
|
|
94
|
+
files: ^(src/execsql/.*\.pyi?|pyproject\.toml)$
|
|
@@ -13,6 +13,29 @@ ______________________________________________________________________
|
|
|
13
13
|
|
|
14
14
|
______________________________________________________________________
|
|
15
15
|
|
|
16
|
+
## [2.22.0] - 2026-07-03
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- `run()` now accepts `allow_rm_file=False` and `allow_serve=False` to disable the `RM_FILE` and `SERVE` metacommands for library callers, matching the existing `allow_system_cmd` kwarg and the `--no-rm-file` / `--no-serve` CLI flags.
|
|
21
|
+
- `[config] system_cmd_timeout` can bound foreground `SYSTEM_CMD` execution; the default remains no timeout.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- `EXPORT … FORMAT SQLITE` and `EXPORT … FORMAT DUCKDB` correctly preserve source column types when exporting from a typed database: text columns stay text (not re-inferred as TIMESTAMP or numeric from value shape), `decimal.Decimal` values bind without error (converted to their exact string representation for SQLite), and unsupported Python objects such as PostGIS geometry are stringified instead of raising a bind error.
|
|
26
|
+
- `EXPORT … FORMAT LATEX` into a ZIP archive no longer crashes with `AttributeError`.
|
|
27
|
+
- Connecting to a server-based database without a server or database name now stops with a clear error message instead of a driver traceback.
|
|
28
|
+
|
|
29
|
+
______________________________________________________________________
|
|
30
|
+
|
|
31
|
+
## [2.21.2] - 2026-06-30
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- Fixed `EXPORT … AS PARQUET` and `EXPORT … AS FEATHER` `ComputeError` when a result column has more than 100 leading `NULL` values followed by non-null numeric values.
|
|
36
|
+
|
|
37
|
+
______________________________________________________________________
|
|
38
|
+
|
|
16
39
|
## [2.21.1] - 2026-06-24
|
|
17
40
|
|
|
18
41
|
### Fixed
|
|
@@ -32,13 +32,19 @@ Linting and formatting are handled by [ruff](https://docs.astral.sh/ruff/):
|
|
|
32
32
|
just lint
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
[
|
|
35
|
+
Static type checking is handled by [mypy](https://mypy.readthedocs.io/) and must pass with zero errors:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
just typecheck
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
[pre-commit](https://pre-commit.com/) hooks enforce additional checks (gitleaks, uv-lock, mdformat, markdownlint, typos, validate-pyproject, mypy) on every commit. To run them manually against all files:
|
|
36
42
|
|
|
37
43
|
```bash
|
|
38
44
|
just pre-commit
|
|
39
45
|
```
|
|
40
46
|
|
|
41
|
-
CI rejects PRs that fail
|
|
47
|
+
CI rejects PRs that fail ruff lint/format, mypy type checking, the full pre-commit suite, docs build, or tests.
|
|
42
48
|
|
|
43
49
|
## Running Tests
|
|
44
50
|
|
|
@@ -96,12 +102,18 @@ Pre-releases are published to PyPI but are not installed by default — `pip ins
|
|
|
96
102
|
|
|
97
103
|
Triggered on pushes to `main`, any `v*.*.*` tag, and pull requests.
|
|
98
104
|
|
|
99
|
-
| Job
|
|
100
|
-
|
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
+
| Job | Trigger | What it does |
|
|
106
|
+
| ---------------------- | ------------------ | ----------------------------------------------------- |
|
|
107
|
+
| `lint` | all events | Runs `ruff check` and `ruff format --check` |
|
|
108
|
+
| `typecheck` | all events | Runs `mypy src/execsql/` (zero-error gate) |
|
|
109
|
+
| `pre-commit` | all events | Runs the full pre-commit suite against all files |
|
|
110
|
+
| `docs` | all events | Builds the documentation site |
|
|
111
|
+
| `tests` | all events | Runs the test matrix (3 OS × 5 Python versions) |
|
|
112
|
+
| `integration-tests` | all events | Runs tests against live database service containers |
|
|
113
|
+
| `access-tests-windows` | all events | Runs MS Access driver tests on Windows (non-blocking) |
|
|
114
|
+
| `build` | `v*.*.*` tags only | Builds sdist + wheel, checks with twine |
|
|
115
|
+
| `publish` | `v*.*.*` tags only | Publishes to PyPI via OIDC trusted publishing |
|
|
116
|
+
| `generate-release` | `v*.*.*` tags only | Creates a GitHub Release with dist artifacts |
|
|
105
117
|
|
|
106
118
|
### PyPI trusted publishing setup
|
|
107
119
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.22.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
|
|
@@ -173,7 +173,7 @@ Optional extras install database drivers and feature bundles:
|
|
|
173
173
|
|
|
174
174
|
```bash
|
|
175
175
|
# Database drivers
|
|
176
|
-
pip install execsql2[postgres] # PostgreSQL (
|
|
176
|
+
pip install execsql2[postgres] # PostgreSQL (psycopg3 / psycopg[binary])
|
|
177
177
|
pip install execsql2[mysql] # MySQL / MariaDB (pymysql)
|
|
178
178
|
pip install execsql2[mssql] # SQL Server (pyodbc)
|
|
179
179
|
pip install execsql2[duckdb] # DuckDB
|
|
@@ -403,7 +403,7 @@ execsql-format --no-sql --in-place scripts/
|
|
|
403
403
|
```yaml
|
|
404
404
|
repos:
|
|
405
405
|
- repo: https://github.com/geocoug/execsql
|
|
406
|
-
rev: v2.
|
|
406
|
+
rev: v2.22.0
|
|
407
407
|
hooks:
|
|
408
408
|
- id: execsql-format
|
|
409
409
|
```
|
|
@@ -42,7 +42,7 @@ Optional extras install database drivers and feature bundles:
|
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
44
|
# Database drivers
|
|
45
|
-
pip install execsql2[postgres] # PostgreSQL (
|
|
45
|
+
pip install execsql2[postgres] # PostgreSQL (psycopg3 / psycopg[binary])
|
|
46
46
|
pip install execsql2[mysql] # MySQL / MariaDB (pymysql)
|
|
47
47
|
pip install execsql2[mssql] # SQL Server (pyodbc)
|
|
48
48
|
pip install execsql2[duckdb] # DuckDB
|
|
@@ -272,7 +272,7 @@ execsql-format --no-sql --in-place scripts/
|
|
|
272
272
|
```yaml
|
|
273
273
|
repos:
|
|
274
274
|
- repo: https://github.com/geocoug/execsql
|
|
275
|
-
rev: v2.
|
|
275
|
+
rev: v2.22.0
|
|
276
276
|
hooks:
|
|
277
277
|
- id: execsql-format
|
|
278
278
|
```
|
|
@@ -179,7 +179,7 @@ ______________________________________________________________________
|
|
|
179
179
|
|
|
180
180
|
### CLI Interface
|
|
181
181
|
|
|
182
|
-
The CLI framework changed from `optparse` to [Typer](https://typer.tiangolo.com/) with Rich-formatted help text. All original short flags (`-a` through `-z`) are preserved. The
|
|
182
|
+
The CLI framework changed from `optparse` to [Typer](https://typer.tiangolo.com/) with Rich-formatted help text. All original short flags (`-a` through `-z`) are preserved. The PyPI distribution is named `execsql2`, but the installed executable remains `execsql` for compatibility.
|
|
183
183
|
|
|
184
184
|
Seven upstream long-form flags were renamed underscore → hyphen and the underscore forms are **not** accepted: `--database-encoding`, `--script-encoding`, `--output-encoding`, `--import-encoding`, `--import-buffer`, `--user-logfile`, `--visible-prompts` (upstream wrote these with underscores). Scripts and CI pipelines that invoke the long-form flags must update the spelling; the short letters (`-e`, `-f`, `-g`, `-i`, `-l`, `-v`, `-z`) are unchanged.
|
|
185
185
|
|
|
@@ -271,45 +271,49 @@ These are behavioral changes driven by security or correctness issues in the ups
|
|
|
271
271
|
|
|
272
272
|
### Bug Fixes
|
|
273
273
|
|
|
274
|
-
| Area | Fix
|
|
275
|
-
| --------------------------------------------------- |
|
|
276
|
-
| Oracle default port | Corrected from `5432` (PostgreSQL) to `1521`.
|
|
277
|
-
| MySQL `LOAD DATA INFILE` encoding | Python encoding names are now mapped to MySQL charset names.
|
|
278
|
-
| `dt_cast` type converters | Base `Database` class auto-populates 8 type converters that were previously left empty after the refactor.
|
|
279
|
-
| `FileWriter` CPU busy-loop | Uses blocking `queue.get(timeout=0.1)` instead of `get_nowait()` in a tight loop.
|
|
280
|
-
| Substitution variable cycles | 100-iteration limit prevents infinite loops on cyclic variable references.
|
|
281
|
-
| Script location in error messages | `ErrInfo.script_file` and `script_line_no` are now populated via `stamp_errinfo()` so error output includes "Line N of script foo.sql" context — restoring behavior present in the monolith.
|
|
282
|
-
| `$ERROR_MESSAGE` not updated | `$ERROR_MESSAGE` is now set on every error path: `exit_now()`, non-halting SQL errors, and non-halting metacommand errors. Previously it was initialized to `""` and never changed.
|
|
283
|
-
| Metacommand error message lost | When `halt_on_metacommand_err` is `ON`, the original handler `ErrInfo` is now re-raised; the generic "Unknown metacommand" message no longer replaces the specific error from the handler.
|
|
284
|
-
| Empty script name in error msg | `_execute_script_direct()` and `_execute_script_textual_console()` no longer append "in script , line 0" to uncaught-exception messages when `current_script_line()` returns an empty string.
|
|
285
|
-
| `PROMPT COMPARE` diff comparison | Diff engine uses native Python equality instead of string comparison — numeric types, Decimals, and booleans compare correctly. `None` is distinguished from empty string. Columns are matched by name (not position), key columns are excluded from comparison, and duplicate PKs keep the first row.
|
|
286
|
-
| `win_config_file` broken | Checked `os.name == "windows"` which Python never returns (correct value is `"nt"`). Fixed to `os.name == "nt"`.
|
|
287
|
-
| ELSEIF + ANDIF/ORIF | ANDIF/ORIF after an ELSEIF were silently attached to the parent IF condition instead of the ELSEIF clause. The compound condition was never evaluated for the ELSEIF branch. Fixed in the AST parser and executor.
|
|
288
|
-
| Cursor leak in `select_rowsource()` | Cursor was not closed on query execution failure. Row generators in EXPORT and COPY paths were not explicitly closed on error, relying on garbage collection for cleanup.
|
|
289
|
-
| `NumericParser` right-associative | Arithmetic operators were parsed right-to-left. `10 - 3 - 2` evaluated as `9` instead of `5`. Fixed to left-associative parsing.
|
|
290
|
-
| Empty-column check precedence | `DataTable` and `Database.populate_table()` had an operator precedence bug in the extra-column emptiness check — a redundant `and conf.del_empty_cols` caused incorrect short-circuit evaluation.
|
|
291
|
-
| SQLite import string processing | `SQLiteDatabase.populate_table()` applied `trim_strings`, `replace_newlines`, and `empty_strings` after copying row data, so processing never reached the INSERT. Fixed to process before extraction.
|
|
292
|
-
| `$CURRENT_DATABASE`/`$CURRENT_DBMS` stale after USE | These variables were only set at startup and on CONNECT, not refreshed when `USE` switched the active database. Now set in `set_static_system_vars()` so they update on any connection change.
|
|
293
|
-
| `DT_Text.data_type_name` wrong | Was `"character"` (same as `DT_Character`), making error messages indistinguishable. Corrected to `"text"`.
|
|
294
|
-
| `DT_Varchar` non-string data unchecked | `_from_data()` only enforced the 255-char limit for `str` inputs; non-string values passed through without conversion or length check.
|
|
295
|
-
| `WriteHooks.write_err()` crash on empty string | `strval[-1]` raised `IndexError` on empty input. Fixed to use `str.endswith()`.
|
|
296
|
-
| `NumericParser` division by zero | `NumericAstNode.eval()` raised unhandled `ZeroDivisionError`. Now raises `NumericParserError` with a clear message.
|
|
297
|
-
| `CondAstNode.eval()` could return `None` | Missing fallthrough for unknown node types silently returned `None`. Now raises `CondParserError`.
|
|
298
|
-
| `DT_Timestamp` claims time-only values | `dateutil.parser.parse()` silently fills in today's date for bare time strings like `"13:15:45"`, so `DT_Timestamp` matched before `DT_Time` in the inference order. `parse_datetime()` now rejects time-only strings.
|
|
299
|
-
| `CounterVars.substitute` skipped pos 0–1 | `re.I` was passed as the positional `pos` argument, skipping the first 2 characters of every string during counter variable expansion. Counter variables at the very start of a line were never matched.
|
|
300
|
-
| `exec_cmd` (SQLite/DuckDB) always raised TypeError | Passed bytes to `curs.execute()` via `.encode()`, which Python 3 `sqlite3`/`duckdb` reject. `EXECUTE PROCEDURE` metacommand was non-functional on these backends.
|
|
301
|
-
| MySQL `LOAD DATA INFILE` injection | File path, delimiter, and quotechar were interpolated without escaping. Now single-quotes are escaped consistent with the PostgreSQL COPY path.
|
|
302
|
-
|
|
|
303
|
-
|
|
|
304
|
-
|
|
|
305
|
-
|
|
|
306
|
-
|
|
|
307
|
-
|
|
|
308
|
-
|
|
|
309
|
-
|
|
|
310
|
-
|
|
|
311
|
-
| AST parser
|
|
312
|
-
| AST
|
|
274
|
+
| Area | Fix |
|
|
275
|
+
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
276
|
+
| Oracle default port | Corrected from `5432` (PostgreSQL) to `1521`. |
|
|
277
|
+
| MySQL `LOAD DATA INFILE` encoding | Python encoding names are now mapped to MySQL charset names. |
|
|
278
|
+
| `dt_cast` type converters | Base `Database` class auto-populates 8 type converters that were previously left empty after the refactor. |
|
|
279
|
+
| `FileWriter` CPU busy-loop | Uses blocking `queue.get(timeout=0.1)` instead of `get_nowait()` in a tight loop. |
|
|
280
|
+
| Substitution variable cycles | 100-iteration limit prevents infinite loops on cyclic variable references. |
|
|
281
|
+
| Script location in error messages | `ErrInfo.script_file` and `script_line_no` are now populated via `stamp_errinfo()` so error output includes "Line N of script foo.sql" context — restoring behavior present in the monolith. |
|
|
282
|
+
| `$ERROR_MESSAGE` not updated | `$ERROR_MESSAGE` is now set on every error path: `exit_now()`, non-halting SQL errors, and non-halting metacommand errors. Previously it was initialized to `""` and never changed. |
|
|
283
|
+
| Metacommand error message lost | When `halt_on_metacommand_err` is `ON`, the original handler `ErrInfo` is now re-raised; the generic "Unknown metacommand" message no longer replaces the specific error from the handler. |
|
|
284
|
+
| Empty script name in error msg | `_execute_script_direct()` and `_execute_script_textual_console()` no longer append "in script , line 0" to uncaught-exception messages when `current_script_line()` returns an empty string. |
|
|
285
|
+
| `PROMPT COMPARE` diff comparison | Diff engine uses native Python equality instead of string comparison — numeric types, Decimals, and booleans compare correctly. `None` is distinguished from empty string. Columns are matched by name (not position), key columns are excluded from comparison, and duplicate PKs keep the first row. |
|
|
286
|
+
| `win_config_file` broken | Checked `os.name == "windows"` which Python never returns (correct value is `"nt"`). Fixed to `os.name == "nt"`. |
|
|
287
|
+
| ELSEIF + ANDIF/ORIF | ANDIF/ORIF after an ELSEIF were silently attached to the parent IF condition instead of the ELSEIF clause. The compound condition was never evaluated for the ELSEIF branch. Fixed in the AST parser and executor. |
|
|
288
|
+
| Cursor leak in `select_rowsource()` | Cursor was not closed on query execution failure. Row generators in EXPORT and COPY paths were not explicitly closed on error, relying on garbage collection for cleanup. |
|
|
289
|
+
| `NumericParser` right-associative | Arithmetic operators were parsed right-to-left. `10 - 3 - 2` evaluated as `9` instead of `5`. Fixed to left-associative parsing. |
|
|
290
|
+
| Empty-column check precedence | `DataTable` and `Database.populate_table()` had an operator precedence bug in the extra-column emptiness check — a redundant `and conf.del_empty_cols` caused incorrect short-circuit evaluation. |
|
|
291
|
+
| SQLite import string processing | `SQLiteDatabase.populate_table()` applied `trim_strings`, `replace_newlines`, and `empty_strings` after copying row data, so processing never reached the INSERT. Fixed to process before extraction. |
|
|
292
|
+
| `$CURRENT_DATABASE`/`$CURRENT_DBMS` stale after USE | These variables were only set at startup and on CONNECT, not refreshed when `USE` switched the active database. Now set in `set_static_system_vars()` so they update on any connection change. |
|
|
293
|
+
| `DT_Text.data_type_name` wrong | Was `"character"` (same as `DT_Character`), making error messages indistinguishable. Corrected to `"text"`. |
|
|
294
|
+
| `DT_Varchar` non-string data unchecked | `_from_data()` only enforced the 255-char limit for `str` inputs; non-string values passed through without conversion or length check. |
|
|
295
|
+
| `WriteHooks.write_err()` crash on empty string | `strval[-1]` raised `IndexError` on empty input. Fixed to use `str.endswith()`. |
|
|
296
|
+
| `NumericParser` division by zero | `NumericAstNode.eval()` raised unhandled `ZeroDivisionError`. Now raises `NumericParserError` with a clear message. |
|
|
297
|
+
| `CondAstNode.eval()` could return `None` | Missing fallthrough for unknown node types silently returned `None`. Now raises `CondParserError`. |
|
|
298
|
+
| `DT_Timestamp` claims time-only values | `dateutil.parser.parse()` silently fills in today's date for bare time strings like `"13:15:45"`, so `DT_Timestamp` matched before `DT_Time` in the inference order. `parse_datetime()` now rejects time-only strings. |
|
|
299
|
+
| `CounterVars.substitute` skipped pos 0–1 | `re.I` was passed as the positional `pos` argument, skipping the first 2 characters of every string during counter variable expansion. Counter variables at the very start of a line were never matched. |
|
|
300
|
+
| `exec_cmd` (SQLite/DuckDB) always raised TypeError | Passed bytes to `curs.execute()` via `.encode()`, which Python 3 `sqlite3`/`duckdb` reject. `EXECUTE PROCEDURE` metacommand was non-functional on these backends. |
|
|
301
|
+
| MySQL `LOAD DATA INFILE` injection | File path, delimiter, and quotechar were interpolated without escaping. Now single-quotes are escaped consistent with the PostgreSQL COPY path. |
|
|
302
|
+
| Missing server/database name at connect | Connecting to a server-based database without a server or database name now stops with a clear fatal error ("Configured database requires a server name, but none is provided.") instead of crashing inside the driver with a `TypeError`. |
|
|
303
|
+
| Config file chain infinite loop | The `config_file` directive could chain config files without limit. A circular reference (via symlinks or different relative paths) caused an infinite loop at startup. Now capped at 20 files. |
|
|
304
|
+
| Cursor leaks in database adapters | ~15 methods across all adapters used `curs = self.cursor()` / `curs.close()` without `try/finally`. If the query raised, the cursor leaked. Converted to `with self._cursor() as curs:`. |
|
|
305
|
+
| JSON export malformed on special column names | Column names containing `"` or `\` produced invalid JSON. Now uses `json.dumps()` for all field names. |
|
|
306
|
+
| Temp file creation TOCTOU race | `TempFileMgr.new_temp_fn()` discarded the `NamedTemporaryFile` handle, creating a race window. Now uses `tempfile.mkstemp()` for secure creation. |
|
|
307
|
+
| `shlex.split` on Windows incorrect mode | Called without `posix=False` on Windows, mishandling backslash-heavy paths in SHELL commands. |
|
|
308
|
+
| AST executor `~`/`+` variable scoping broken | The AST executor passed `localvars` through function parameters but never pushed `CommandList` frames onto `commandliststack`. Legacy metacommand handlers (`x_sub`, `x_rm_sub`, `xf_sub_defined`, `SUB_LOCAL`, prompt handlers, REPL) access `commandliststack[-1]` for `~` local and `+` outer-scope variables. This caused `~` vars to be invisible to SQL, `SUB_DEFINED(~var)` to always return false, and the REPL `.vars`/`.stack` to show empty state. Fixed by pushing/popping `CommandList` frames in `execute()` and `_execute_script_native()`. |
|
|
309
|
+
| Firebird adapter import | Adapter imported `fdb` (the unmaintained legacy driver) while the `[firebird]` extra declared `firebird-driver`. `pip install execsql2[firebird]` followed by a Firebird connect raised `ModuleNotFoundError: No module named 'fdb'`. Adapter now imports `firebird.driver`, matching the declared dependency. |
|
|
310
|
+
| Connect timeouts on network adapters | MySQL, SQL Server / Access / DSN (pyodbc), Firebird, and SMTP all now apply a 30 s connect timeout matching the existing PostgreSQL default. A silently-dropped network peer (firewall rule, dead VM) used to hang scripts indefinitely; now the connect fails fast. |
|
|
311
|
+
| AST parser INCLUDE quoted paths broken | The AST parser captured the full INCLUDE target including surrounding quotes (`"path"`), but the legacy dispatch regex stripped them. Quoted INCLUDE paths failed with "File does not exist" even when the file was present. Fixed by stripping matched quote pairs in the parser. |
|
|
312
|
+
| AST parser `BEGIN SCRIPT name(params)` rejected | The regex required whitespace between the script name and parameter list. `BEGIN SCRIPT foo(a,b)` (no space before `(`) silently failed to match, causing the matching `END SCRIPT` to raise "Unmatched END SCRIPT metacommand." Fixed by allowing optional whitespace before the parameter expression. |
|
|
313
|
+
| AST executor forward SCRIPT references broken | The legacy engine registered all `BEGIN SCRIPT` blocks at parse time (two-pass), so `EXECUTE SCRIPT foo` could appear before the `BEGIN SCRIPT foo` definition. The AST executor walked the tree in a single pass, so forward references failed with "There is no SCRIPT named foo." Fixed by adding a pre-registration scan of all SCRIPT blocks before execution begins. |
|
|
314
|
+
| DB-export type inference overrides source types | `DataTable`/`Column` inferred column types from the *string shape* of values — correct for CSV import (everything is `str`) but wrong for DB-query exports where the driver returns typed Python objects. A text column with values like `"2026-06-30 10:07:20 PM"` was inferred as `TIMESTAMP`, causing DuckDB bind errors. SQLite, DuckDB, HDF5, and JSON-schema exports now pass `infer_strings=False` to `DataTable`: string values are classified as text types only, while native Python objects (`Decimal`, `datetime`, etc.) still run through the full accumulator set for accurate schema inference. |
|
|
315
|
+
| `EXPORT FORMAT SQLITE` rejects `decimal.Decimal` | SQLite's Python adapter does not accept `Decimal` in `executemany`, raising `ProgrammingError`. SQLite exports now convert `Decimal` values to their exact string representation before binding; SQLite's NUMERIC affinity stores them without loss of precision. |
|
|
316
|
+
| Unsupported Python objects crash native exports | `EXPORT FORMAT SQLITE` and `EXPORT FORMAT DUCKDB` raised bind errors when the DB driver returned user-defined Python objects (e.g. PostGIS geometry). Both exporters now stringify any object whose type is not in the adapter's safe-binding set, preserving values as their `str()` form instead of crashing. |
|
|
313
317
|
|
|
314
318
|
______________________________________________________________________
|
|
315
319
|
|
|
@@ -6,7 +6,7 @@ ______________________________________________________________________
|
|
|
6
6
|
|
|
7
7
|
## Execution Flow
|
|
8
8
|
|
|
9
|
-
When a user runs `
|
|
9
|
+
When a user runs `execsql script.sql mydb.sqlite -t l`, the following sequence occurs:
|
|
10
10
|
|
|
11
11
|
```mermaid
|
|
12
12
|
flowchart TD
|
|
@@ -14,7 +14,8 @@ Or with [uv](https://docs.astral.sh/uv/):
|
|
|
14
14
|
uv add execsql2
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
This installs the `
|
|
17
|
+
This installs the `execsql` and `execsql-format` command-line tools. The PyPI distribution is named
|
|
18
|
+
`execsql2`; the executable remains `execsql` for compatibility.
|
|
18
19
|
|
|
19
20
|
To install with optional dependencies:
|
|
20
21
|
|
|
@@ -12,7 +12,7 @@ When adding a very large amount of data with the [IMPORT](../reference/metacomma
|
|
|
12
12
|
|
|
13
13
|
## Implicit DROP TABLE Statements
|
|
14
14
|
|
|
15
|
-
The "REPLACEMENT" keyword for the [IMPORT](../reference/metacommands.md#import) and [COPY](../reference/metacommands.md#copy) metacommands allows a previously existing table to be replaced. To accomplish this, execsql issues a "DROP TABLE" statement to the database in use. PostgreSQL, SQLite, MySQL, MariaDB, Oracle, and DuckDB support a form of the "DROP TABLE" statement that automatically removes all foreign keys to the named table. execsql uses these forms of the "DROP TABLE" statement for these DBMSs
|
|
15
|
+
The "REPLACEMENT" keyword for the [IMPORT](../reference/metacommands.md#import) and [COPY](../reference/metacommands.md#copy) metacommands allows a previously existing table to be replaced. To accomplish this, execsql issues a "DROP TABLE" statement to the database in use. This is not an atomic replacement: if the drop succeeds but a later create or load step fails, the old table has already been removed. If the drop fails, execsql stops the metacommand before creating or loading the replacement table. PostgreSQL, SQLite, MySQL, MariaDB, Oracle, and DuckDB support a form of the "DROP TABLE" statement that automatically removes all foreign keys to the named table. execsql uses these forms of the "DROP TABLE" statement for these DBMSs. SQL Server, MS-Access, and Firebird do not have a form of the "DROP TABLE" statement that automatically removes foreign keys. Therefore, if the "REPLACEMENT" keyword is used with any of these three DBMSs, for a table that has foreign keys into it, that table will not be dropped, and the IMPORT or COPY command will stop. To avoid this, when using any of these three DBMSs, you should include in the script the appropriate SQL commands to remove foreign keys (and possibly even to remove the table) before using the IMPORT or COPY metacommands.
|
|
16
16
|
|
|
17
17
|
## Boolean Data Types
|
|
18
18
|
|
|
@@ -333,6 +333,9 @@ The section and property names that may be used in a configuration file are list
|
|
|
333
333
|
`allow_system_cmd` { #allow_system_cmd }
|
|
334
334
|
: When set to "No", the `SYSTEM_CMD` (SHELL) metacommand is disabled. Any script that attempts to execute an OS command will fail with an error. The default is "Yes". This can also be set via the `--no-system-cmd` CLI flag or `allow_system_cmd=False` in the library API. See [Security — Disabling SYSTEM_CMD](security.md#disable_system_cmd) for details.
|
|
335
335
|
|
|
336
|
+
`system_cmd_timeout` { #system_cmd_timeout }
|
|
337
|
+
: Maximum number of seconds a foreground `SYSTEM_CMD` may run before *execsql* stops it. The default is `0`, which means no timeout. When a foreground command times out, `$SYSTEM_CMD_EXIT_STATUS` is set to `124` and the metacommand fails. `SYSTEM_CMD ... CONTINUE` starts a detached background process and is not timeout-managed by this setting.
|
|
338
|
+
|
|
336
339
|
`allow_rm_file` { #allow_rm_file }
|
|
337
340
|
: When set to "No", the `RM_FILE` metacommand (which deletes a file) is disabled. Any script that attempts to remove a file will fail with an error. The default is "Yes". This can also be set via the `--no-rm-file` CLI flag or `allow_rm_file=False` in the library API. Symmetric with `allow_system_cmd`.
|
|
338
341
|
|