execsql2 2.10.1__tar.gz → 2.11.1__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.10.1 → execsql2-2.11.1}/.claude/project_context.md +24 -8
- {execsql2-2.10.1 → execsql2-2.11.1}/CHANGELOG.md +43 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/PKG-INFO +6 -2
- {execsql2-2.10.1 → execsql2-2.11.1}/README.md +5 -1
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/about/divergence.md +13 -8
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/getting-started/syntax.md +4 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/reference/metacommands.md +23 -10
- {execsql2-2.10.1 → execsql2-2.11.1}/pyproject.toml +2 -2
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/cli/__init__.py +6 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/cli/lint.py +1 -1
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/cli/run.py +8 -3
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/xlsx.py +5 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/yaml.py +2 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/control.py +4 -10
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/debug.py +1 -1
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/debug_repl.py +106 -44
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/script/engine.py +21 -7
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/state.py +2 -2
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/errors.py +41 -2
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/gui.py +26 -4
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_breakpoint.py +108 -48
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_metacommands_extended.py +1 -3
- execsql2-2.11.1/tests/test_error_messages.py +452 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/uv.lock +1 -1
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/agents/dba.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/agents/herald.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/agents/inspector.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/agents/oracle.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/agents/patcher.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/agents/qa.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/agents/scribe.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/commands/code-oracle.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/commands/migrate.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/commands/review-changes.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/commands/test-module.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/commands/update-changelog.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/commands/where-is.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.claude/state/status.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.github/workflows/ci-cd.yml +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.gitignore +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.pre-commit-config.yaml +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.pre-commit-hooks.yaml +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.python-version +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/.readthedocs.yaml +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/CLAUDE.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/CONTRIBUTING.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/LICENSE.txt +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/NOTICE +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/SECURITY.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/about/contributors.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/about/copyright.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/api/cli.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/api/db.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/api/exporters.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/api/importers.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/api/index.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/api/metacommands.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/dev/adding_db_adapters.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/dev/adding_exporters.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/dev/adding_importers.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/dev/adding_metacommands.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/dev/architecture.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/getting-started/installation.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/getting-started/requirements.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/guides/debugging.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/guides/documentation.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/guides/encoding.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/guides/examples.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/guides/formatter.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/guides/logging.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/guides/sql_syntax.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/guides/usage.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/guides/using_scripts.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/Compare_planets.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/actions.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/actions2.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/checkboxes.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/connect.b64 +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/connect.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/create_conf.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/data_error1_screenshot.jpg +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/entry_form.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/execsql_console.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/execsql_logo_01.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/fatals.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/logo_small.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/pause_terminal.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/pause_terminal_sm.b64 +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/pause_terminal_sm.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/prompt_compare.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/set_build_commands.jpg +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/unit_conversions.b64 +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/unit_conversions_029.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/unmatched.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/images/vim_execsql_highlight.png +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/index.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/reference/configuration.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/reference/security.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/docs/reference/substitution_vars.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/extras/vscode-execsql/README.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/extras/vscode-execsql/package.json +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/justfile +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/scripts/generate_vscode_grammar.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/__main__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/cli/dsn.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/cli/help.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/config.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/constants.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/access.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/base.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/dsn.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/duckdb.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/factory.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/firebird.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/mysql.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/oracle.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/postgres.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/sqlite.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/db/sqlserver.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exceptions.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/base.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/delimited.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/duckdb.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/feather.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/html.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/json.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/latex.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/markdown.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/ods.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/parquet.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/pretty.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/protocol.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/raw.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/sqlite.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/templates.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/values.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/xls.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/xml.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/exporters/zip.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/format.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/gui/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/gui/base.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/gui/console.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/gui/desktop.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/gui/tui.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/importers/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/importers/base.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/importers/csv.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/importers/feather.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/importers/ods.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/importers/xls.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/conditions.py +1 -1
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/connect.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/data.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/dispatch.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/io.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/io_export.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/io_fileops.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/io_import.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/io_write.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/prompt.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/script_ext.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/metacommands/system.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/models.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/parser.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/py.typed +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/script/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/script/control.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/script/variables.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/types.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/auth.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/crypto.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/datetime.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/fileio.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/mail.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/numeric.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/regex.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/strings.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/src/execsql/utils/timer.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/README.md +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/config_settings.sqlite +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/example_config_prompt.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/execsql.conf +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/make_config_db.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/md_compare.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/md_glossary.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/md_upsert.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/pg_compare.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/pg_glossary.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/pg_upsert.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/script_template.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/ss_compare.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/ss_glossary.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/templates/ss_upsert.sql +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/cli/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/cli/test_cli.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/cli/test_cli_e2e.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/cli/test_cli_run.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/cli/test_lint.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/cli/test_ping.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/cli/test_profile.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/conftest.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/db/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/db/test_base.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/db/test_duckdb.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/db/test_factory.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/db/test_postgres.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/db/test_sqlite.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/db/test_sqlite_extra.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_base.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_db.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_delimited.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_duckdb_exporter.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_exporters.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_feather.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_html_latex.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_json.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_markdown.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_ods.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_parquet.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_sqlite_exporter.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_templates.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_xls_xlsx.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_xlsx.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_xml.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_yaml.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/exporters/test_zip.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/gui/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/gui/test_backends.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/importers/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/importers/test_csv_importer.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/importers/test_feather_importer.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/importers/test_ods_importer.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/importers/test_xls_importer.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/integration/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/integration/conftest.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/integration/test_dsn.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/integration/test_duckdb.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/integration/test_mysql.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/integration/test_postgres.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/integration/test_sqlite.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_assert.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_connect.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_metacommands.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_metacommands_connect.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_metacommands_data.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_metacommands_io.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_metacommands_script_ext.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_metacommands_system.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_metacommands_system_extra.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/metacommands/test_row_count.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_config.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_config_data.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_constants.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_engine.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_exceptions.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_format.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_mail.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_models.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_package.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_parser.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_registry.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_script.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_state.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/test_types.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/__init__.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_auth.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_auth_extra.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_crypto.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_datetime.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_errors.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_errors_extra.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_fileio.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_fileio_extra.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_numeric.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_regex.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_strings.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_timer.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/tests/utils/test_timer_extra.py +0 -0
- {execsql2-2.10.1 → execsql2-2.11.1}/zensical.toml +0 -0
|
@@ -189,10 +189,10 @@ Triggered on: push to `main`, any tag `v*.*.*`, pull requests.
|
|
|
189
189
|
|
|
190
190
|
## Versioning
|
|
191
191
|
|
|
192
|
-
`bump-my-version` manages versions. Current: `2.
|
|
192
|
+
`bump-my-version` manages versions. Current: `2.11.0`. Bump commands:
|
|
193
193
|
|
|
194
|
-
- `just bump-patch` → 2.
|
|
195
|
-
- `just bump-minor` → 2.
|
|
194
|
+
- `just bump-patch` → 2.11.0 → 2.11.1
|
|
195
|
+
- `just bump-minor` → 2.11.0 → 2.12.0
|
|
196
196
|
Bumps commit + tag. Pre-commit hook runs `uv lock` + stages `uv.lock`.
|
|
197
197
|
|
|
198
198
|
## Ruff Config
|
|
@@ -254,16 +254,32 @@ the foreseeable future.
|
|
|
254
254
|
| Dispatch optimization already in place (verified) | 2.5.0 | 2026-04 |
|
|
255
255
|
| PostgreSQL integration tests (9 tests, CI Docker) | 2.5.0 | 2026-04 |
|
|
256
256
|
| MySQL integration tests (9 tests, CI Docker) | 2.5.0 | 2026-04 |
|
|
257
|
+
| `RuntimeContext` refactor + module proxy | 2.6.0 | 2026-04 |
|
|
258
|
+
| `noqa` cleanup (180 suppressions removed) | 2.6.0 | 2026-04 |
|
|
259
|
+
| Coverage raised to 86% (3010 tests) | 2.6.0 | 2026-04 |
|
|
260
|
+
| Markdown, YAML, XLSX export formats | 2.7.0 | 2026-04 |
|
|
261
|
+
| `ASSERT` metacommand | 2.8.0 | 2026-04 |
|
|
262
|
+
| `--dry-run` variable expansion | 2.8.0 | 2026-04 |
|
|
263
|
+
| `--profile` per-statement timing | 2.8.0 | 2026-04 |
|
|
264
|
+
| `--ping` connectivity test | 2.9.0 | 2026-04 |
|
|
265
|
+
| `--lint` static script analysis | 2.9.0 | 2026-04 |
|
|
266
|
+
| Configuration docs audit (6 fixes) | 2.9.0 | 2026-04 |
|
|
267
|
+
| `ROW_COUNT_GT/GTE/EQ/LT` conditionals | 2.10.0 | 2026-04 |
|
|
268
|
+
| `BREAKPOINT` debug REPL with step mode | 2.10.0 | 2026-04 |
|
|
269
|
+
| Error messages restored (script location, command) | 2.11.0 | 2026-04 |
|
|
270
|
+
| 16-item codebase analysis fix sweep | 2.11.x | 2026-04 |
|
|
257
271
|
|
|
258
272
|
______________________________________________________________________
|
|
259
273
|
|
|
260
|
-
### v2.6
|
|
274
|
+
### Completed milestone detail (v2.6–v2.11)
|
|
261
275
|
|
|
262
|
-
|
|
263
|
-
- [x] **`noqa` cleanup in `metacommands/__init__.py`** — removed all 180 redundant `# noqa` comments; `__all__` already satisfies ruff F401.
|
|
264
|
-
- [x] **Coverage push to 86%** — 403 new tests (3010 total) covering `db/base.py` (55→99%), `metacommands/connect.py` (36→100%), `script/engine.py` (77→95%), `exporters/delimited.py` (76→95%). Remaining gap to 90% is in GUI, ODS, and import handlers.
|
|
276
|
+
#### v2.6 — Architecture & Internal Quality
|
|
265
277
|
|
|
266
|
-
|
|
278
|
+
- [x] `state.py` → `RuntimeContext` refactor
|
|
279
|
+
- [x] `noqa` cleanup in `metacommands/__init__.py`
|
|
280
|
+
- [x] Coverage push to 86%
|
|
281
|
+
|
|
282
|
+
#### v2.7 — New Export/Import Formats
|
|
267
283
|
|
|
268
284
|
- [x] **Parquet import** — already existed as `IMPORT TO table FROM PARQUET file` (verified present).
|
|
269
285
|
- [x] **YAML export** — `FORMAT YAML` via PyYAML, list-of-dicts with native type preservation.
|
|
@@ -13,6 +13,49 @@ ______________________________________________________________________
|
|
|
13
13
|
|
|
14
14
|
______________________________________________________________________
|
|
15
15
|
|
|
16
|
+
## [2.11.1] - 2026-04-01
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- `x_assert` crash when `exec_log` is None — added null guard on `log_user_msg()` call.
|
|
21
|
+
- `--ping` version-query loop exiting prematurely — `break` was at wrong indentation, skipping fallback queries when the first query returned no rows.
|
|
22
|
+
- `CONSOLE SET WIDTH/HEIGHT` crash — `gui_console_width()`/`gui_console_height()` restored as setter functions with GUI console propagation.
|
|
23
|
+
- `$ERROR_MESSAGE` now contains full `errmsg()` (with script location and timestamp) for non-halting errors.
|
|
24
|
+
- Non-halting SQL and metacommand errors now logged to exec_log.
|
|
25
|
+
- `x_debug_log_subvars` log format — was printing full tuple instead of name/value for local variables.
|
|
26
|
+
- Dead `endloop()` removed from `control.py` — `state.endloop()` is canonical.
|
|
27
|
+
- YAML `append=True` now emits `---` document separator for valid multi-document streams.
|
|
28
|
+
- REPL dot-command parsing consistency between dispatcher and exit-check.
|
|
29
|
+
- `__delattr__` on state proxy uses cached `_DEFAULT_CTX` instead of allocating per call.
|
|
30
|
+
- `write_query_to_xlsx` single-sheet now updates `export_metadata`.
|
|
31
|
+
- `isinstance()` used instead of `type()` equality in `MetaCommandList.add()`.
|
|
32
|
+
- Module docstrings in `conditions.py` and `control.py` moved before imports.
|
|
33
|
+
- FEATHER divergence doc corrected — `polars` only, not `polars + pyarrow`.
|
|
34
|
+
- README pre-commit rev updated to `v2.11.0`; options table completed.
|
|
35
|
+
|
|
36
|
+
______________________________________________________________________
|
|
37
|
+
|
|
38
|
+
## [2.11.0] - 2026-04-01
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- `--debug` CLI flag — starts the script in step-through debug mode. The debug REPL pauses before each statement, as if `BREAKPOINT` were inserted at the top with `.next` always active.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- BREAKPOINT debug REPL now pauses **before** each statement instead of after, so the upcoming statement can be inspected before it runs.
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- BREAKPOINT REPL no longer wraps variable values in extra single quotes — values are now displayed exactly as defined.
|
|
51
|
+
- Error messages now include script file name and line number — `ErrInfo` fields `script_file` and `script_line_no` are populated via a new `stamp_errinfo()` helper called from `exit_now()` and metacommand error paths, restoring monolith-level "Line N of script foo.sql" context in all error output.
|
|
52
|
+
- `$ERROR_MESSAGE` substitution variable is now updated on every error: in `exit_now()`, in non-halting SQL errors (`SqlStmt.run()`), and in non-halting metacommand errors (`MetacommandStmt.run()`). Previously it was initialized to `""` and never changed.
|
|
53
|
+
- `MetacommandStmt.run()` now re-raises the original handler `ErrInfo` when `halt_on_metacommand_err` is True, instead of discarding it and raising a generic "Unknown metacommand" error.
|
|
54
|
+
- `write_warning()` now accepts an `always=True` keyword argument that bypasses the `conf.write_warnings` gate, ensuring structural warnings (IF-level mismatch, unsubstituted variables) are always visible on stderr.
|
|
55
|
+
- Uncaught-exception error message in `_execute_script_direct()` and `_execute_script_textual_console()` no longer appends "in script , line 0" when `current_script_line()` returns an empty string.
|
|
56
|
+
|
|
57
|
+
______________________________________________________________________
|
|
58
|
+
|
|
16
59
|
## [2.10.1] - 2026-04-01
|
|
17
60
|
|
|
18
61
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.11.1
|
|
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: Repository, https://github.com/geocoug/execsql
|
|
6
6
|
Project-URL: Issues, https://github.com/geocoug/execsql/issues
|
|
@@ -220,9 +220,13 @@ execsql script.sql # read connection from config file
|
|
|
220
220
|
| `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
|
|
221
221
|
| `-w` | Skip password prompt when a username is supplied |
|
|
222
222
|
| `--dsn URL` | Connection string (e.g. `postgresql://user:pass@host/db`) |
|
|
223
|
+
| `--output-dir DIR` | Default base directory for EXPORT output files |
|
|
223
224
|
| `--dry-run` | Parse the script and report commands without executing |
|
|
224
225
|
| `--lint` | Static analysis: check structure and warn on issues (no DB) |
|
|
226
|
+
| `--ping` | Test database connectivity and exit |
|
|
227
|
+
| `--profile` | Show per-statement timing summary after execution |
|
|
225
228
|
| `--progress` | Show a progress bar for long-running IMPORT operations |
|
|
229
|
+
| `--debug` | Start in step-through debug mode (REPL pauses before each stmt) |
|
|
226
230
|
| `--dump-keywords` | Print metacommand keywords as JSON and exit |
|
|
227
231
|
| `--gui-framework {tkinter,textual}` | GUI framework for interactive prompts |
|
|
228
232
|
|
|
@@ -297,7 +301,7 @@ execsql-format --check scripts/
|
|
|
297
301
|
```yaml
|
|
298
302
|
repos:
|
|
299
303
|
- repo: https://github.com/geocoug/execsql
|
|
300
|
-
rev: v2.
|
|
304
|
+
rev: v2.11.0
|
|
301
305
|
hooks:
|
|
302
306
|
- id: execsql-format
|
|
303
307
|
args: [--in-place]
|
|
@@ -110,9 +110,13 @@ execsql script.sql # read connection from config file
|
|
|
110
110
|
| `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
|
|
111
111
|
| `-w` | Skip password prompt when a username is supplied |
|
|
112
112
|
| `--dsn URL` | Connection string (e.g. `postgresql://user:pass@host/db`) |
|
|
113
|
+
| `--output-dir DIR` | Default base directory for EXPORT output files |
|
|
113
114
|
| `--dry-run` | Parse the script and report commands without executing |
|
|
114
115
|
| `--lint` | Static analysis: check structure and warn on issues (no DB) |
|
|
116
|
+
| `--ping` | Test database connectivity and exit |
|
|
117
|
+
| `--profile` | Show per-statement timing summary after execution |
|
|
115
118
|
| `--progress` | Show a progress bar for long-running IMPORT operations |
|
|
119
|
+
| `--debug` | Start in step-through debug mode (REPL pauses before each stmt) |
|
|
116
120
|
| `--dump-keywords` | Print metacommand keywords as JSON and exit |
|
|
117
121
|
| `--gui-framework {tkinter,textual}` | GUI framework for interactive prompts |
|
|
118
122
|
|
|
@@ -187,7 +191,7 @@ execsql-format --check scripts/
|
|
|
187
191
|
```yaml
|
|
188
192
|
repos:
|
|
189
193
|
- repo: https://github.com/geocoug/execsql
|
|
190
|
-
rev: v2.
|
|
194
|
+
rev: v2.11.0
|
|
191
195
|
hooks:
|
|
192
196
|
- id: execsql-format
|
|
193
197
|
args: [--in-place]
|
|
@@ -22,6 +22,7 @@ ______________________________________________________________________
|
|
|
22
22
|
| `--progress` | Show a Rich progress bar during long-running IMPORT operations. |
|
|
23
23
|
| `--dump-keywords` | Emit all metacommand keywords, conditionals, config options, and export formats as structured JSON. |
|
|
24
24
|
| `--gui-framework` | Select GUI backend: `tkinter` (default) or `textual` (terminal UI). |
|
|
25
|
+
| `--debug` | Start in step-through debug mode. The debug REPL pauses before each statement, as if `BREAKPOINT` were at the top with `.next` always active. |
|
|
25
26
|
| `--dry-run` | Parse the script and print the full command list without connecting to a database or executing anything. Substitution variables already populated at parse time (env vars, `--assign-arg` values, built-in start-time vars) are expanded in the output; execution-time variables (`$DB_NAME`, `$CURRENT_TIME`, etc.) remain unexpanded. |
|
|
26
27
|
| `--profile` | Record wall-clock time for each SQL and metacommand statement. After the script completes, print a summary table sorted by elapsed time (descending), showing time, percentage of total, source location, command type, and a command preview. Top 20 slowest statements are shown. |
|
|
27
28
|
| `--ping` | Test database connectivity and exit. Connects using the supplied connection parameters, queries for the server version, and prints a one-line success message (exit 0) or the error (exit 1). No script file argument is required. |
|
|
@@ -32,7 +33,7 @@ ______________________________________________________________________
|
|
|
32
33
|
| Format | Description |
|
|
33
34
|
| ----------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
34
35
|
| `PARQUET` | Export query or table results to Apache Parquet via `polars`. |
|
|
35
|
-
| `FEATHER` | Export to Apache Feather/IPC via `polars`
|
|
36
|
+
| `FEATHER` | Export to Apache Feather/IPC via `polars` (upstream used `pandas` + `pyarrow`). |
|
|
36
37
|
| `YAML` | Export query or table results as a YAML sequence of mappings via `PyYAML`. |
|
|
37
38
|
| `MARKDOWN` / `MD` | Export query or table results as a GitHub-Flavored Markdown (GFM) pipe table. Pure Python, no optional dependencies. |
|
|
38
39
|
| `XLSX` | Export query or table results to an Excel XLSX workbook via `openpyxl` (single or multi-sheet). |
|
|
@@ -167,13 +168,17 @@ These are behavioral changes driven by security or correctness issues in the ups
|
|
|
167
168
|
|
|
168
169
|
### Bug Fixes
|
|
169
170
|
|
|
170
|
-
| Area | Fix
|
|
171
|
-
| --------------------------------- |
|
|
172
|
-
| Oracle default port | Corrected from `5432` (PostgreSQL) to `1521`.
|
|
173
|
-
| MySQL `LOAD DATA INFILE` encoding | Python encoding names are now mapped to MySQL charset names.
|
|
174
|
-
| `dt_cast` type converters | Base `Database` class auto-populates 8 type converters that were previously left empty after the refactor.
|
|
175
|
-
| `FileWriter` CPU busy-loop | Uses blocking `queue.get(timeout=0.1)` instead of `get_nowait()` in a tight loop.
|
|
176
|
-
| Substitution variable cycles | 100-iteration limit prevents infinite loops on cyclic variable references.
|
|
171
|
+
| Area | Fix |
|
|
172
|
+
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
173
|
+
| Oracle default port | Corrected from `5432` (PostgreSQL) to `1521`. |
|
|
174
|
+
| MySQL `LOAD DATA INFILE` encoding | Python encoding names are now mapped to MySQL charset names. |
|
|
175
|
+
| `dt_cast` type converters | Base `Database` class auto-populates 8 type converters that were previously left empty after the refactor. |
|
|
176
|
+
| `FileWriter` CPU busy-loop | Uses blocking `queue.get(timeout=0.1)` instead of `get_nowait()` in a tight loop. |
|
|
177
|
+
| Substitution variable cycles | 100-iteration limit prevents infinite loops on cyclic variable references. |
|
|
178
|
+
| 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. |
|
|
179
|
+
| `$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. |
|
|
180
|
+
| 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. |
|
|
181
|
+
| 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. |
|
|
177
182
|
|
|
178
183
|
______________________________________________________________________
|
|
179
184
|
|
|
@@ -224,6 +224,10 @@ Valid encoding names can be displayed with the `-y` option. See also [Character
|
|
|
224
224
|
execsql --ping --dsn sqlite:///mydb.sqlite
|
|
225
225
|
```
|
|
226
226
|
|
|
227
|
+
`--debug`
|
|
228
|
+
|
|
229
|
+
: Start in step-through debug mode. The debug REPL pauses before each statement, as if a `BREAKPOINT` metacommand were inserted at the top of the script with `.next` always active. Type `.continue` or `.c` at the REPL prompt to resume normal execution, or `.next` / `.n` to step one statement at a time. Silently skipped in non-TTY environments.
|
|
230
|
+
|
|
227
231
|
`--profile`
|
|
228
232
|
|
|
229
233
|
: Record the wall-clock execution time of each SQL statement and metacommand. After the script finishes, print a summary table to the console showing elapsed time, percentage of total time, source file and line number, command type, and a preview of the command text. Statements are sorted from slowest to fastest; the top 20 are displayed. Useful for identifying slow queries or metacommands in long-running scripts.
|
|
@@ -127,20 +127,30 @@ Pauses script execution and drops into an interactive debug REPL (read-eval-prin
|
|
|
127
127
|
|
|
128
128
|
**Non-interactive safety:** If `sys.stdin` is not a TTY (e.g. CI pipelines, piped input, batch execution) the metacommand is silently skipped. Scripts will never hang in automation.
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
All REPL commands are dot-prefixed to avoid ambiguity with variable names and SQL. Anything without a dot prefix is treated as a variable lookup or SQL.
|
|
131
|
+
|
|
132
|
+
**REPL commands (dot-prefixed):**
|
|
131
133
|
|
|
132
134
|
| Command | Description |
|
|
133
135
|
|---------|-------------|
|
|
134
|
-
|
|
|
135
|
-
|
|
|
136
|
-
|
|
|
137
|
-
|
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
|
|
136
|
+
| `.continue` or `.c` | Resume script execution |
|
|
137
|
+
| `.abort` or `.q` | Halt the script with exit status 1 |
|
|
138
|
+
| `.vars` | List user, system, local, and counter variables (grouped by type) |
|
|
139
|
+
| `.vars all` | Include environment variables (`&`) in the listing |
|
|
140
|
+
| `.next` or `.n` | Execute the next script statement, then pause again (step mode) |
|
|
141
|
+
| `.stack` | Show the command-list stack: script name, cursor index, and nesting depth |
|
|
142
|
+
| `.help` | Show the list of available REPL commands |
|
|
143
|
+
|
|
144
|
+
**Variable inspection and SQL (no dot prefix):**
|
|
142
145
|
|
|
143
|
-
|
|
146
|
+
| Input | Description |
|
|
147
|
+
|-------|-------------|
|
|
148
|
+
| `logfile` | Print the value of the `logfile` variable |
|
|
149
|
+
| `$ARG_1` | Print the value of a system/built-in variable |
|
|
150
|
+
| `&HOME` | Print the value of an environment variable |
|
|
151
|
+
| `SELECT ...;` | Run ad-hoc SQL against the current database and pretty-print results |
|
|
152
|
+
|
|
153
|
+
Pressing Ctrl-D (EOF) or Ctrl-C (KeyboardInterrupt) at the `execsql debug>` prompt resumes execution, the same as typing `.continue`.
|
|
144
154
|
|
|
145
155
|
**Example:**
|
|
146
156
|
|
|
@@ -153,6 +163,9 @@ SELECT count(*) FROM staging;
|
|
|
153
163
|
|
|
154
164
|
BREAKPOINT is silently skipped inside a `False` [IF](#if_cmd) block.
|
|
155
165
|
|
|
166
|
+
!!! tip
|
|
167
|
+
Use `execsql --debug script.sql` to start in step-through mode without adding a `BREAKPOINT` metacommand to your script. The REPL pauses before each statement.
|
|
168
|
+
|
|
156
169
|
|
|
157
170
|
## BEGIN BATCH and END BATCH { #batch }
|
|
158
171
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "execsql2"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.11.1"
|
|
8
8
|
description = "Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = { file = "LICENSE.txt" }
|
|
@@ -158,7 +158,7 @@ skip-magic-trailing-comma = false
|
|
|
158
158
|
line-ending = "auto"
|
|
159
159
|
|
|
160
160
|
[tool.bumpversion]
|
|
161
|
-
current_version = "2.
|
|
161
|
+
current_version = "2.11.1"
|
|
162
162
|
commit = true
|
|
163
163
|
commit_args = "--no-verify"
|
|
164
164
|
tag = true
|
|
@@ -278,6 +278,11 @@ def main(
|
|
|
278
278
|
"--profile",
|
|
279
279
|
help="Record per-statement execution times and print a timing summary after the script completes.",
|
|
280
280
|
),
|
|
281
|
+
debug: bool = typer.Option(
|
|
282
|
+
False,
|
|
283
|
+
"--debug",
|
|
284
|
+
help="Start in step-through debug mode. The debug REPL pauses before each statement.",
|
|
285
|
+
),
|
|
281
286
|
version: bool | None = typer.Option(
|
|
282
287
|
None,
|
|
283
288
|
"--version",
|
|
@@ -446,6 +451,7 @@ def main(
|
|
|
446
451
|
profile=profile,
|
|
447
452
|
ping=ping,
|
|
448
453
|
lint=lint,
|
|
454
|
+
debug=debug,
|
|
449
455
|
)
|
|
450
456
|
|
|
451
457
|
|
|
@@ -194,7 +194,7 @@ def _lint_cmdlist(
|
|
|
194
194
|
for cmd in cmdlist.cmdlist:
|
|
195
195
|
src = cmd.source
|
|
196
196
|
lno = cmd.line_no
|
|
197
|
-
stmt = cmd.command.statement
|
|
197
|
+
stmt = cmd.command.statement
|
|
198
198
|
|
|
199
199
|
if cmd.command_type == "sql":
|
|
200
200
|
# SQL statements: check for variable references only
|
|
@@ -8,6 +8,7 @@ and drives the main execution loop. Separated from argument parsing
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import atexit
|
|
11
|
+
from typing import Any
|
|
11
12
|
import datetime
|
|
12
13
|
import getpass
|
|
13
14
|
import os
|
|
@@ -128,7 +129,7 @@ def _print_profile(profile_data: list[tuple]) -> None:
|
|
|
128
129
|
# ---------------------------------------------------------------------------
|
|
129
130
|
|
|
130
131
|
|
|
131
|
-
def _ping_db(db) -> None:
|
|
132
|
+
def _ping_db(db: Any) -> None:
|
|
132
133
|
"""Test connectivity for *db*, print connection details, and exit.
|
|
133
134
|
|
|
134
135
|
Attempts to execute ``SELECT version()`` (or ``SELECT sqlite_version()``
|
|
@@ -156,7 +157,7 @@ def _ping_db(db) -> None:
|
|
|
156
157
|
curs.close()
|
|
157
158
|
if row and row[0]:
|
|
158
159
|
version_str = str(row[0]).split("\n")[0].strip()
|
|
159
|
-
|
|
160
|
+
break
|
|
160
161
|
except Exception:
|
|
161
162
|
continue
|
|
162
163
|
|
|
@@ -214,6 +215,7 @@ def _run(
|
|
|
214
215
|
profile: bool = False,
|
|
215
216
|
ping: bool = False,
|
|
216
217
|
lint: bool = False,
|
|
218
|
+
debug: bool = False,
|
|
217
219
|
) -> None:
|
|
218
220
|
"""Initialise state, connect to the database, load the script, and run it.
|
|
219
221
|
|
|
@@ -547,6 +549,9 @@ def _run(
|
|
|
547
549
|
if profile:
|
|
548
550
|
_state.profile_data = []
|
|
549
551
|
|
|
552
|
+
if debug:
|
|
553
|
+
_state.step_mode = True
|
|
554
|
+
|
|
550
555
|
_execute_script_direct(conf, profile=profile)
|
|
551
556
|
|
|
552
557
|
|
|
@@ -653,7 +658,7 @@ def _execute_script_direct(conf: ConfigData, *, profile: bool = False) -> None:
|
|
|
653
658
|
lno = strace[0][1]
|
|
654
659
|
msg = f"{Path(sys.argv[0]).name}: Uncaught exception {sys.exc_info()[0]} ({sys.exc_info()[1]}) on line {lno}"
|
|
655
660
|
script, slno = current_script_line()
|
|
656
|
-
if script
|
|
661
|
+
if script:
|
|
657
662
|
msg += f" in script {script}, line {slno}"
|
|
658
663
|
from execsql.utils.errors import exit_now
|
|
659
664
|
|
|
@@ -178,6 +178,11 @@ def write_query_to_xlsx(
|
|
|
178
178
|
wb.save(outfile)
|
|
179
179
|
wb.close()
|
|
180
180
|
|
|
181
|
+
if _state.export_metadata is not None:
|
|
182
|
+
_state.export_metadata.add(
|
|
183
|
+
ExportRecord(queryname=select_stmt, outfile=outfile, zipfile=None, description=desc),
|
|
184
|
+
)
|
|
185
|
+
|
|
181
186
|
|
|
182
187
|
def write_queries_to_xlsx(
|
|
183
188
|
table_list: str,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from execsql.exceptions import ErrInfo
|
|
3
2
|
|
|
4
3
|
"""
|
|
5
4
|
Control-flow metacommand handlers for execsql.
|
|
@@ -18,6 +17,8 @@ Implements the imperative ``x_*`` functions for script flow control:
|
|
|
18
17
|
"""
|
|
19
18
|
|
|
20
19
|
import time
|
|
20
|
+
|
|
21
|
+
from execsql.exceptions import ErrInfo
|
|
21
22
|
from typing import Any
|
|
22
23
|
|
|
23
24
|
import execsql.state as _state
|
|
@@ -62,7 +63,8 @@ def x_assert(**kwargs: Any) -> None:
|
|
|
62
63
|
|
|
63
64
|
result = _state.xcmd_test(condition)
|
|
64
65
|
if result:
|
|
65
|
-
_state.exec_log
|
|
66
|
+
if _state.exec_log is not None:
|
|
67
|
+
_state.exec_log.log_user_msg(f"ASSERT passed: {condition}")
|
|
66
68
|
else:
|
|
67
69
|
raise ErrInfo(type="cmd", other_msg=message)
|
|
68
70
|
|
|
@@ -134,14 +136,6 @@ def x_loop(**kwargs: Any) -> None:
|
|
|
134
136
|
)
|
|
135
137
|
|
|
136
138
|
|
|
137
|
-
def endloop() -> None:
|
|
138
|
-
if len(_state.loopcommandstack) == 0:
|
|
139
|
-
raise ErrInfo("error", other_msg="END LOOP metacommand without a matching preceding LOOP metacommand.")
|
|
140
|
-
_state.compiling_loop = False
|
|
141
|
-
_state.commandliststack.append(_state.loopcommandstack[-1])
|
|
142
|
-
_state.loopcommandstack.pop()
|
|
143
|
-
|
|
144
|
-
|
|
145
139
|
def x_halt(**kwargs: Any) -> None:
|
|
146
140
|
errmsg = kwargs["errmsg"]
|
|
147
141
|
tee = kwargs["tee"]
|
|
@@ -74,7 +74,7 @@ def x_debug_log_subvars(**kwargs: Any) -> None:
|
|
|
74
74
|
local = kwargs["local"]
|
|
75
75
|
user = kwargs["user"]
|
|
76
76
|
for s in _state.commandliststack[-1].localvars.substitutions:
|
|
77
|
-
_state.exec_log.log_status_info(f"Substitution [{s}] = [{s}]")
|
|
77
|
+
_state.exec_log.log_status_info(f"Substitution [{s[0]}] = [{s[1]}]")
|
|
78
78
|
if local is None:
|
|
79
79
|
for s in _state.subvars.substitutions:
|
|
80
80
|
if user is None or s[0][0].isalnum() or s[0][0] == "_":
|