execsql2 2.16.7__tar.gz → 2.16.12__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.16.7 → execsql2-2.16.12}/CHANGELOG.md +36 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/PKG-INFO +1 -1
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/about/divergence.md +28 -11
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/reference/metacommands.md +111 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +1 -1
- {execsql2-2.16.7 → execsql2-2.16.12}/pyproject.toml +3 -3
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/debug/repl.py +59 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/format.py +2 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/debug.py +89 -1
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/dispatch.py +18 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/script/ast.py +43 -6
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/script/executor.py +28 -13
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/script/parser.py +175 -26
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/fileio.py +9 -1
- execsql2-2.16.12/tests/metacommands/test_show_scripts.py +154 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_ast.py +26 -3
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_ast_parser.py +75 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_executor.py +358 -0
- execsql2-2.16.12/tests/test_parser_params.py +56 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/uv.lock +1 -1
- {execsql2-2.16.7 → execsql2-2.16.12}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/.github/workflows/ci-cd.yml +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/.gitignore +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/.pre-commit-config.yaml +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/.pre-commit-hooks.yaml +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/.python-version +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/.readthedocs.yaml +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/CONTRIBUTING.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/LICENSE.txt +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/NOTICE +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/README.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/SECURITY.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/about/contributors.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/about/copyright.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/api/cli.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/api/db.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/api/exporters.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/api/importers.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/api/index.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/api/metacommands.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/dev/adding_db_adapters.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/dev/adding_exporters.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/dev/adding_importers.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/dev/adding_metacommands.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/dev/architecture.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/getting-started/installation.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/getting-started/requirements.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/getting-started/syntax.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/guides/debugging.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/guides/documentation.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/guides/encoding.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/guides/examples.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/guides/formatter.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/guides/logging.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/guides/sql_syntax.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/guides/usage.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/guides/using_scripts.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/Compare_planets.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/actions.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/actions2.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/checkboxes.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/connect.b64 +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/connect.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/create_conf.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/data_error1_screenshot.jpg +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/entry_form.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/execsql_console.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/execsql_logo_01.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/fatals.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/logo_small.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/pause_terminal.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/pause_terminal_sm.b64 +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/pause_terminal_sm.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/prompt_compare.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/set_build_commands.jpg +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/unit_conversions.b64 +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/unit_conversions_029.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/unmatched.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/images/vim_execsql_highlight.png +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/index.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/reference/configuration.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/reference/security.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/docs/reference/substitution_vars.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/extras/plugin-template/README.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/extras/plugin-template/pyproject.toml +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/extras/plugin-template/tests/test_plugin.py.example +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/extras/vscode-execsql/README.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/extras/vscode-execsql/package.json +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/justfile +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/scripts/generate_vscode_grammar.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/__main__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/api.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/cli/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/cli/dsn.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/cli/help.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/cli/lint.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/cli/lint_ast.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/cli/run.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/config.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/access.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/base.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/dsn.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/duckdb.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/factory.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/firebird.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/mysql.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/oracle.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/postgres.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/sqlite.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/db/sqlserver.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/debug/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exceptions.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/base.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/delimited.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/duckdb.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/feather.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/html.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/json.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/latex.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/markdown.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/ods.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/parquet.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/pretty.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/protocol.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/raw.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/sqlite.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/templates.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/values.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/xls.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/xlsx.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/xml.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/yaml.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/exporters/zip.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/gui/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/gui/base.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/gui/console.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/gui/desktop.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/gui/tui.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/importers/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/importers/base.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/importers/csv.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/importers/feather.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/importers/json.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/importers/ods.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/importers/xls.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/conditions.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/connect.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/control.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/data.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/io.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/io_export.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/io_fileops.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/io_import.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/io_write.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/prompt.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/script_ext.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/system.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/metacommands/upsert.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/models.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/parser.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/plugins.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/py.typed +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/script/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/script/control.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/script/engine.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/script/variables.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/state.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/types.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/auth.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/crypto.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/datetime.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/errors.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/gui.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/mail.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/numeric.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/regex.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/strings.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/src/execsql/utils/timer.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/README.md +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/config_settings.sqlite +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/example_config_prompt.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/execsql.conf +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/make_config_db.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/md_compare.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/md_glossary.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/md_upsert.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/pg_compare.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/pg_glossary.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/pg_upsert.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/script_template.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/ss_compare.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/ss_glossary.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/templates/ss_upsert.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/cli/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/cli/test_cli.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/cli/test_cli_e2e.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/cli/test_cli_run.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/cli/test_lint.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/cli/test_ping.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/cli/test_profile.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/conftest.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/db/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/db/test_base.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/db/test_db_adapters_mocked.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/db/test_dsn.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/db/test_duckdb.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/db/test_factory.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/db/test_postgres.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/db/test_sqlite.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/db/test_sqlite_extra.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_base.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_db.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_delimited.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_duckdb_exporter.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_exporters.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_feather.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_html_extended.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_html_latex.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_json.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_json_extended.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_latex_extended.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_markdown.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_ods.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_parquet.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_pretty_extended.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_raw_extended.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_sqlite_exporter.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_templates.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_templates_extended.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_values_extended.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_xls_xlsx.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_xlsx.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_xml.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_yaml.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/exporters/test_zip.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/gui/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/gui/test_backends.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/gui/test_compare_stats.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/gui/test_compute_row_diffs.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/importers/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/importers/test_base_extended.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/importers/test_csv_edge_cases.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/importers/test_csv_importer.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/importers/test_feather_importer.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/importers/test_json_importer.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/importers/test_ods_importer.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/importers/test_xls_importer.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/integration/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/integration/conftest.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/integration/test_dsn.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/integration/test_duckdb.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/integration/test_mysql.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/integration/test_postgres.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/integration/test_sqlite.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_assert.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_breakpoint.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_connect.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_io_export.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_io_import.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_metacommands.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_metacommands_connect.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_metacommands_data.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_metacommands_extended.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_metacommands_io.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_metacommands_script_ext.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_metacommands_system.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_metacommands_system_extra.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_pg_upsert.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/metacommands/test_row_count.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/scripts/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/scripts/fixtures/control_flow.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/scripts/fixtures/parse_only/parse_tree.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/scripts/fixtures/smoke.sql +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/scripts/test_sql_scripts.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_api.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_config.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_config_data.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_config_extended.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_debug_repl.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_engine.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_error_messages.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_exceptions.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_format.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_mail.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_models.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_package.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_parser.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_plugins.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_registry.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_script.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_state.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/test_types.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/__init__.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_auth.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_auth_extra.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_crypto.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_datetime.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_errors.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_errors_extra.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_fileio.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_fileio_extra.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_numeric.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_regex.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_strings.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_timer.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/tests/utils/test_timer_extra.py +0 -0
- {execsql2-2.16.7 → execsql2-2.16.12}/zensical.toml +0 -0
|
@@ -13,6 +13,42 @@ ______________________________________________________________________
|
|
|
13
13
|
|
|
14
14
|
______________________________________________________________________
|
|
15
15
|
|
|
16
|
+
## [2.16.12] - 2026-05-01
|
|
17
|
+
|
|
18
|
+
______________________________________________________________________
|
|
19
|
+
|
|
20
|
+
## [2.16.11] - 2026-05-01
|
|
21
|
+
|
|
22
|
+
______________________________________________________________________
|
|
23
|
+
|
|
24
|
+
## [2.16.10] - 2026-05-01
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- EXECUTE SCRIPT with a variable-substituted target name (e.g., `EXECUTE SCRIPT !!#script_name!!`) now works correctly. Previously, the parser's regex only accepted literal word characters as the script identifier, causing variable targets to fall through to the dispatch table and fail with "EXECUTE SCRIPT should be handled by the AST executor." The parser now recognizes `!!var!!` substitution patterns as valid script identifiers.
|
|
29
|
+
|
|
30
|
+
______________________________________________________________________
|
|
31
|
+
|
|
32
|
+
## [2.16.9] - 2026-05-01
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- `SHOW SCRIPTS` metacommand lists all registered SCRIPT definitions with parameter signatures and source locations.
|
|
37
|
+
- `SHOW SCRIPT <name>` metacommand shows detail for a single SCRIPT (parameters, source file and line range, docstring).
|
|
38
|
+
- `.scripts` REPL command lists all registered scripts; `.scripts <name>` shows detail for one script.
|
|
39
|
+
- Default parameter values for SCRIPT definitions: `BEGIN SCRIPT load(schema, table, batch=1000)`. Parameters with defaults can be omitted at call site; the default value is used automatically. Required parameters must precede optional parameters (like Python).
|
|
40
|
+
- Automatic docstring extraction for SCRIPT blocks. Comments (`--` or `/* */`) immediately following `BEGIN SCRIPT` are captured as documentation. A blank line terminates the docstring. Docstrings are displayed by `SHOW SCRIPT`, `SHOW SCRIPTS`, and `.scripts` in the debug REPL.
|
|
41
|
+
|
|
42
|
+
______________________________________________________________________
|
|
43
|
+
|
|
44
|
+
## [2.16.8] - 2026-04-30
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- SQL comments (`--` and `/* */`) inside multi-line SQL statements no longer split the statement. Previously, a comment like `-- col2,` between SELECT columns would cause the parser to flush the accumulated SQL at the comment line, sending an incomplete statement to the database. Comments inside SQL are now preserved as part of the statement text.
|
|
49
|
+
|
|
50
|
+
______________________________________________________________________
|
|
51
|
+
|
|
16
52
|
## [2.16.7] - 2026-04-30
|
|
17
53
|
|
|
18
54
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.16.
|
|
3
|
+
Version: 2.16.12
|
|
4
4
|
Summary: Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables.
|
|
5
5
|
Project-URL: Homepage, https://execsql2.readthedocs.io
|
|
6
6
|
Project-URL: Repository, https://github.com/geocoug/execsql
|
|
@@ -52,6 +52,21 @@ ______________________________________________________________________
|
|
|
52
52
|
| `CONFIG LOG_SQL` | Enable SQL query audit logging — writes executed SQL to the log file. |
|
|
53
53
|
| `PG_UPSERT` | QA-checked, FK-dependency-ordered upserts from staging to base schema on PostgreSQL. Integrates [pg-upsert](https://pg-upsert.readthedocs.io/) as an optional dependency. Three modes: full pipeline, QA-only, and schema check. Supports `EXPORT_FAILURES`, `EXPORT_FORMAT`, `EXPORT_MAX_ROWS`, and `STRICT_COLUMNS` keywords. `STRICT_COLUMNS` forces all missing columns to be errors (requires `pg-upsert>=1.22.0`). |
|
|
54
54
|
| `IMPORT … FROM JSON` | Import a JSON file (array of objects or NDJSON) into a database table. Nested objects are flattened with dot-separated column names; arrays are stored as JSON strings. |
|
|
55
|
+
| `SHOW SCRIPTS` | List all registered SCRIPT definitions with parameter signatures and source locations. Includes scripts from INCLUDEEd files. |
|
|
56
|
+
| `SHOW SCRIPT <name>` | Show detail for a single registered SCRIPT: name, parameters (with defaults), source file/line range, and docstring. |
|
|
57
|
+
|
|
58
|
+
### SCRIPT Enhancements
|
|
59
|
+
|
|
60
|
+
| Feature | Description |
|
|
61
|
+
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
62
|
+
| Default parameters | `BEGIN SCRIPT load(schema, table, batch=1000)` — parameters with defaults can be omitted at call site. Required parameters must precede optional parameters. |
|
|
63
|
+
| Docstrings | Comments (`--` or `/* */`) immediately following `BEGIN SCRIPT` are captured as documentation. A blank line terminates the docstring. Displayed by `SHOW SCRIPT`, `SHOW SCRIPTS`, and `.scripts` REPL command. |
|
|
64
|
+
|
|
65
|
+
### Bug Fixes
|
|
66
|
+
|
|
67
|
+
| Fix | Description |
|
|
68
|
+
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
69
|
+
| Variable EXECUTE SCRIPT targets | `EXECUTE SCRIPT !!#var!!` now works — the parser accepts substitution variable patterns as script identifiers, and the executor resolves them at runtime. |
|
|
55
70
|
|
|
56
71
|
### Conditional Tests
|
|
57
72
|
|
|
@@ -131,17 +146,19 @@ execsql2 adds a full interactive debugging system that has no equivalent in upst
|
|
|
131
146
|
|
|
132
147
|
**REPL commands** (all dot-prefixed to avoid collisions with variable names and SQL):
|
|
133
148
|
|
|
134
|
-
| Command | Description
|
|
135
|
-
| ---------------------- |
|
|
136
|
-
| `.continue` / `.c` | Resume normal script execution
|
|
137
|
-
| `.abort` / `.q` | Halt the script with exit status 1
|
|
138
|
-
| `.vars` / `.v` | List all user, system, local, and counter variables (grouped by type)
|
|
139
|
-
| `.vars all` / `.v all` | Include environment variables (`&`) in the listing
|
|
140
|
-
| `.next` / `.n` | Execute the next statement, then pause again (step mode)
|
|
141
|
-
| `.where` / `.w` | Show the current script file, line number, and upcoming statement text
|
|
142
|
-
| `.stack` | Show the command-list stack (script name, cursor position, nesting depth)
|
|
143
|
-
| `.set VAR VAL` / `.s` | Set or update a substitution variable; prints confirmation on success
|
|
144
|
-
| `.
|
|
149
|
+
| Command | Description |
|
|
150
|
+
| ---------------------- | --------------------------------------------------------------------------- |
|
|
151
|
+
| `.continue` / `.c` | Resume normal script execution |
|
|
152
|
+
| `.abort` / `.q` | Halt the script with exit status 1 |
|
|
153
|
+
| `.vars` / `.v` | List all user, system, local, and counter variables (grouped by type) |
|
|
154
|
+
| `.vars all` / `.v all` | Include environment variables (`&`) in the listing |
|
|
155
|
+
| `.next` / `.n` | Execute the next statement, then pause again (step mode) |
|
|
156
|
+
| `.where` / `.w` | Show the current script file, line number, and upcoming statement text |
|
|
157
|
+
| `.stack` | Show the command-list stack (script name, cursor position, nesting depth) |
|
|
158
|
+
| `.set VAR VAL` / `.s` | Set or update a substitution variable; prints confirmation on success |
|
|
159
|
+
| `.scripts` | List all registered SCRIPT definitions with parameters and source locations |
|
|
160
|
+
| `.scripts NAME` | Show detail for a specific SCRIPT (parameters, source file/line range) |
|
|
161
|
+
| `.help` / `.h` | Show available commands |
|
|
145
162
|
|
|
146
163
|
**Non-prefixed input** is interpreted as either a variable lookup or ad-hoc SQL:
|
|
147
164
|
|
|
@@ -141,6 +141,8 @@ All REPL commands are dot-prefixed to avoid ambiguity with variable names and SQ
|
|
|
141
141
|
| `.vars all` | Include environment variables (`&`) in the listing |
|
|
142
142
|
| `.next` or `.n` | Execute the next script statement, then pause again (step mode) |
|
|
143
143
|
| `.stack` | Show the command-list stack: script name, cursor index, and nesting depth |
|
|
144
|
+
| `.scripts` | List all registered SCRIPT definitions with parameters and source locations |
|
|
145
|
+
| `.scripts NAME` | Show detail for a specific SCRIPT (parameters, source file/line range) |
|
|
144
146
|
| `.help` | Show the list of available REPL commands |
|
|
145
147
|
|
|
146
148
|
**Variable inspection and SQL (no dot prefix):**
|
|
@@ -219,6 +221,10 @@ BEGIN SCRIPT <script_name>
|
|
|
219
221
|
BEGIN SCRIPT <script_name> WITH PARAMETERS (param1[, param2[,..]])
|
|
220
222
|
```
|
|
221
223
|
|
|
224
|
+
```
|
|
225
|
+
BEGIN SCRIPT <script_name>(param1, param2=default_value)
|
|
226
|
+
```
|
|
227
|
+
|
|
222
228
|
```
|
|
223
229
|
END SCRIPT [script_name]
|
|
224
230
|
```
|
|
@@ -232,6 +238,56 @@ If the WITH PARAMETERS clause is used, the parameter names specified must be ass
|
|
|
232
238
|
|
|
233
239
|
The "WITH" and "PARAMETERS" keywords are both optional.
|
|
234
240
|
|
|
241
|
+
### Default parameter values
|
|
242
|
+
|
|
243
|
+
Parameters can have default values using `param=value` syntax. Parameters with defaults are optional at the call site — if omitted, the default value is used. Required parameters (no default) must precede optional parameters.
|
|
244
|
+
|
|
245
|
+
```sql
|
|
246
|
+
-- !x! BEGIN SCRIPT load_data(schema, table, batch_size=1000, dry_run=false)
|
|
247
|
+
INSERT INTO !!#table!! SELECT * FROM staging LIMIT !!#batch_size!!;
|
|
248
|
+
-- !x! END SCRIPT
|
|
249
|
+
|
|
250
|
+
-- All of these are valid:
|
|
251
|
+
-- !x! EXECUTE SCRIPT load_data(schema=public, table=users)
|
|
252
|
+
-- !x! EXECUTE SCRIPT load_data(schema=public, table=users, batch_size=500)
|
|
253
|
+
-- !x! EXECUTE SCRIPT load_data(schema=public, table=users, batch_size=500, dry_run=true)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
A required parameter after an optional parameter is a parse error:
|
|
257
|
+
|
|
258
|
+
```sql
|
|
259
|
+
-- Parse error: required parameter 'table' after optional parameter 'batch'
|
|
260
|
+
-- !x! BEGIN SCRIPT bad(schema, batch=1000, table)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Docstrings
|
|
264
|
+
|
|
265
|
+
Comments (`--` or `/* */`) immediately following the BEGIN SCRIPT line are captured as the script's docstring. A blank line terminates the docstring. Docstrings are displayed by [SHOW SCRIPT](#show_script), [SHOW SCRIPTS](#show_scripts), and the `.scripts` REPL command.
|
|
266
|
+
|
|
267
|
+
```sql
|
|
268
|
+
-- !x! BEGIN SCRIPT load_data(schema, table)
|
|
269
|
+
-- Load data from staging into the target table.
|
|
270
|
+
-- Parameters:
|
|
271
|
+
-- schema - Target schema name
|
|
272
|
+
-- table - Target table name
|
|
273
|
+
|
|
274
|
+
-- !x! SUB ~batch 1000
|
|
275
|
+
INSERT INTO !!#table!! SELECT * FROM staging;
|
|
276
|
+
-- !x! END SCRIPT
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Block comments are also valid:
|
|
280
|
+
|
|
281
|
+
```sql
|
|
282
|
+
-- !x! BEGIN SCRIPT load_data(schema, table)
|
|
283
|
+
/* Load data from staging into the target table. */
|
|
284
|
+
|
|
285
|
+
INSERT INTO !!#table!! SELECT * FROM staging;
|
|
286
|
+
-- !x! END SCRIPT
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Other notes
|
|
290
|
+
|
|
235
291
|
If a script name is provided with the END SCRIPT metacommand, it must match the name used in the corresponding BEGIN SCRIPT metacommand. If it does not, *execsql* will halt with an error message.
|
|
236
292
|
|
|
237
293
|
A BEGIN/END SCRIPT block can be used in ways similar to a separate script file that is included with the [INCLUDE](#include) metacommand. Both allow the same code to be executed repeatedly, either at different locations in the main script or recursively to perform looping.
|
|
@@ -2697,6 +2753,61 @@ Assigns the value of the specified numeric expression to the counter. The next t
|
|
|
2697
2753
|
The numeric expression may consist of the simple algebraic operations of addition, subtraction, multiplication, and division. Parentheses may be used to control evaluation order. Numeric values used in the expression may be integers or floating-point numbers, but the result will be reduced to an integer before assignment to the counter variable.
|
|
2698
2754
|
|
|
2699
2755
|
|
|
2756
|
+
## SHOW SCRIPTS { #show_scripts }
|
|
2757
|
+
|
|
2758
|
+
```
|
|
2759
|
+
SHOW SCRIPTS
|
|
2760
|
+
```
|
|
2761
|
+
|
|
2762
|
+
Lists all registered SCRIPT definitions with their parameter signatures and source locations. This is useful for discovering what scripts are available at runtime, especially when scripts are loaded from INCLUDEEd files whose paths are determined dynamically.
|
|
2763
|
+
|
|
2764
|
+
**Example output:**
|
|
2765
|
+
|
|
2766
|
+
```
|
|
2767
|
+
Registered scripts (3):
|
|
2768
|
+
|
|
2769
|
+
load_data(schema, table, batch_size=1000) pipeline.sql:15-42
|
|
2770
|
+
cleanup() init.sql:10-25
|
|
2771
|
+
validate(schema, table) pipeline.sql:62-80
|
|
2772
|
+
```
|
|
2773
|
+
|
|
2774
|
+
Default parameter values are shown in the signature. Use `SHOW SCRIPT <name>` for full detail including docstrings.
|
|
2775
|
+
|
|
2776
|
+
If no scripts are registered, prints `No scripts registered.`
|
|
2777
|
+
|
|
2778
|
+
## SHOW SCRIPT { #show_script }
|
|
2779
|
+
|
|
2780
|
+
```
|
|
2781
|
+
SHOW SCRIPT <name>
|
|
2782
|
+
```
|
|
2783
|
+
|
|
2784
|
+
Shows detail for a single registered SCRIPT definition, including its parameter list (with required/optional status and defaults), source file/line range, and docstring.
|
|
2785
|
+
|
|
2786
|
+
**Example:**
|
|
2787
|
+
|
|
2788
|
+
```sql
|
|
2789
|
+
-- !x! SHOW SCRIPT load_data
|
|
2790
|
+
```
|
|
2791
|
+
|
|
2792
|
+
**Example output:**
|
|
2793
|
+
|
|
2794
|
+
```
|
|
2795
|
+
Script: load_data(schema, table, batch_size=1000)
|
|
2796
|
+
Source: pipeline.sql:15-42
|
|
2797
|
+
Parameters:
|
|
2798
|
+
schema (required)
|
|
2799
|
+
table (required)
|
|
2800
|
+
batch_size (optional, default: 1000)
|
|
2801
|
+
|
|
2802
|
+
Load data from staging into the target table.
|
|
2803
|
+
```
|
|
2804
|
+
|
|
2805
|
+
If the script is not found, prints `No script named '<name>' is registered.`
|
|
2806
|
+
|
|
2807
|
+
!!! tip
|
|
2808
|
+
In the debug REPL, use `.scripts` to list all scripts or `.scripts <name>` to show detail for one script.
|
|
2809
|
+
|
|
2810
|
+
|
|
2700
2811
|
## SUB { #subcmd }
|
|
2701
2812
|
|
|
2702
2813
|
```
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
},
|
|
94
94
|
"action-keywords": {
|
|
95
95
|
"comment": "sub, write, execute script, export, etc.",
|
|
96
|
-
"match": "(?i)\\b(reset\\s+dialog_canceled|write\\s+create_table|export_metadata|pg_upsert\\s+check|sub_querystring|execute\\s+script|append\\s+script|extend\\s+script|reset\\s+counter|export\\s+query|pg_upsert\\s+qa|sub_tempfile|write\\s+script|import_file|set\\s+counter|sub_decrypt|sub_encrypt|autocommit|breakpoint|copy\\s+query|disconnect|select_sub|sub_append|system_cmd|pg_upsert|pg_vacuum|sub_empty|sub_local|connect|include|max_int|rm_file|subdata|sub_add|sub_ini|assert|export|import|rm_sub|debug|email|serve|write|copy|log|run|sub|use|zip|cd)\\b",
|
|
96
|
+
"match": "(?i)\\b(reset\\s+dialog_canceled|write\\s+create_table|export_metadata|pg_upsert\\s+check|sub_querystring|execute\\s+script|append\\s+script|extend\\s+script|reset\\s+counter|export\\s+query|pg_upsert\\s+qa|show\\s+scripts|sub_tempfile|write\\s+script|import_file|set\\s+counter|show\\s+script|sub_decrypt|sub_encrypt|autocommit|breakpoint|copy\\s+query|disconnect|select_sub|sub_append|system_cmd|pg_upsert|pg_vacuum|sub_empty|sub_local|connect|include|max_int|rm_file|subdata|sub_add|sub_ini|assert|export|import|rm_sub|debug|email|serve|write|copy|log|run|sub|use|zip|cd)\\b",
|
|
97
97
|
"name": "keyword.other.execsql"
|
|
98
98
|
},
|
|
99
99
|
"config-event-keywords": {
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "execsql2"
|
|
7
|
-
version = "2.16.
|
|
7
|
+
version = "2.16.12"
|
|
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" }
|
|
@@ -165,7 +165,7 @@ skip-magic-trailing-comma = false
|
|
|
165
165
|
line-ending = "auto"
|
|
166
166
|
|
|
167
167
|
[tool.bumpversion]
|
|
168
|
-
current_version = "2.16.
|
|
168
|
+
current_version = "2.16.12"
|
|
169
169
|
commit = true
|
|
170
170
|
tag = true
|
|
171
171
|
tag_name = "v{new_version}"
|
|
@@ -188,7 +188,7 @@ addopts = [
|
|
|
188
188
|
"--cov=execsql",
|
|
189
189
|
"--cov-branch",
|
|
190
190
|
"--cov-report=xml",
|
|
191
|
-
"--cov-fail-under=
|
|
191
|
+
"--cov-fail-under=89",
|
|
192
192
|
"--strict-markers",
|
|
193
193
|
"--strict-config",
|
|
194
194
|
"--color=yes",
|
|
@@ -111,6 +111,8 @@ _HELP_COMMANDS = [
|
|
|
111
111
|
(".where", ".w", "Show the current script location and upcoming statement"),
|
|
112
112
|
(".stack", "", "Show the command-list stack (script name, line, depth)"),
|
|
113
113
|
(".set VAR VAL", ".s", "Set or update a substitution variable"),
|
|
114
|
+
(".scripts", "", "List all registered SCRIPT definitions"),
|
|
115
|
+
(".scripts NAME", "", "Show detail for a specific SCRIPT"),
|
|
114
116
|
(".help", ".h", "Show this help text"),
|
|
115
117
|
]
|
|
116
118
|
|
|
@@ -290,6 +292,12 @@ def _handle_dot_command(line: str) -> None:
|
|
|
290
292
|
varname = parts[0]
|
|
291
293
|
value = parts[1] if len(parts) > 1 else ""
|
|
292
294
|
_set_var(varname, value)
|
|
295
|
+
elif cmd.startswith("scripts"):
|
|
296
|
+
rest = cmd[7:].strip()
|
|
297
|
+
if rest:
|
|
298
|
+
_print_script_detail(rest)
|
|
299
|
+
else:
|
|
300
|
+
_print_scripts()
|
|
293
301
|
else:
|
|
294
302
|
_write(f" {_c(_RED, 'Unknown command:')} {line!r}. Type '.help' for available commands.\n")
|
|
295
303
|
|
|
@@ -507,3 +515,54 @@ def _set_var(varname: str, value: str) -> None:
|
|
|
507
515
|
else:
|
|
508
516
|
subvars.add_substitution(varname, value)
|
|
509
517
|
_write(f" {_c(_CYAN, varname)} {_c(_DIM, '=')} {value}\n")
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
def _print_scripts() -> None:
|
|
521
|
+
"""Print all registered SCRIPT definitions."""
|
|
522
|
+
from execsql.metacommands.debug import _format_script_signature, _format_script_source
|
|
523
|
+
|
|
524
|
+
scripts = _state.ast_scripts
|
|
525
|
+
if not scripts:
|
|
526
|
+
_write(" (no scripts registered)\n\n")
|
|
527
|
+
return
|
|
528
|
+
_write_rule(f" {_c(_BOLD + _YELLOW, 'Scripts')} {_c(_DIM, f'({len(scripts)})')} ")
|
|
529
|
+
sigs = {name: _format_script_signature(name, block.param_defs) for name, block in scripts.items()}
|
|
530
|
+
max_sig = max(len(s) for s in sigs.values())
|
|
531
|
+
for name, block in scripts.items():
|
|
532
|
+
sig = sigs[name]
|
|
533
|
+
src = _format_script_source(block.span)
|
|
534
|
+
_write(f" {_c(_CYAN, sig):<{max_sig + len(_CYAN) + len(_RESET)}} {_c(_DIM, src)}\n")
|
|
535
|
+
_write("\n")
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def _print_script_detail(name: str) -> None:
|
|
539
|
+
"""Print detail for a single SCRIPT definition."""
|
|
540
|
+
from execsql.metacommands.debug import _format_script_signature, _format_script_source
|
|
541
|
+
|
|
542
|
+
script_name = name.lower()
|
|
543
|
+
scripts = _state.ast_scripts
|
|
544
|
+
if script_name not in scripts:
|
|
545
|
+
_write(f" {_c(_RED, 'No script named')} {_c(_CYAN, repr(script_name))} {_c(_RED, 'is registered.')}\n")
|
|
546
|
+
return
|
|
547
|
+
block = scripts[script_name]
|
|
548
|
+
sig = _format_script_signature(block.name, block.param_defs)
|
|
549
|
+
src = _format_script_source(block.span)
|
|
550
|
+
_write_rule(f" {_c(_BOLD + _YELLOW, 'Script')} {_c(_DIM, '──')} {_c(_CYAN, sig)} ")
|
|
551
|
+
_write(f" {_c(_BOLD, 'Source:')} {src}\n")
|
|
552
|
+
if block.param_defs:
|
|
553
|
+
_write(f" {_c(_BOLD, 'Parameters:')}\n")
|
|
554
|
+
max_name = max(len(p.name) for p in block.param_defs)
|
|
555
|
+
for p in block.param_defs:
|
|
556
|
+
if p.default is not None:
|
|
557
|
+
_write(
|
|
558
|
+
f" {_c(_CYAN, p.name):<{max_name + len(_CYAN) + len(_RESET)}} {_c(_DIM, f'(optional, default: {p.default})')}\n",
|
|
559
|
+
)
|
|
560
|
+
else:
|
|
561
|
+
_write(f" {_c(_CYAN, p.name):<{max_name + len(_CYAN) + len(_RESET)}} {_c(_DIM, '(required)')}\n")
|
|
562
|
+
else:
|
|
563
|
+
_write(f" {_c(_BOLD, 'Parameters:')} (none)\n")
|
|
564
|
+
if block.doc:
|
|
565
|
+
_write("\n")
|
|
566
|
+
for doc_line in block.doc.split("\n"):
|
|
567
|
+
_write(f" {_c(_DIM, doc_line)}\n")
|
|
568
|
+
_write("\n")
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from execsql.utils.errors import fatal_error
|
|
3
2
|
|
|
4
3
|
"""
|
|
5
4
|
Debug metacommand handlers for execsql.
|
|
@@ -7,11 +6,16 @@ Debug metacommand handlers for execsql.
|
|
|
7
6
|
Provides ``x_debug_write_metacommands``, which implements the
|
|
8
7
|
``WRITE METACOMMANDS`` debug metacommand that prints the full registered
|
|
9
8
|
metacommand list to the log/console for troubleshooting.
|
|
9
|
+
|
|
10
|
+
Also provides ``x_show_scripts`` and ``x_show_script`` for runtime
|
|
11
|
+
introspection of registered SCRIPT blocks.
|
|
10
12
|
"""
|
|
11
13
|
|
|
14
|
+
from pathlib import Path
|
|
12
15
|
from typing import Any
|
|
13
16
|
|
|
14
17
|
import execsql.state as _state
|
|
18
|
+
from execsql.utils.errors import fatal_error
|
|
15
19
|
from execsql.utils.fileio import EncodedFile, filewriter_open_as_new, filewriter_write
|
|
16
20
|
|
|
17
21
|
|
|
@@ -173,3 +177,87 @@ def x_debug_write_config(**kwargs: Any) -> None:
|
|
|
173
177
|
|
|
174
178
|
for line in lines:
|
|
175
179
|
write(f"{line}\n")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
# ---------------------------------------------------------------------------
|
|
183
|
+
# Helpers for SCRIPT introspection (shared by metacommands and REPL)
|
|
184
|
+
# ---------------------------------------------------------------------------
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _format_script_signature(name: str, param_defs: Any) -> str:
|
|
188
|
+
"""Return ``name(param1, param2, opt=default)`` or ``name()``.
|
|
189
|
+
|
|
190
|
+
*param_defs* may be a list of :class:`ParamDef` objects (preferred) or
|
|
191
|
+
a plain list of strings (backward compat).
|
|
192
|
+
"""
|
|
193
|
+
if not param_defs:
|
|
194
|
+
return f"{name}()"
|
|
195
|
+
parts: list[str] = []
|
|
196
|
+
for p in param_defs:
|
|
197
|
+
if hasattr(p, "default") and p.default is not None:
|
|
198
|
+
parts.append(f"{p.name}={p.default}")
|
|
199
|
+
elif hasattr(p, "name"):
|
|
200
|
+
parts.append(p.name)
|
|
201
|
+
else:
|
|
202
|
+
parts.append(str(p))
|
|
203
|
+
return f"{name}({', '.join(parts)})"
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _format_script_source(span: Any) -> str:
|
|
207
|
+
"""Return ``file:start-end`` from a SourceSpan."""
|
|
208
|
+
filename = Path(span.file).name if span and span.file else "<unknown>"
|
|
209
|
+
if span and span.start_line is not None:
|
|
210
|
+
if span.end_line is not None and span.end_line != span.start_line:
|
|
211
|
+
return f"{filename}:{span.start_line}-{span.end_line}"
|
|
212
|
+
return f"{filename}:{span.start_line}"
|
|
213
|
+
return filename
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
# ---------------------------------------------------------------------------
|
|
217
|
+
# SHOW SCRIPTS / SHOW SCRIPT metacommand handlers
|
|
218
|
+
# ---------------------------------------------------------------------------
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def x_show_scripts(**kwargs: Any) -> None:
|
|
222
|
+
"""List all registered SCRIPT definitions with parameters and source location."""
|
|
223
|
+
scripts = _state.ast_scripts
|
|
224
|
+
if not scripts:
|
|
225
|
+
_state.output.write("No scripts registered.\n")
|
|
226
|
+
return
|
|
227
|
+
_state.output.write(f"Registered scripts ({len(scripts)}):\n\n")
|
|
228
|
+
# Compute column width for alignment
|
|
229
|
+
sigs = {name: _format_script_signature(name, block.param_defs) for name, block in scripts.items()}
|
|
230
|
+
max_sig = max(len(s) for s in sigs.values())
|
|
231
|
+
for name, block in scripts.items():
|
|
232
|
+
sig = sigs[name]
|
|
233
|
+
src = _format_script_source(block.span)
|
|
234
|
+
_state.output.write(f" {sig:<{max_sig}} {src}\n")
|
|
235
|
+
_state.output.write("\n")
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def x_show_script(**kwargs: Any) -> None:
|
|
239
|
+
"""Show detail for a single registered SCRIPT definition."""
|
|
240
|
+
script_name = kwargs.get("script_id", "").lower()
|
|
241
|
+
scripts = _state.ast_scripts
|
|
242
|
+
if script_name not in scripts:
|
|
243
|
+
_state.output.write(f"No script named '{script_name}' is registered.\n")
|
|
244
|
+
return
|
|
245
|
+
block = scripts[script_name]
|
|
246
|
+
sig = _format_script_signature(block.name, block.param_defs)
|
|
247
|
+
src = _format_script_source(block.span)
|
|
248
|
+
_state.output.write(f"Script: {sig}\n")
|
|
249
|
+
_state.output.write(f"Source: {src}\n")
|
|
250
|
+
if block.param_defs:
|
|
251
|
+
_state.output.write("Parameters:\n")
|
|
252
|
+
max_name = max(len(p.name) for p in block.param_defs)
|
|
253
|
+
for p in block.param_defs:
|
|
254
|
+
if p.default is not None:
|
|
255
|
+
_state.output.write(f" {p.name:<{max_name}} (optional, default: {p.default})\n")
|
|
256
|
+
else:
|
|
257
|
+
_state.output.write(f" {p.name:<{max_name}} (required)\n")
|
|
258
|
+
else:
|
|
259
|
+
_state.output.write("Parameters: (none)\n")
|
|
260
|
+
if block.doc:
|
|
261
|
+
_state.output.write("\n")
|
|
262
|
+
for doc_line in block.doc.split("\n"):
|
|
263
|
+
_state.output.write(f" {doc_line}\n")
|
|
@@ -99,6 +99,8 @@ from execsql.metacommands.debug import (
|
|
|
99
99
|
x_debug_write_metacommands,
|
|
100
100
|
x_debug_write_odbc_drivers,
|
|
101
101
|
x_debug_write_subvars,
|
|
102
|
+
x_show_script,
|
|
103
|
+
x_show_scripts,
|
|
102
104
|
)
|
|
103
105
|
from execsql.debug.repl import x_breakpoint
|
|
104
106
|
from execsql.metacommands.io import (
|
|
@@ -1747,6 +1749,22 @@ def build_dispatch_table() -> MetaCommandList:
|
|
|
1747
1749
|
run_when_false=False,
|
|
1748
1750
|
)
|
|
1749
1751
|
|
|
1752
|
+
# ------------------------------------------------------------------
|
|
1753
|
+
# SHOW SCRIPTS / SHOW SCRIPT
|
|
1754
|
+
# ------------------------------------------------------------------
|
|
1755
|
+
mcl.add(
|
|
1756
|
+
r"^\s*SHOW\s+SCRIPTS\s*$",
|
|
1757
|
+
x_show_scripts,
|
|
1758
|
+
description="SHOW SCRIPTS",
|
|
1759
|
+
category="action",
|
|
1760
|
+
)
|
|
1761
|
+
mcl.add(
|
|
1762
|
+
r"^\s*SHOW\s+SCRIPT\s+(?P<script_id>\w+)\s*$",
|
|
1763
|
+
x_show_script,
|
|
1764
|
+
description="SHOW SCRIPT",
|
|
1765
|
+
category="action",
|
|
1766
|
+
)
|
|
1767
|
+
|
|
1750
1768
|
# ------------------------------------------------------------------
|
|
1751
1769
|
# IF / ORIF / ANDIF / ELSEIF / ELSE / ENDIF
|
|
1752
1770
|
# ------------------------------------------------------------------
|
|
@@ -52,6 +52,7 @@ __all__ = [
|
|
|
52
52
|
"IfBlock",
|
|
53
53
|
"LoopBlock",
|
|
54
54
|
"BatchBlock",
|
|
55
|
+
"ParamDef",
|
|
55
56
|
"ScriptBlock",
|
|
56
57
|
"SqlBlock",
|
|
57
58
|
"IncludeDirective",
|
|
@@ -290,6 +291,24 @@ class BatchBlock(Node):
|
|
|
290
291
|
return f"BatchBlock({self.span}, body={len(self.body)})"
|
|
291
292
|
|
|
292
293
|
|
|
294
|
+
@dataclass(frozen=True, slots=True)
|
|
295
|
+
class ParamDef:
|
|
296
|
+
"""A single SCRIPT parameter definition with an optional default value.
|
|
297
|
+
|
|
298
|
+
Attributes:
|
|
299
|
+
name: The parameter name (as declared, without ``#`` prefix).
|
|
300
|
+
default: The default value string, or ``None`` for required parameters.
|
|
301
|
+
"""
|
|
302
|
+
|
|
303
|
+
name: str
|
|
304
|
+
default: str | None = None
|
|
305
|
+
|
|
306
|
+
@property
|
|
307
|
+
def required(self) -> bool:
|
|
308
|
+
"""Return ``True`` if this parameter has no default value."""
|
|
309
|
+
return self.default is None
|
|
310
|
+
|
|
311
|
+
|
|
293
312
|
@dataclass
|
|
294
313
|
class ScriptBlock(Node):
|
|
295
314
|
"""A BEGIN SCRIPT name ... END SCRIPT structure.
|
|
@@ -299,20 +318,31 @@ class ScriptBlock(Node):
|
|
|
299
318
|
|
|
300
319
|
Attributes:
|
|
301
320
|
name: The script block name (lowercased).
|
|
302
|
-
|
|
321
|
+
param_defs: Optional list of :class:`ParamDef` parameter definitions.
|
|
322
|
+
doc: Optional docstring extracted from comments immediately following
|
|
323
|
+
the BEGIN SCRIPT line.
|
|
303
324
|
body: Nodes within the script block.
|
|
304
325
|
"""
|
|
305
326
|
|
|
306
327
|
name: str
|
|
307
|
-
|
|
328
|
+
param_defs: list[ParamDef] | None = None
|
|
329
|
+
doc: str | None = None
|
|
308
330
|
body: list[Node] = field(default_factory=list)
|
|
309
331
|
|
|
332
|
+
@property
|
|
333
|
+
def param_names(self) -> list[str] | None:
|
|
334
|
+
"""Return parameter names only (backward compatibility)."""
|
|
335
|
+
if self.param_defs is None:
|
|
336
|
+
return None
|
|
337
|
+
return [p.name for p in self.param_defs]
|
|
338
|
+
|
|
310
339
|
def children(self) -> Iterator[Node]:
|
|
311
340
|
yield from self.body
|
|
312
341
|
|
|
313
342
|
def __repr__(self) -> str:
|
|
314
|
-
params = f", params={self.param_names}" if self.
|
|
315
|
-
|
|
343
|
+
params = f", params={self.param_names}" if self.param_defs else ""
|
|
344
|
+
doc_tag = ", doc=True" if self.doc else ""
|
|
345
|
+
return f"ScriptBlock({self.span}, name={self.name!r}{params}{doc_tag}, body={len(self.body)})"
|
|
316
346
|
|
|
317
347
|
|
|
318
348
|
@dataclass
|
|
@@ -547,8 +577,15 @@ def _node_label(node: Node) -> str:
|
|
|
547
577
|
if isinstance(node, BatchBlock):
|
|
548
578
|
return f"{_tag('BATCH')} BEGIN BATCH"
|
|
549
579
|
if isinstance(node, ScriptBlock):
|
|
550
|
-
|
|
551
|
-
|
|
580
|
+
if node.param_defs:
|
|
581
|
+
parts = []
|
|
582
|
+
for p in node.param_defs:
|
|
583
|
+
parts.append(f"{p.name}={p.default}" if p.default is not None else p.name)
|
|
584
|
+
params = f" ({', '.join(parts)})"
|
|
585
|
+
else:
|
|
586
|
+
params = ""
|
|
587
|
+
doc_tag = " [doc]" if node.doc else ""
|
|
588
|
+
return f"{_tag('SCRIPT')} {node.name}{params}{doc_tag}"
|
|
552
589
|
if isinstance(node, SqlBlock):
|
|
553
590
|
return f"{_tag('SQL_BLK')} BEGIN SQL"
|
|
554
591
|
if isinstance(node, IncludeDirective):
|
|
@@ -648,7 +648,10 @@ def _execute_include(
|
|
|
648
648
|
WHILE/UNTIL loops are handled natively too.
|
|
649
649
|
"""
|
|
650
650
|
if node.is_execute_script:
|
|
651
|
-
target
|
|
651
|
+
# Substitute variables in the target — the script name may be passed
|
|
652
|
+
# as a parameter (e.g., EXECUTE SCRIPT !!#script_name!!).
|
|
653
|
+
effective_locals = _stack_localvars(ctx) or localvars
|
|
654
|
+
target = substitute_vars(node.target, effective_locals, ctx=ctx).strip().lower()
|
|
652
655
|
|
|
653
656
|
# Native path: target is in our AST registry
|
|
654
657
|
if target in ctx.ast_scripts:
|
|
@@ -713,23 +716,35 @@ def _execute_script_native(
|
|
|
713
716
|
for param, arg in all_prepared_args:
|
|
714
717
|
paramvals.add_substitution(param, arg)
|
|
715
718
|
|
|
716
|
-
# Validate parameter names match
|
|
717
|
-
if script_block.
|
|
719
|
+
# Validate parameter names match — with default parameter support
|
|
720
|
+
if script_block.param_defs is not None:
|
|
718
721
|
passed_names = [p[0].lstrip("#") for p in all_prepared_args]
|
|
719
|
-
|
|
722
|
+
required = [p.name for p in script_block.param_defs if p.required]
|
|
723
|
+
missing = [p for p in required if p not in passed_names]
|
|
724
|
+
if missing:
|
|
720
725
|
raise ErrInfo(
|
|
721
726
|
"error",
|
|
722
|
-
other_msg=f"
|
|
727
|
+
other_msg=(f"Missing required parameter(s) ({', '.join(missing)}) in call to {script_block.name}."),
|
|
723
728
|
)
|
|
729
|
+
# Inject defaults for optional params not provided
|
|
730
|
+
for pdef in script_block.param_defs:
|
|
731
|
+
if pdef.default is not None and pdef.name not in passed_names:
|
|
732
|
+
paramvals.add_substitution(f"#{pdef.name}", pdef.default)
|
|
724
733
|
else:
|
|
725
|
-
if script_block.
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
734
|
+
if script_block.param_defs is not None:
|
|
735
|
+
required = [p.name for p in script_block.param_defs if p.required]
|
|
736
|
+
if required:
|
|
737
|
+
raise ErrInfo(
|
|
738
|
+
"error",
|
|
739
|
+
other_msg=(
|
|
740
|
+
f"Missing required parameter(s) ({', '.join(required)}) in call to {script_block.name}."
|
|
741
|
+
),
|
|
742
|
+
)
|
|
743
|
+
# No args provided but all params have defaults — inject them all
|
|
744
|
+
paramvals = ScriptArgSubVarSet()
|
|
745
|
+
for pdef in script_block.param_defs:
|
|
746
|
+
if pdef.default is not None:
|
|
747
|
+
paramvals.add_substitution(f"#{pdef.name}", pdef.default)
|
|
733
748
|
|
|
734
749
|
# Push a CommandList frame onto the stack so that:
|
|
735
750
|
# - get_subvarset() can find ~local and +outer-scope variables
|