execsql2 2.12.3__tar.gz → 2.12.5__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.12.3 → execsql2-2.12.5}/CHANGELOG.md +12 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/PKG-INFO +4 -1
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/about/divergence.md +7 -6
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/getting-started/installation.md +1 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/reference/metacommands.md +116 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +1 -1
- {execsql2-2.12.3 → execsql2-2.12.5}/pyproject.toml +4 -2
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/__init__.py +9 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/dispatch.py +30 -0
- execsql2-2.12.5/src/execsql/metacommands/upsert.py +448 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/cli/test_cli.py +6 -1
- execsql2-2.12.5/tests/metacommands/test_pg_upsert.py +997 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/uv.lock +30 -18
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/agents/dba.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/agents/herald.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/agents/inspector.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/agents/liaison.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/agents/oracle.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/agents/patcher.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/agents/qa.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/agents/scribe.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/commands/code-oracle.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/commands/migrate.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/commands/review-changes.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/commands/test-module.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/commands/update-changelog.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/commands/where-is.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/project_context.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.claude/state/status.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.github/workflows/ci-cd.yml +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.gitignore +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.pre-commit-config.yaml +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.pre-commit-hooks.yaml +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.python-version +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/.readthedocs.yaml +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/CLAUDE.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/CONTRIBUTING.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/LICENSE.txt +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/NOTICE +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/README.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/SECURITY.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/about/contributors.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/about/copyright.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/api/cli.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/api/db.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/api/exporters.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/api/importers.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/api/index.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/api/metacommands.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/dev/adding_db_adapters.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/dev/adding_exporters.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/dev/adding_importers.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/dev/adding_metacommands.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/dev/architecture.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/getting-started/requirements.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/getting-started/syntax.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/guides/debugging.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/guides/documentation.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/guides/encoding.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/guides/examples.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/guides/formatter.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/guides/logging.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/guides/sql_syntax.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/guides/usage.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/guides/using_scripts.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/Compare_planets.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/actions.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/actions2.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/checkboxes.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/connect.b64 +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/connect.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/create_conf.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/data_error1_screenshot.jpg +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/entry_form.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/execsql_console.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/execsql_logo_01.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/fatals.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/logo_small.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/pause_terminal.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/pause_terminal_sm.b64 +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/pause_terminal_sm.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/prompt_compare.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/set_build_commands.jpg +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/unit_conversions.b64 +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/unit_conversions_029.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/unmatched.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/images/vim_execsql_highlight.png +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/index.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/reference/configuration.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/reference/security.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/docs/reference/substitution_vars.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/extras/vscode-execsql/README.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/extras/vscode-execsql/package.json +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/justfile +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/scripts/generate_vscode_grammar.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/__main__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/cli/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/cli/dsn.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/cli/help.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/cli/lint.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/cli/run.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/config.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/constants.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/access.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/base.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/dsn.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/duckdb.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/factory.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/firebird.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/mysql.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/oracle.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/postgres.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/sqlite.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/db/sqlserver.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/debug/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/debug/repl.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exceptions.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/base.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/delimited.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/duckdb.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/feather.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/html.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/json.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/latex.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/markdown.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/ods.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/parquet.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/pretty.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/protocol.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/raw.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/sqlite.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/templates.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/values.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/xls.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/xlsx.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/xml.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/yaml.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/exporters/zip.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/format.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/gui/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/gui/base.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/gui/console.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/gui/desktop.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/gui/tui.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/importers/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/importers/base.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/importers/csv.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/importers/feather.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/importers/ods.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/importers/xls.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/conditions.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/connect.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/control.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/data.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/debug.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/io.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/io_export.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/io_fileops.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/io_import.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/io_write.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/prompt.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/script_ext.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/metacommands/system.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/models.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/parser.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/py.typed +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/script/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/script/control.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/script/engine.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/script/variables.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/state.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/types.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/auth.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/crypto.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/datetime.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/errors.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/fileio.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/gui.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/mail.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/numeric.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/regex.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/strings.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/src/execsql/utils/timer.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/README.md +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/config_settings.sqlite +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/example_config_prompt.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/execsql.conf +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/make_config_db.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/md_compare.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/md_glossary.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/md_upsert.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/pg_compare.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/pg_glossary.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/pg_upsert.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/script_template.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/ss_compare.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/ss_glossary.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/templates/ss_upsert.sql +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/cli/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/cli/test_cli_e2e.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/cli/test_cli_run.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/cli/test_lint.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/cli/test_ping.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/cli/test_profile.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/conftest.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/db/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/db/test_base.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/db/test_duckdb.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/db/test_factory.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/db/test_postgres.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/db/test_sqlite.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/db/test_sqlite_extra.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_base.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_db.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_delimited.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_duckdb_exporter.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_exporters.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_feather.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_html_latex.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_json.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_markdown.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_ods.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_parquet.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_sqlite_exporter.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_templates.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_xls_xlsx.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_xlsx.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_xml.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_yaml.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/exporters/test_zip.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/gui/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/gui/test_backends.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/importers/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/importers/test_csv_importer.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/importers/test_feather_importer.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/importers/test_ods_importer.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/importers/test_xls_importer.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/integration/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/integration/conftest.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/integration/test_dsn.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/integration/test_duckdb.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/integration/test_mysql.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/integration/test_postgres.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/integration/test_sqlite.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_assert.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_breakpoint.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_connect.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_io_export.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_io_import.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_metacommands.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_metacommands_connect.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_metacommands_data.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_metacommands_extended.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_metacommands_io.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_metacommands_script_ext.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_metacommands_system.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_metacommands_system_extra.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/metacommands/test_row_count.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_config.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_config_data.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_constants.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_engine.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_error_messages.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_exceptions.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_format.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_mail.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_models.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_package.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_parser.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_registry.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_script.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_state.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/test_types.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/__init__.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_auth.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_auth_extra.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_crypto.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_datetime.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_errors.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_errors_extra.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_fileio.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_fileio_extra.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_numeric.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_regex.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_strings.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_timer.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/tests/utils/test_timer_extra.py +0 -0
- {execsql2-2.12.3 → execsql2-2.12.5}/zensical.toml +0 -0
|
@@ -13,6 +13,18 @@ ______________________________________________________________________
|
|
|
13
13
|
|
|
14
14
|
______________________________________________________________________
|
|
15
15
|
|
|
16
|
+
## [2.12.5] - 2026-04-03
|
|
17
|
+
|
|
18
|
+
______________________________________________________________________
|
|
19
|
+
|
|
20
|
+
## [2.12.4] - 2026-04-03
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- New `PG_UPSERT` metacommand for QA-checked, FK-dependency-ordered upserts from a staging schema to a base schema on PostgreSQL. Integrates [pg-upsert](https://pg-upsert.readthedocs.io/) as an optional dependency (`pip install execsql2[upsert]`). Three modes: full pipeline (`PG_UPSERT FROM ... TO ... TABLES ...`), QA-only (`PG_UPSERT QA ...`), and schema check (`PG_UPSERT CHECK ...`). Supports `METHOD`, `COMMIT`, `INTERACTIVE`, `COMPACT`, `EXCLUDE`, `EXCLUDE_NULL`, and `LOGFILE` keywords. Sets 12 `$PG_UPSERT_*` substitution variables after execution.
|
|
25
|
+
|
|
26
|
+
______________________________________________________________________
|
|
27
|
+
|
|
16
28
|
## [2.12.3] - 2026-04-02
|
|
17
29
|
|
|
18
30
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.12.
|
|
3
|
+
Version: 2.12.5
|
|
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
|
|
@@ -51,6 +51,7 @@ Requires-Dist: keyring; extra == 'all'
|
|
|
51
51
|
Requires-Dist: odfpy; extra == 'all'
|
|
52
52
|
Requires-Dist: openpyxl; extra == 'all'
|
|
53
53
|
Requires-Dist: oracledb; extra == 'all'
|
|
54
|
+
Requires-Dist: pg-upsert>=1.17.0; extra == 'all'
|
|
54
55
|
Requires-Dist: polars; extra == 'all'
|
|
55
56
|
Requires-Dist: psycopg2-binary; extra == 'all'
|
|
56
57
|
Requires-Dist: pymysql; extra == 'all'
|
|
@@ -107,6 +108,8 @@ Provides-Extra: oracle
|
|
|
107
108
|
Requires-Dist: oracledb; extra == 'oracle'
|
|
108
109
|
Provides-Extra: postgres
|
|
109
110
|
Requires-Dist: psycopg2-binary; extra == 'postgres'
|
|
111
|
+
Provides-Extra: upsert
|
|
112
|
+
Requires-Dist: pg-upsert>=1.17.0; extra == 'upsert'
|
|
110
113
|
Description-Content-Type: text/markdown
|
|
111
114
|
|
|
112
115
|
> [!NOTE]
|
|
@@ -41,12 +41,13 @@ ______________________________________________________________________
|
|
|
41
41
|
|
|
42
42
|
### Metacommands
|
|
43
43
|
|
|
44
|
-
| Metacommand | Description
|
|
45
|
-
| ---------------------- |
|
|
46
|
-
| `ASSERT` | Evaluate a condition and raise an error (halting the script) if it is false. Supports all IF conditions. Optional quoted failure message. Skipped in false IF blocks.
|
|
47
|
-
| `BREAKPOINT` | Pause script execution and drop into an interactive debug REPL. See [Debugging](#debugging) below for full details.
|
|
48
|
-
| `CONFIG SHOW_PROGRESS` | Enable the Rich progress bar for IMPORT operations at runtime.
|
|
49
|
-
| `CONFIG LOG_SQL` | Enable SQL query audit logging — writes executed SQL to the log file.
|
|
44
|
+
| Metacommand | Description |
|
|
45
|
+
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
46
|
+
| `ASSERT` | Evaluate a condition and raise an error (halting the script) if it is false. Supports all IF conditions. Optional quoted failure message. Skipped in false IF blocks. |
|
|
47
|
+
| `BREAKPOINT` | Pause script execution and drop into an interactive debug REPL. See [Debugging](#debugging) below for full details. |
|
|
48
|
+
| `CONFIG SHOW_PROGRESS` | Enable the Rich progress bar for IMPORT operations at runtime. |
|
|
49
|
+
| `CONFIG LOG_SQL` | Enable SQL query audit logging — writes executed SQL to the log file. |
|
|
50
|
+
| `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. |
|
|
50
51
|
|
|
51
52
|
### Conditional Tests
|
|
52
53
|
|
|
@@ -25,6 +25,7 @@ pip install "execsql2[duckdb]" # DuckDB
|
|
|
25
25
|
pip install "execsql2[mssql]" # MS SQL Server / ODBC
|
|
26
26
|
pip install "execsql2[formats]" # ODS, Excel, Jinja2, Feather, Parquet, HDF5
|
|
27
27
|
pip install "execsql2[auth]" # OS keyring integration
|
|
28
|
+
pip install "execsql2[upsert]" # PG_UPSERT metacommand (pg-upsert)
|
|
28
29
|
pip install "execsql2[all-db]" # All database drivers
|
|
29
30
|
pip install "execsql2[all]" # Everything
|
|
30
31
|
```
|
|
@@ -2066,6 +2066,122 @@ If the "HALT" action is taken, either as a result of user input or as a result o
|
|
|
2066
2066
|
Double quotes (as shown above), apostrophes, or square brackets can be used to delimit the text.
|
|
2067
2067
|
|
|
2068
2068
|
|
|
2069
|
+
## PG_UPSERT { #pg_upsert }
|
|
2070
|
+
|
|
2071
|
+
```
|
|
2072
|
+
PG_UPSERT FROM <staging_schema> TO <base_schema> TABLES <table1>, <table2> [options]
|
|
2073
|
+
PG_UPSERT QA FROM <staging_schema> TO <base_schema> TABLES <table1>, <table2> [options]
|
|
2074
|
+
PG_UPSERT CHECK FROM <staging_schema> TO <base_schema> TABLES <table1>, <table2>
|
|
2075
|
+
```
|
|
2076
|
+
|
|
2077
|
+
Performs QA-checked, FK-dependency-ordered upserts from a staging schema to a base schema on PostgreSQL. Integrates [pg-upsert](https://pg-upsert.readthedocs.io/) as an optional dependency.
|
|
2078
|
+
|
|
2079
|
+
**Requires:** `pip install execsql2[upsert]`
|
|
2080
|
+
|
|
2081
|
+
**Requires:** A PostgreSQL connection. Raises an error if the current DBMS is not PostgreSQL.
|
|
2082
|
+
|
|
2083
|
+
### Modes
|
|
2084
|
+
|
|
2085
|
+
- **Full pipeline** (`PG_UPSERT FROM ... TO ... TABLES ...`): Runs all QA checks, then upserts data (update + insert by default), with optional commit.
|
|
2086
|
+
- **QA only** (`PG_UPSERT QA FROM ... TO ... TABLES ...`): Runs all QA checks without upserting. Never commits.
|
|
2087
|
+
- **Schema check** (`PG_UPSERT CHECK FROM ... TO ... TABLES ...`): Checks column existence and type compatibility only. Never commits.
|
|
2088
|
+
|
|
2089
|
+
### Optional keywords
|
|
2090
|
+
|
|
2091
|
+
Keywords can appear in any order after the table list.
|
|
2092
|
+
|
|
2093
|
+
| Keyword | Description |
|
|
2094
|
+
|---------|-------------|
|
|
2095
|
+
| `METHOD upsert\|update\|insert` | Upsert strategy. `upsert` (default) updates existing + inserts new rows. `update` only updates. `insert` only inserts. Full mode only. |
|
|
2096
|
+
| `COMMIT` | Commit changes if QA passes. Without it, changes are rolled back (dry-run). Full mode only. |
|
|
2097
|
+
| `EXCLUDE col1, col2` | Columns to skip during upsert. |
|
|
2098
|
+
| `EXCLUDE_NULL col1, col2` | Columns to skip in null QA checks. |
|
|
2099
|
+
| `INTERACTIVE` | Enable pg-upsert's interactive UI dialogs (tkinter or textual) for reviewing QA failures. Without it, runs non-interactively. |
|
|
2100
|
+
| `COMPACT` | Use compact grid format for QA summary instead of detailed per-table panels. |
|
|
2101
|
+
| `LOGFILE <path>` | Append pg-upsert's plain-text log output to the given file. Supports quoted paths for spaces: `LOGFILE "path/to/log.txt"`. |
|
|
2102
|
+
|
|
2103
|
+
### Substitution variables
|
|
2104
|
+
|
|
2105
|
+
Set after every `PG_UPSERT` execution:
|
|
2106
|
+
|
|
2107
|
+
| Variable | Type | Description |
|
|
2108
|
+
|----------|------|-------------|
|
|
2109
|
+
| `$PG_UPSERT_QA_PASSED` | TRUE/FALSE | Did all QA checks pass? |
|
|
2110
|
+
| `$PG_UPSERT_ROWS_UPDATED` | integer | Total rows updated across all tables |
|
|
2111
|
+
| `$PG_UPSERT_ROWS_INSERTED` | integer | Total rows inserted across all tables |
|
|
2112
|
+
| `$PG_UPSERT_COMMITTED` | TRUE/FALSE | Were changes committed? |
|
|
2113
|
+
| `$PG_UPSERT_STAGING_SCHEMA` | string | Staging schema name used |
|
|
2114
|
+
| `$PG_UPSERT_BASE_SCHEMA` | string | Base schema name used |
|
|
2115
|
+
| `$PG_UPSERT_TABLES` | string | Comma-separated list of table names processed |
|
|
2116
|
+
| `$PG_UPSERT_METHOD` | string | Upsert method used |
|
|
2117
|
+
| `$PG_UPSERT_DURATION` | float | Elapsed time in seconds |
|
|
2118
|
+
| `$PG_UPSERT_STARTED_AT` | string | ISO 8601 start timestamp |
|
|
2119
|
+
| `$PG_UPSERT_FINISHED_AT` | string | ISO 8601 end timestamp |
|
|
2120
|
+
| `$PG_UPSERT_RESULT_JSON` | JSON string | Full result for detailed inspection |
|
|
2121
|
+
|
|
2122
|
+
!!! note "Using `$PG_UPSERT_RESULT_JSON` with WRITE"
|
|
2123
|
+
The JSON value is stored as compact single-line JSON. Because it contains double quotes (`"`), square brackets (`[]`), and apostrophes may appear in data, use tilde or backtick delimiters with WRITE:
|
|
2124
|
+
|
|
2125
|
+
```sql
|
|
2126
|
+
-- !x! WRITE ~!!$PG_UPSERT_RESULT_JSON!!~
|
|
2127
|
+
-- !x! WRITE `!!$PG_UPSERT_RESULT_JSON!!`
|
|
2128
|
+
```
|
|
2129
|
+
|
|
2130
|
+
### Temporary objects
|
|
2131
|
+
|
|
2132
|
+
pg-upsert creates temporary tables and views (all prefixed `ups_`) that persist after the metacommand completes. Users can query these for debugging and inspection — for example, `SELECT * FROM ups_control` shows per-table QA results and row counts.
|
|
2133
|
+
|
|
2134
|
+
For the full list of temporary objects and their schemas, see the [pg-upsert Temporary Objects Reference](https://pg-upsert.readthedocs.io/en/latest/architecture/#temporary-objects-reference).
|
|
2135
|
+
|
|
2136
|
+
### Examples
|
|
2137
|
+
|
|
2138
|
+
```sql
|
|
2139
|
+
-- Full pipeline: QA + upsert + commit
|
|
2140
|
+
-- !x! PG_UPSERT FROM staging TO public TABLES books, authors COMMIT
|
|
2141
|
+
|
|
2142
|
+
-- Dry run (no commit) with update-only method
|
|
2143
|
+
-- !x! PG_UPSERT FROM staging TO public TABLES books METHOD update
|
|
2144
|
+
|
|
2145
|
+
-- QA only with interactive review
|
|
2146
|
+
-- !x! PG_UPSERT QA FROM staging TO public TABLES books, authors INTERACTIVE
|
|
2147
|
+
|
|
2148
|
+
-- Schema check only
|
|
2149
|
+
-- !x! PG_UPSERT CHECK FROM staging TO public TABLES books, authors
|
|
2150
|
+
|
|
2151
|
+
-- Log pg-upsert output to a file
|
|
2152
|
+
-- !x! PG_UPSERT FROM staging TO public TABLES books, authors LOGFILE "upsert.log" COMMIT
|
|
2153
|
+
|
|
2154
|
+
-- Use substitution variables after upsert
|
|
2155
|
+
-- !x! PG_UPSERT FROM staging TO public TABLES books COMMIT
|
|
2156
|
+
-- !x! WRITE "Updated !!$PG_UPSERT_ROWS_UPDATED!! rows, inserted !!$PG_UPSERT_ROWS_INSERTED!! in !!$PG_UPSERT_DURATION!! seconds"
|
|
2157
|
+
|
|
2158
|
+
-- Inspect pg-upsert's control table after a run
|
|
2159
|
+
-- !x! PG_UPSERT FROM staging TO public TABLES books, authors, genres COMMIT
|
|
2160
|
+
-- !x! EXPORT ups_control TO stdout AS txt
|
|
2161
|
+
|
|
2162
|
+
-- Export QA results to a CSV file for review
|
|
2163
|
+
-- !x! PG_UPSERT QA FROM staging TO public TABLES books, authors
|
|
2164
|
+
-- !x! EXPORT ups_control TO "qa_results.csv" AS csv
|
|
2165
|
+
|
|
2166
|
+
-- Check for type mismatches between schemas and display them
|
|
2167
|
+
-- !x! PG_UPSERT CHECK FROM staging TO public TABLES books, authors
|
|
2168
|
+
-- !x! EXPORT ups_type_mismatches TO stdout AS txt
|
|
2169
|
+
|
|
2170
|
+
-- Conditional logic based on QA results
|
|
2171
|
+
-- !x! PG_UPSERT FROM staging TO public TABLES books, authors
|
|
2172
|
+
-- !x! IF !!$PG_UPSERT_QA_PASSED!! = TRUE
|
|
2173
|
+
-- !x! WRITE "All QA checks passed — proceeding with commit"
|
|
2174
|
+
-- !x! ELSE
|
|
2175
|
+
-- !x! WRITE "QA failed — inspect ups_control for details"
|
|
2176
|
+
-- !x! EXPORT ups_control TO stdout AS txt
|
|
2177
|
+
-- !x! ENDIF
|
|
2178
|
+
|
|
2179
|
+
-- Write the full JSON result using tilde delimiters (JSON contains " and [])
|
|
2180
|
+
-- !x! PG_UPSERT FROM staging TO public TABLES books COMMIT
|
|
2181
|
+
-- !x! WRITE ~!!$PG_UPSERT_RESULT_JSON!!~
|
|
2182
|
+
```
|
|
2183
|
+
|
|
2184
|
+
|
|
2069
2185
|
## PG_VACUUM
|
|
2070
2186
|
|
|
2071
2187
|
```
|
|
@@ -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|sub_querystring|execute\\s+script|append\\s+script|extend\\s+script|reset\\s+counter|export\\s+query|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_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|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",
|
|
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.12.
|
|
7
|
+
version = "2.12.5"
|
|
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" }
|
|
@@ -58,6 +58,7 @@ odbc = ["pyodbc"]
|
|
|
58
58
|
# Feature bundles
|
|
59
59
|
formats = ["odfpy", "xlrd", "openpyxl", "Jinja2", "polars", "tables", "PyYAML"]
|
|
60
60
|
auth = ["keyring"]
|
|
61
|
+
upsert = ["pg-upsert>=1.17.0"]
|
|
61
62
|
# Convenience groups
|
|
62
63
|
all-db = [
|
|
63
64
|
"psycopg2-binary",
|
|
@@ -71,6 +72,7 @@ all = [
|
|
|
71
72
|
"execsql2[all-db]",
|
|
72
73
|
"execsql2[formats]",
|
|
73
74
|
"execsql2[auth]",
|
|
75
|
+
"execsql2[upsert]",
|
|
74
76
|
]
|
|
75
77
|
dev = [
|
|
76
78
|
"build>=1.2.2.post1",
|
|
@@ -159,7 +161,7 @@ skip-magic-trailing-comma = false
|
|
|
159
161
|
line-ending = "auto"
|
|
160
162
|
|
|
161
163
|
[tool.bumpversion]
|
|
162
|
-
current_version = "2.12.
|
|
164
|
+
current_version = "2.12.5"
|
|
163
165
|
commit = true
|
|
164
166
|
commit_args = "--no-verify"
|
|
165
167
|
tag = true
|
|
@@ -168,6 +168,11 @@ from execsql.metacommands.script_ext import (
|
|
|
168
168
|
x_extendscript_sql,
|
|
169
169
|
x_executescript,
|
|
170
170
|
)
|
|
171
|
+
from execsql.metacommands.upsert import (
|
|
172
|
+
x_pg_upsert,
|
|
173
|
+
x_pg_upsert_check,
|
|
174
|
+
x_pg_upsert_qa,
|
|
175
|
+
)
|
|
171
176
|
from execsql.metacommands.system import (
|
|
172
177
|
x_system_cmd,
|
|
173
178
|
x_email,
|
|
@@ -401,6 +406,10 @@ __all__ = [
|
|
|
401
406
|
"x_write_warnings",
|
|
402
407
|
"x_gui_level",
|
|
403
408
|
"x_execute",
|
|
409
|
+
# upsert handlers
|
|
410
|
+
"x_pg_upsert",
|
|
411
|
+
"x_pg_upsert_check",
|
|
412
|
+
"x_pg_upsert_qa",
|
|
404
413
|
# regex helpers
|
|
405
414
|
"ins_rxs",
|
|
406
415
|
"ins_quoted_rx",
|
|
@@ -168,6 +168,11 @@ from execsql.metacommands.script_ext import (
|
|
|
168
168
|
x_extendscript_metacommand,
|
|
169
169
|
x_extendscript_sql,
|
|
170
170
|
)
|
|
171
|
+
from execsql.metacommands.upsert import (
|
|
172
|
+
x_pg_upsert,
|
|
173
|
+
x_pg_upsert_check,
|
|
174
|
+
x_pg_upsert_qa,
|
|
175
|
+
)
|
|
171
176
|
from execsql.metacommands.system import (
|
|
172
177
|
x_cancel_halt,
|
|
173
178
|
x_cancel_halt_email,
|
|
@@ -2142,6 +2147,31 @@ def build_dispatch_table() -> MetaCommandList:
|
|
|
2142
2147
|
x_write,
|
|
2143
2148
|
)
|
|
2144
2149
|
|
|
2150
|
+
# ------------------------------------------------------------------
|
|
2151
|
+
# PG_UPSERT — pg-upsert integration (optional dependency)
|
|
2152
|
+
# ------------------------------------------------------------------
|
|
2153
|
+
# Order matters: CHECK and QA patterns must precede the general pattern
|
|
2154
|
+
# so that "PG_UPSERT CHECK ..." and "PG_UPSERT QA ..." are matched
|
|
2155
|
+
# before "PG_UPSERT FROM ...".
|
|
2156
|
+
mcl.add(
|
|
2157
|
+
r"^\s*PG_UPSERT\s+CHECK\s+FROM\s+(?P<staging_schema>\S+)\s+TO\s+(?P<base_schema>\S+)\s+TABLES\s+(?P<tail>.+)$",
|
|
2158
|
+
x_pg_upsert_check,
|
|
2159
|
+
description="PG_UPSERT CHECK",
|
|
2160
|
+
category="action",
|
|
2161
|
+
)
|
|
2162
|
+
mcl.add(
|
|
2163
|
+
r"^\s*PG_UPSERT\s+QA\s+FROM\s+(?P<staging_schema>\S+)\s+TO\s+(?P<base_schema>\S+)\s+TABLES\s+(?P<tail>.+)$",
|
|
2164
|
+
x_pg_upsert_qa,
|
|
2165
|
+
description="PG_UPSERT QA",
|
|
2166
|
+
category="action",
|
|
2167
|
+
)
|
|
2168
|
+
mcl.add(
|
|
2169
|
+
r"^\s*PG_UPSERT\s+FROM\s+(?P<staging_schema>\S+)\s+TO\s+(?P<base_schema>\S+)\s+TABLES\s+(?P<tail>.+)$",
|
|
2170
|
+
x_pg_upsert,
|
|
2171
|
+
description="PG_UPSERT",
|
|
2172
|
+
category="action",
|
|
2173
|
+
)
|
|
2174
|
+
|
|
2145
2175
|
# ------------------------------------------------------------------
|
|
2146
2176
|
# SUB (top-level variable assignment — kept near end so more specific
|
|
2147
2177
|
# SUB_* patterns above take precedence)
|