execsql2 2.8.0__tar.gz → 2.9.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.8.0 → execsql2-2.9.0}/.claude/project_context.md +66 -7
- {execsql2-2.8.0 → execsql2-2.9.0}/CHANGELOG.md +9 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/PKG-INFO +2 -1
- {execsql2-2.8.0 → execsql2-2.9.0}/README.md +1 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/about/divergence.md +2 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/getting-started/syntax.md +28 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/reference/configuration.md +11 -7
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/reference/metacommands.md +18 -11
- {execsql2-2.8.0 → execsql2-2.9.0}/pyproject.toml +2 -2
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/cli/__init__.py +25 -0
- execsql2-2.9.0/src/execsql/cli/lint.py +459 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/cli/run.py +101 -9
- execsql2-2.9.0/tests/cli/test_lint.py +473 -0
- execsql2-2.9.0/tests/cli/test_ping.py +315 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/uv.lock +1 -1
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/agents/dba.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/agents/herald.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/agents/inspector.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/agents/oracle.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/agents/patcher.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/agents/qa.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/agents/scribe.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/commands/code-oracle.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/commands/migrate.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/commands/review-changes.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/commands/test-module.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/commands/update-changelog.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/commands/where-is.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.claude/state/status.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.github/workflows/ci-cd.yml +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.gitignore +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.pre-commit-config.yaml +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.pre-commit-hooks.yaml +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.python-version +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/.readthedocs.yaml +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/CLAUDE.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/CONTRIBUTING.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/LICENSE.txt +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/NOTICE +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/SECURITY.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/about/contributors.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/about/copyright.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/api/cli.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/api/db.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/api/exporters.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/api/importers.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/api/index.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/api/metacommands.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/dev/adding_db_adapters.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/dev/adding_exporters.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/dev/adding_importers.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/dev/adding_metacommands.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/dev/architecture.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/getting-started/installation.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/getting-started/requirements.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/guides/debugging.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/guides/documentation.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/guides/encoding.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/guides/examples.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/guides/formatter.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/guides/logging.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/guides/sql_syntax.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/guides/usage.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/guides/using_scripts.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/Compare_planets.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/actions.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/actions2.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/checkboxes.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/connect.b64 +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/connect.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/create_conf.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/data_error1_screenshot.jpg +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/entry_form.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/execsql_console.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/execsql_logo_01.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/fatals.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/logo_small.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/pause_terminal.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/pause_terminal_sm.b64 +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/pause_terminal_sm.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/prompt_compare.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/set_build_commands.jpg +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/unit_conversions.b64 +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/unit_conversions_029.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/unmatched.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/images/vim_execsql_highlight.png +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/index.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/reference/security.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/docs/reference/substitution_vars.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/extras/vscode-execsql/README.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/extras/vscode-execsql/package.json +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/justfile +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/scripts/generate_vscode_grammar.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/__main__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/cli/dsn.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/cli/help.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/config.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/constants.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/access.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/base.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/dsn.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/duckdb.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/factory.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/firebird.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/mysql.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/oracle.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/postgres.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/sqlite.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/db/sqlserver.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exceptions.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/base.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/delimited.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/duckdb.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/feather.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/html.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/json.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/latex.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/markdown.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/ods.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/parquet.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/pretty.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/protocol.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/raw.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/sqlite.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/templates.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/values.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/xls.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/xlsx.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/xml.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/yaml.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/exporters/zip.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/format.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/gui/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/gui/base.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/gui/console.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/gui/desktop.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/gui/tui.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/importers/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/importers/base.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/importers/csv.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/importers/feather.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/importers/ods.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/importers/xls.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/conditions.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/connect.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/control.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/data.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/debug.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/dispatch.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/io.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/io_export.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/io_fileops.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/io_import.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/io_write.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/prompt.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/script_ext.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/metacommands/system.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/models.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/parser.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/py.typed +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/script/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/script/control.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/script/engine.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/script/variables.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/state.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/types.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/auth.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/crypto.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/datetime.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/errors.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/fileio.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/gui.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/mail.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/numeric.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/regex.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/strings.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/src/execsql/utils/timer.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/README.md +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/config_settings.sqlite +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/example_config_prompt.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/execsql.conf +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/make_config_db.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/md_compare.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/md_glossary.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/md_upsert.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/pg_compare.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/pg_glossary.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/pg_upsert.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/script_template.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/ss_compare.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/ss_glossary.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/templates/ss_upsert.sql +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/cli/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/cli/test_cli.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/cli/test_cli_e2e.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/cli/test_cli_run.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/cli/test_profile.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/conftest.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/db/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/db/test_base.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/db/test_duckdb.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/db/test_factory.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/db/test_postgres.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/db/test_sqlite.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/db/test_sqlite_extra.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_base.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_db.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_delimited.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_duckdb_exporter.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_exporters.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_feather.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_html_latex.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_json.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_markdown.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_ods.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_parquet.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_sqlite_exporter.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_templates.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_xls_xlsx.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_xlsx.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_xml.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_yaml.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/exporters/test_zip.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/gui/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/gui/test_backends.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/importers/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/importers/test_csv_importer.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/importers/test_feather_importer.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/importers/test_ods_importer.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/importers/test_xls_importer.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/integration/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/integration/conftest.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/integration/test_dsn.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/integration/test_duckdb.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/integration/test_mysql.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/integration/test_postgres.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/integration/test_sqlite.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_assert.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_connect.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_metacommands.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_metacommands_connect.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_metacommands_data.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_metacommands_extended.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_metacommands_io.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_metacommands_script_ext.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_metacommands_system.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/metacommands/test_metacommands_system_extra.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_config.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_config_data.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_constants.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_engine.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_exceptions.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_format.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_mail.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_models.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_package.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_parser.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_registry.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_script.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_state.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/test_types.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/__init__.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_auth.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_auth_extra.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_crypto.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_datetime.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_errors.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_errors_extra.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_fileio.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_fileio_extra.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_numeric.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_regex.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_strings.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_timer.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/tests/utils/test_timer_extra.py +0 -0
- {execsql2-2.8.0 → execsql2-2.9.0}/zensical.toml +0 -0
|
@@ -275,28 +275,63 @@ ______________________________________________________________________
|
|
|
275
275
|
- [x] **`ASSERT` metacommand** — `-- !x! ASSERT <condition> "message"`. Reuses IF condition engine. 13 tests.
|
|
276
276
|
- [x] **`--dry-run` improvements** — expands substitution variables populated at parse time. 4 new tests.
|
|
277
277
|
- [x] **Script profiling (`--profile`)** — per-statement `perf_counter()` timing with sorted summary table. 19 tests.
|
|
278
|
-
-
|
|
278
|
+
- ~~**Parallel execution blocks**~~ — deferred to v3.0+. See design notes and deferral rationale below.
|
|
279
279
|
|
|
280
|
-
###
|
|
280
|
+
### Candidate Features (unscheduled — pick and assign to milestones)
|
|
281
281
|
|
|
282
|
-
|
|
282
|
+
#### Quick Wins
|
|
283
|
+
|
|
284
|
+
- [x] **`--ping`** — test database connectivity and exit with a status message. Useful for CI health checks and connection debugging. (shipped v2.8.x)
|
|
285
|
+
- ~~`SUB_FILE`~~ — redundant with existing `SUB_INI` metacommand which already loads variables from INI-format files.
|
|
286
|
+
- [ ] **`WRITE TABLE` metacommand** — pretty-print a query result to the console as a formatted table (like `psql` output). Quick debugging aid without needing a full EXPORT.
|
|
287
|
+
- [ ] **`--env` / `--config` flag** — load a specific config file by path instead of relying on the search hierarchy. `execsql --env prod.conf script.sql`.
|
|
288
|
+
|
|
289
|
+
#### Scripting & Reliability
|
|
290
|
+
|
|
291
|
+
- [ ] **`ON ERROR RETRY N`** — retry a failed SQL statement N times with exponential backoff. Handles transient network blips and lock timeouts in ETL scripts.
|
|
292
|
+
- [ ] **`DIFF` metacommand** — compare two query results non-interactively and write differences to a file or set `$DIFF_COUNT`. Unlike `PROMPT COMPARE` (which is GUI/interactive), DIFF is headless and scriptable — designed for CI pipelines, automated validation, and audit trails. Supports arbitrary queries, not just table names.
|
|
293
|
+
- [x] **Script linting (`--lint`)** — parse and report common issues without executing: unmatched IF/ENDIF, unmatched LOOP/END LOOP, undefined variable references, missing INCLUDE files. (shipped v2.8.x)
|
|
294
|
+
|
|
295
|
+
#### Persistent State (`~/.execsql/state.db`)
|
|
296
|
+
|
|
297
|
+
A central SQLite database at `~/.execsql/state.db` that tracks per-script
|
|
298
|
+
state across runs. Cross-platform via `Path.home()`. Created automatically
|
|
299
|
+
on first use. All features below depend on this infrastructure.
|
|
300
|
+
|
|
301
|
+
- [ ] **State DB infrastructure** — `StateDB` class, schema creation, `~/.execsql/` directory management. Foundation for everything below.
|
|
302
|
+
- [ ] **Run numbering (`$RUN_NUMBER`, `$LAST_RUN_TIME`, `$FIRST_RUN_TIME`)** — persistent per-script run counter and timestamps. Always-on, incremented each invocation. `--reset-run-number` CLI flag to reset. Useful for audit trails, incremental file naming (`output_!!$RUN_NUMBER!!.csv`), conditional first-run logic.
|
|
303
|
+
- [ ] **Resumable scripts (`--checkpoint`)** — checkpoint after each statement. Auto-resumes on next `--checkpoint` run if checkpoint exists and script hash matches. Saves position, variables, and DB alias. Deletes checkpoint on successful completion.
|
|
304
|
+
- [ ] **Run history (`--history`)** — log each run (start time, duration, exit status, commands run, script path) to a `run_history` table. `execsql --history script.sql` shows past runs. Useful for auditing and debugging intermittent failures.
|
|
305
|
+
- [ ] **Persistent variables (`PERSIST` / `RECALL`)** — save substitution variables across runs. `-- !x! PERSIST $last_watermark` saves to state DB; next run `-- !x! RECALL $last_watermark` restores it. Enables incremental ETL (remember the last-processed timestamp/ID without external bookkeeping).
|
|
306
|
+
- [ ] **Script scheduling metadata** — store cron-like schedule info per script. `execsql --schedule "0 2 * * *" script.sql` records intent. `execsql --list-schedules` shows all. Doesn't execute (that's cron/Task Scheduler's job) — just a registry so you can answer "what runs when?" from one place.
|
|
307
|
+
|
|
308
|
+
#### Notifications & Integrations
|
|
309
|
+
|
|
310
|
+
- [ ] **Webhook notifications** — `ON ERROR_HALT WEBHOOK "https://..."` and `ON COMPLETE WEBHOOK "https://..."`. Like the existing `ON ERROR_HALT EMAIL` but for Slack/Teams/PagerDuty. More relevant than email in 2026.
|
|
311
|
+
- [ ] **HTTP/REST export** — `EXPORT QUERY ... TO POST "https://api.example.com/data" AS JSON`. POST query results directly to a webhook or API endpoint.
|
|
312
|
+
|
|
313
|
+
#### Developer Experience
|
|
314
|
+
|
|
315
|
+
- [ ] **Programmatic Python API** — `execsql.run(script, db=...)` for notebook/pipeline usage. Each call gets its own isolated `RuntimeContext`.
|
|
283
316
|
- [ ] **TOML configuration** — `execsql.toml` as modern alternative to legacy INI format (coexist initially).
|
|
317
|
+
- [ ] **Colorized SQL in console output** — syntax-highlight SQL statements in WRITE, dry-run, and error output via Rich/Pygments.
|
|
284
318
|
|
|
285
|
-
|
|
319
|
+
#### Testing & CI Hardening
|
|
286
320
|
|
|
287
321
|
- [ ] **Property-based testing (Hypothesis)** — for parsers, type inference, substitution variables.
|
|
288
322
|
- [ ] **Parser fuzzing** — `CondParser` and `NumericParser` handle arbitrary user input; fuzz for edge cases.
|
|
289
323
|
- [ ] **Nightly CI against latest DB driver versions** — catch upstream breakage in psycopg2, pymysql, duckdb, etc.
|
|
290
324
|
- [ ] **CI benchmarks** — track substitution variable and dispatch performance over time.
|
|
291
325
|
|
|
292
|
-
|
|
326
|
+
#### Documentation & Community
|
|
293
327
|
|
|
294
|
-
- [ ] **Cookbook / recipes page** — real-world examples: ETL workflows, HTML reports, data validation pipelines.
|
|
328
|
+
- [ ] **Cookbook / recipes page** — real-world examples: ETL workflows, HTML reports, data validation pipelines, CI integration.
|
|
295
329
|
- [ ] **Migration guide from upstream execsql** — what changed, what's new, how to switch.
|
|
296
330
|
- [ ] **Interactive tutorial** — guided walkthrough script against a bundled SQLite DB.
|
|
297
331
|
|
|
298
|
-
|
|
332
|
+
#### v3.0+ — Major Features
|
|
299
333
|
|
|
334
|
+
- [ ] **Parallel execution blocks** — `PARALLEL BEGIN ... PARALLEL END` for independent statements. See design notes and deferral rationale below.
|
|
300
335
|
- [ ] **Plugin system** — entry points for `execsql.exporters`, `execsql.importers`, `execsql.metacommands` allowing external packages to register new handlers.
|
|
301
336
|
- [ ] **LSP / language server** — for the VS Code extension: autocomplete metacommands, validate substitution variables, jump-to-definition for `INCLUDE`d scripts.
|
|
302
337
|
|
|
@@ -367,6 +402,30 @@ INSERT INTO summary_c SELECT ... FROM raw_data;
|
|
|
367
402
|
block — but that negates parallelism for most backends, so this is
|
|
368
403
|
mainly useful for independent ETL loads.
|
|
369
404
|
|
|
405
|
+
**Deferral rationale (2026-04):** Moved from v2.8 to v3.0+. The
|
|
406
|
+
complexity-to-value ratio is poor for the current user base:
|
|
407
|
+
|
|
408
|
+
1. **Connection pooling does not exist.** `DatabasePool` holds one
|
|
409
|
+
connection per alias. Workers need their own connections, requiring
|
|
410
|
+
either a pool-per-alias model or fresh connections from the DSN —
|
|
411
|
+
significant infrastructure work.
|
|
412
|
+
2. **Global state is not thread-safe.** Even with `RuntimeContext`, the
|
|
413
|
+
context is shared. Workers writing `$LAST_ROWCOUNT` or reading
|
|
414
|
+
`_state.subvars` would race. Per-worker read-only snapshots are needed.
|
|
415
|
+
3. **Error semantics are complex.** Partial failure (2 of 4 workers fail)
|
|
416
|
+
requires decisions about cancellation, rollback, and error aggregation.
|
|
417
|
+
4. **Narrow real-world benefit.** Most execsql users target a single DBMS.
|
|
418
|
+
Databases like PostgreSQL already parallelize queries internally.
|
|
419
|
+
Running concurrent INSERTTs against the same server often doesn't help
|
|
420
|
+
because they compete for locks, I/O, and CPU.
|
|
421
|
+
5. **Better alternatives exist for orchestration.** Users with true
|
|
422
|
+
parallelism needs are better served by calling `execsql.run()` (v2.9
|
|
423
|
+
library API) from their own threading/async code, or by tools like
|
|
424
|
+
Airflow/dbt.
|
|
425
|
+
|
|
426
|
+
Revisit if the library API (v2.9) reveals demand for in-script
|
|
427
|
+
parallelism that can't be met by external orchestration.
|
|
428
|
+
|
|
370
429
|
______________________________________________________________________
|
|
371
430
|
|
|
372
431
|
## Open Design Questions
|
|
@@ -13,6 +13,15 @@ ______________________________________________________________________
|
|
|
13
13
|
|
|
14
14
|
______________________________________________________________________
|
|
15
15
|
|
|
16
|
+
## [2.9.0] - 2026-04-01
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **`--lint` flag** — parse a script and perform static analysis without connecting to a database or executing anything. Reports unmatched `IF`/`ENDIF`, `LOOP`/`END LOOP`, and `BEGIN BATCH`/`END BATCH` blocks as errors; potentially undefined `!!$VAR!!` variable references and missing `INCLUDE` file targets as warnings. Exits 0 if no errors are found (warnings alone do not affect the exit code); exits 1 if any errors are found. Works with both file scripts and inline `-c` scripts.
|
|
21
|
+
- **`--ping` flag** — test database connectivity without running a script. `execsql --ping --dsn <URL>` connects to the database, queries the server version, prints a one-line success summary (DBMS name, version, and location), and exits 0. On failure it prints the error and exits 1. No script file argument is required when `--ping` is used.
|
|
22
|
+
|
|
23
|
+
______________________________________________________________________
|
|
24
|
+
|
|
16
25
|
## [2.8.0] - 2026-04-01
|
|
17
26
|
|
|
18
27
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.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: Repository, https://github.com/geocoug/execsql
|
|
6
6
|
Project-URL: Issues, https://github.com/geocoug/execsql/issues
|
|
@@ -221,6 +221,7 @@ execsql script.sql # read connection from config file
|
|
|
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
223
|
| `--dry-run` | Parse the script and report commands without executing |
|
|
224
|
+
| `--lint` | Static analysis: check structure and warn on issues (no DB) |
|
|
224
225
|
| `--progress` | Show a progress bar for long-running IMPORT operations |
|
|
225
226
|
| `--dump-keywords` | Print metacommand keywords as JSON and exit |
|
|
226
227
|
| `--gui-framework {tkinter,textual}` | GUI framework for interactive prompts |
|
|
@@ -111,6 +111,7 @@ execsql script.sql # read connection from config file
|
|
|
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
113
|
| `--dry-run` | Parse the script and report commands without executing |
|
|
114
|
+
| `--lint` | Static analysis: check structure and warn on issues (no DB) |
|
|
114
115
|
| `--progress` | Show a progress bar for long-running IMPORT operations |
|
|
115
116
|
| `--dump-keywords` | Print metacommand keywords as JSON and exit |
|
|
116
117
|
| `--gui-framework {tkinter,textual}` | GUI framework for interactive prompts |
|
|
@@ -24,6 +24,8 @@ ______________________________________________________________________
|
|
|
24
24
|
| `--gui-framework` | Select GUI backend: `tkinter` (default) or `textual` (terminal UI). |
|
|
25
25
|
| `--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
26
|
| `--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
|
+
| `--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. |
|
|
28
|
+
| `--lint` | Parse the script and perform static analysis without connecting to a database. Reports unmatched IF/ENDIF, LOOP/END LOOP, and BEGIN BATCH/END BATCH blocks (errors), potentially undefined `!!$VAR!!` references (warnings), and missing INCLUDE file targets (warnings). Exits 0 if no errors, 1 if errors found. |
|
|
27
29
|
|
|
28
30
|
### Export Formats
|
|
29
31
|
|
|
@@ -196,6 +196,34 @@ Valid encoding names can be displayed with the `-y` option. See also [Character
|
|
|
196
196
|
|
|
197
197
|
Substitution variables that are already populated at parse time are expanded in the output: environment variables (`!!&ENV_VAR!!`), `--assign-arg` values (`!!$ARG_1!!`), and built-in start-time variables like `!!$SCRIPT_START_TIME!!` and `!!$USER!!`. Variables that are set during execution — such as `$CURRENT_TIME`, `$DB_NAME`, and `$TIMER` — remain unexpanded because no database connection is established in dry-run mode. Local `~`-prefixed script-scope variables are also left unexpanded.
|
|
198
198
|
|
|
199
|
+
`--lint`
|
|
200
|
+
|
|
201
|
+
: Parse the script and perform static analysis without connecting to a database or executing anything. A complement to `--dry-run` focused on structural correctness rather than command display.
|
|
202
|
+
|
|
203
|
+
Checks performed:
|
|
204
|
+
|
|
205
|
+
- **Unmatched IF / ENDIF** — open IF blocks with no closing ENDIF, or orphan ENDIF with no IF (error).
|
|
206
|
+
- **Unmatched LOOP / END LOOP** — open LOOP with no END LOOP, or orphan END LOOP (error).
|
|
207
|
+
- **Unmatched BEGIN BATCH / END BATCH** — open batch with no close, or orphan END BATCH (error).
|
|
208
|
+
- **Potentially undefined variables** — `!!$VAR!!` references where `$VAR` is not a built-in variable, not `$ARG_N`, and was not defined by a preceding `SUB` metacommand in the same script (warning — may be a false-positive if the variable is set in a config file or via `-a`).
|
|
209
|
+
- **Missing INCLUDE files** — `INCLUDE` targets that do not exist on disk relative to the script's directory (warning; `INCLUDE IF EXISTS` targets are never checked).
|
|
210
|
+
- **Empty script** — no commands found (warning).
|
|
211
|
+
|
|
212
|
+
Exits 0 when no errors are found (warnings alone do not affect the exit code). Exits 1 when any errors are found.
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
execsql --lint script.sql
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`--ping`
|
|
219
|
+
|
|
220
|
+
: Test database connectivity and exit. Connects to the configured database, queries the server version if possible, and prints a one-line summary on success (exit 0). On failure, prints the error message and exits with code 1. No script file is required — `--ping` can be combined with `--dsn` or other connection flags without specifying a `.sql` file.
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
execsql --ping --dsn postgresql://user:pass@host/db
|
|
224
|
+
execsql --ping --dsn sqlite:///mydb.sqlite
|
|
225
|
+
```
|
|
226
|
+
|
|
199
227
|
`--profile`
|
|
200
228
|
|
|
201
229
|
: 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.
|
|
@@ -28,7 +28,7 @@ The section and property names that may be used in a configuration file are list
|
|
|
28
28
|
: The database server name. This is equivalent to the second command-line argument for client-server databases.
|
|
29
29
|
|
|
30
30
|
`db`
|
|
31
|
-
: The database name. This is equivalent to the third command-line argument for client-server databases
|
|
31
|
+
: The database name. This is equivalent to the third command-line argument for client-server databases. The alias `database` is also accepted.
|
|
32
32
|
|
|
33
33
|
`db_file`
|
|
34
34
|
: The name of the database file. This is equivalent to the second command-line argument for file-based databases.
|
|
@@ -132,9 +132,9 @@ The section and property names that may be used in a configuration file are list
|
|
|
132
132
|
|
|
133
133
|
: Controls how often row-count progress is written to the execution log during IMPORT operations. Set to a positive integer N to log a status line every N rows (e.g. `import_progress_interval = 10000`). The default is `0` (silent). When enabled, a final completion line (e.g. "IMPORT into schema.table complete: 1000000 rows imported.") is also written. Supported for all database adapters.
|
|
134
134
|
|
|
135
|
-
`
|
|
135
|
+
`import_common_columns_only` { #import_only_common }
|
|
136
136
|
|
|
137
|
-
: Determines whether the [IMPORT](metacommands.md#import) metacommand will import data from a CSV file when the file has more data columns than the target table. The property value should be either "Yes" or "No". The default, "No", indicates that the target table must have all of the columns present in the CSV file; if the target table has fewer columns, an error will result. A property value of "Yes" will result in import of only the columns in common between the CSV file and the target table.
|
|
137
|
+
: Determines whether the [IMPORT](metacommands.md#import) metacommand will import data from a CSV file when the file has more data columns than the target table. The property value should be either "Yes" or "No". The default, "No", indicates that the target table must have all of the columns present in the CSV file; if the target table has fewer columns, an error will result. A property value of "Yes" will result in import of only the columns in common between the CSV file and the target table. The legacy alias `import_only_common_columns` is also accepted.
|
|
138
138
|
|
|
139
139
|
`import_row_buffer`
|
|
140
140
|
|
|
@@ -171,7 +171,7 @@ The section and property names that may be used in a configuration file are list
|
|
|
171
171
|
## Section `output` { #config_output }
|
|
172
172
|
|
|
173
173
|
`log_write_messages`
|
|
174
|
-
: Specifies whether output of the [WRITE](metacommands.md#write) metacommand will also be written to *execsql*'s log file. The property value should be either "Yes" or "No". This configuration property can also be controlled within a script with the [CONFIG LOG_WRITE_MESSAGES](metacommands.md#logwritemessages) metacommand.
|
|
174
|
+
: Specifies whether output of the [WRITE](metacommands.md#write) metacommand will also be written to *execsql*'s log file. The property value should be either "Yes" or "No". The default is "No". This configuration property can also be controlled within a script with the [CONFIG LOG_WRITE_MESSAGES](metacommands.md#logwritemessages) metacommand.
|
|
175
175
|
|
|
176
176
|
`make_export_dirs`
|
|
177
177
|
: The output directories used in the [EXPORT](metacommands.md#export) and [WRITE](metacommands.md#write) metacommands will be automatically created if they do not exist (and the user has the necessary permission). The property value should be either "Yes" or "No". This is equivalent to the "-d" command-line option.
|
|
@@ -186,12 +186,12 @@ The section and property names that may be used in a configuration file are list
|
|
|
186
186
|
: The number of data rows to be buffered from the database when exporting data. Larger values result in faster exports, up to a point, and at a diminishing rate of return. Larger values also require more memory. The setting value must be a positive integer greater than zero. The default value is 1000 rows. This value cannot be customized when using DuckDB.
|
|
187
187
|
|
|
188
188
|
`hdf5_text_len`
|
|
189
|
-
: The length to be assigned to columns that have the 'text' data type when data are exported in the HDF5 format.
|
|
189
|
+
: The length to be assigned to columns that have the 'text' data type when data are exported in the HDF5 format. The default is `1000`.
|
|
190
190
|
|
|
191
191
|
`css_file`
|
|
192
192
|
: The URI of a CSS file to be included in the header of an HTML file created with the [EXPORT](metacommands.md#export) metacommand. If this is specified, it will replace the CSS styles that *execsql* would otherwise use.
|
|
193
193
|
|
|
194
|
-
`
|
|
194
|
+
`css_styles`
|
|
195
195
|
: A set of CSS style specifications to be included in the header of an HTML file created with the [EXPORT](metacommands.md#export) metacommand. If this is specified, it will replace the CSS styles that *execsql* would otherwise use. Both css_file and css_style may be specified; if they are, they will be included in the header of the HTML file in that order.
|
|
196
196
|
|
|
197
197
|
`template_processor`
|
|
@@ -240,6 +240,10 @@ The section and property names that may be used in a configuration file are list
|
|
|
240
240
|
- 2: Also use a GUI dialog if a message is included with the [HALT](metacommands.md#halt) metacommand, and prompt for the initial database to use if no database connection parameters are specified in a configuration file or on the command line.
|
|
241
241
|
- 3: Additionally, open a GUI console when *execsql* starts.
|
|
242
242
|
|
|
243
|
+
`gui_framework` { #gui_framework }
|
|
244
|
+
|
|
245
|
+
: The GUI framework to use when `gui_level` is greater than 0. The property value must be either `tkinter` (the default) or `textual`. `tkinter` uses native desktop dialogs via Tk; `textual` provides a terminal-based UI that works in headless/SSH environments. This can also be set via the `--gui-framework` command-line option.
|
|
246
|
+
|
|
243
247
|
## Section `email`
|
|
244
248
|
|
|
245
249
|
`host`
|
|
@@ -305,7 +309,7 @@ The section and property names that may be used in a configuration file are list
|
|
|
305
309
|
: The full name or path to an additional configuration file to be read. If only a path is specified, the name of the configuration file should be `execsql.conf`. The configuration file specified will be read immediately following the configuration file in which it is named. No configuration file will be read more than once. If the name or path are invalid, this setting will be silently ignored. This setting may include [substitution variables](substitution_vars.md#substitution_vars); at the time that configuration files are read, however, only environment variables and system variables related to the script name and path are defined.
|
|
306
310
|
|
|
307
311
|
`dao_flush_delay_secs`
|
|
308
|
-
: The number of seconds that *execsql* should wait between the time that a query is created in Access (which uses DAO) and the time that the next statement is executed using ODBC. This value must be greater than or equal to 5.0.
|
|
312
|
+
: The number of seconds that *execsql* should wait between the time that a query is created in Access (which uses DAO) and the time that the next statement is executed using ODBC. This value must be greater than or equal to 5.0. The default is `5.0`.
|
|
309
313
|
|
|
310
314
|
`linux_config_file`
|
|
311
315
|
: The full name or path to an additional configuration file to be read if *execsql* is running on Linux. If only a path is specified, the name of the configuration file should be `execsql.conf`. The configuration file specified will be read immediately following the configuration file in which it is named. No configuration file will be read more than once. If the name or path are invalid, this setting will be silently ignored. This setting may include [substitution variables](substitution_vars.md#substitution_vars); at the time that configuration files are read, however, only environment variables and system variables related to the script name and path are defined.
|
|
@@ -60,14 +60,17 @@ Evaluates `<condition>` using the same expression engine as [IF](#if_cmd). If th
|
|
|
60
60
|
|
|
61
61
|
When [HALT_ON_METACOMMAND_ERROR](#config) is `ON` (the default), a failed assertion halts the script. When it is `OFF`, execution continues after the failure is logged.
|
|
62
62
|
|
|
63
|
-
The `<condition>` supports all conditional tests available to `IF`, including:
|
|
63
|
+
The `<condition>` supports all [conditional tests](metacommands.md#conditional_tests) available to `IF`, including:
|
|
64
64
|
|
|
65
|
-
- `TABLE_EXISTS
|
|
66
|
-
- `COLUMN_EXISTS
|
|
67
|
-
- `
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
- `
|
|
65
|
+
- `TABLE_EXISTS(<table>)` / `NOT TABLE_EXISTS(<table>)`
|
|
66
|
+
- `COLUMN_EXISTS(<table>, <column>)` / `NOT COLUMN_EXISTS(<table>, <column>)`
|
|
67
|
+
- `HAS_ROWS(<table>)` / `NOT HAS_ROWS(<table>)`
|
|
68
|
+
- `EQUAL(<val1>, <val2>)` / `NOT EQUAL(<val1>, <val2>)`
|
|
69
|
+
- `IS_GT(<val1>, <val2>)`, `IS_GTE(<val1>, <val2>)`, `IS_ZERO(<val>)`
|
|
70
|
+
- `DBMS(<type>)`, `SCHEMA_EXISTS(<schema>)`, `VIEW_EXISTS(<view>)`
|
|
71
|
+
- Boolean combinators: `AND`, `OR`, `NOT`
|
|
72
|
+
|
|
73
|
+
Substitution variables in the condition are expanded before evaluation. Use the `!!varname!!` syntax (e.g., `!!$myvar!!`).
|
|
71
74
|
|
|
72
75
|
ASSERT is silently skipped inside a `False` [IF](#if_cmd) block.
|
|
73
76
|
|
|
@@ -75,13 +78,17 @@ ASSERT is silently skipped inside a `False` [IF](#if_cmd) block.
|
|
|
75
78
|
|
|
76
79
|
```sql
|
|
77
80
|
-- Halt with a custom message if the staging table is missing.
|
|
78
|
-
-- !x! ASSERT TABLE_EXISTS
|
|
81
|
+
-- !x! ASSERT TABLE_EXISTS(staging) "staging table must exist before running this script"
|
|
79
82
|
|
|
80
|
-
-- Halt with the default message if no rows
|
|
81
|
-
-- !x! ASSERT
|
|
83
|
+
-- Halt with the default message if the table has no rows.
|
|
84
|
+
-- !x! ASSERT HAS_ROWS(staging)
|
|
82
85
|
|
|
83
86
|
-- Verify a substitution variable has the expected value.
|
|
84
|
-
-- !x!
|
|
87
|
+
-- !x! SUB env prod
|
|
88
|
+
-- !x! ASSERT EQUAL(!!env!!, prod) 'expected production environment'
|
|
89
|
+
|
|
90
|
+
-- Combine conditions with AND/OR/NOT.
|
|
91
|
+
-- !x! ASSERT TABLE_EXISTS(orders) AND HAS_ROWS(orders) "orders table missing or empty"
|
|
85
92
|
```
|
|
86
93
|
|
|
87
94
|
## AUTOCOMMIT
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "execsql2"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.9.0"
|
|
8
8
|
description = "Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = { file = "LICENSE.txt" }
|
|
@@ -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.9.0"
|
|
162
162
|
commit = true
|
|
163
163
|
commit_args = "--no-verify"
|
|
164
164
|
tag = true
|
|
@@ -223,6 +223,25 @@ def main(
|
|
|
223
223
|
"--dry-run",
|
|
224
224
|
help=("Parse the script and print the command list without connecting to a database or executing anything."),
|
|
225
225
|
),
|
|
226
|
+
lint: bool = typer.Option(
|
|
227
|
+
False,
|
|
228
|
+
"--lint",
|
|
229
|
+
help=(
|
|
230
|
+
"Parse the script and perform static analysis without connecting to a database or executing anything. "
|
|
231
|
+
"Reports unmatched IF/ENDIF/LOOP/BATCH blocks (errors), potentially undefined variables, "
|
|
232
|
+
"and missing INCLUDE files (warnings). Exits 0 if no errors, 1 if errors found."
|
|
233
|
+
),
|
|
234
|
+
),
|
|
235
|
+
ping: bool = typer.Option(
|
|
236
|
+
False,
|
|
237
|
+
"--ping",
|
|
238
|
+
help=(
|
|
239
|
+
"Test database connectivity and exit. "
|
|
240
|
+
"Prints connection details and the server version on success (exit 0), "
|
|
241
|
+
"or the error message on failure (exit 1). "
|
|
242
|
+
"No script file is required."
|
|
243
|
+
),
|
|
244
|
+
),
|
|
226
245
|
dsn: str | None = typer.Option(
|
|
227
246
|
None,
|
|
228
247
|
"--dsn",
|
|
@@ -350,6 +369,10 @@ def main(
|
|
|
350
369
|
positional = args or []
|
|
351
370
|
if command is not None:
|
|
352
371
|
script_name = None # inline mode — no script file
|
|
372
|
+
elif ping:
|
|
373
|
+
# --ping does not require a script file; positional args are still
|
|
374
|
+
# available for server/db arguments if --dsn is not used.
|
|
375
|
+
script_name = None
|
|
353
376
|
else:
|
|
354
377
|
if not positional:
|
|
355
378
|
_err_console.print(
|
|
@@ -421,6 +444,8 @@ def main(
|
|
|
421
444
|
output_dir=output_dir,
|
|
422
445
|
progress=progress,
|
|
423
446
|
profile=profile,
|
|
447
|
+
ping=ping,
|
|
448
|
+
lint=lint,
|
|
424
449
|
)
|
|
425
450
|
|
|
426
451
|
|