execsql2 2.15.0__tar.gz → 2.15.2__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.15.0 → execsql2-2.15.2}/.gitignore +4 -7
- {execsql2-2.15.0 → execsql2-2.15.2}/CHANGELOG.md +57 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/PKG-INFO +2 -1
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/about/divergence.md +50 -31
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/reference/configuration.md +4 -1
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/reference/metacommands.md +2 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/reference/substitution_vars.md +1 -1
- {execsql2-2.15.0 → execsql2-2.15.2}/pyproject.toml +3 -2
- execsql2-2.15.2/src/execsql/config.py +586 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/base.py +0 -1
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/duckdb.py +6 -7
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/sqlite.py +47 -47
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/gui/base.py +173 -28
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/gui/console.py +50 -13
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/gui/desktop.py +70 -28
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/gui/tui.py +57 -32
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/conditions.py +0 -24
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/io_export.py +6 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/io_import.py +5 -5
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/upsert.py +17 -33
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/models.py +0 -1
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/parser.py +22 -23
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/script/engine.py +2 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/types.py +28 -30
- execsql2-2.15.2/src/execsql/utils/datetime.py +86 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/utils/errors.py +0 -19
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/utils/fileio.py +0 -8
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/db/test_sqlite_extra.py +12 -23
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/gui/test_compare_stats.py +69 -9
- execsql2-2.15.2/tests/gui/test_compute_row_diffs.py +430 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_io_import.py +31 -31
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_metacommands.py +0 -50
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_pg_upsert.py +9 -37
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_config_extended.py +55 -10
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_engine.py +12 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_parser.py +2 -2
- execsql2-2.15.2/tests/utils/test_datetime.py +197 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_errors.py +1 -81
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_fileio_extra.py +0 -4
- {execsql2-2.15.0 → execsql2-2.15.2}/uv.lock +3 -1
- execsql2-2.15.0/.claude/agents/dba.md +0 -123
- execsql2-2.15.0/.claude/agents/herald.md +0 -92
- execsql2-2.15.0/.claude/agents/inspector.md +0 -107
- execsql2-2.15.0/.claude/agents/liaison.md +0 -107
- execsql2-2.15.0/.claude/agents/oracle.md +0 -134
- execsql2-2.15.0/.claude/agents/patcher.md +0 -70
- execsql2-2.15.0/.claude/agents/qa.md +0 -83
- execsql2-2.15.0/.claude/agents/scribe.md +0 -100
- execsql2-2.15.0/.claude/commands/code-oracle.md +0 -20
- execsql2-2.15.0/.claude/commands/migrate.md +0 -77
- execsql2-2.15.0/.claude/commands/review-changes.md +0 -79
- execsql2-2.15.0/.claude/commands/test-module.md +0 -75
- execsql2-2.15.0/.claude/commands/update-changelog.md +0 -21
- execsql2-2.15.0/.claude/commands/where-is.md +0 -51
- execsql2-2.15.0/.claude/project_context.md +0 -576
- execsql2-2.15.0/.claude/state/status.md +0 -6
- execsql2-2.15.0/src/execsql/config.py +0 -658
- execsql2-2.15.0/src/execsql/constants.py +0 -370
- execsql2-2.15.0/src/execsql/utils/datetime.py +0 -280
- execsql2-2.15.0/tests/test_constants.py +0 -94
- execsql2-2.15.0/tests/utils/test_datetime.py +0 -102
- {execsql2-2.15.0 → execsql2-2.15.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/.github/workflows/ci-cd.yml +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/.pre-commit-config.yaml +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/.pre-commit-hooks.yaml +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/.python-version +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/.readthedocs.yaml +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/CLAUDE.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/CONTRIBUTING.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/LICENSE.txt +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/NOTICE +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/README.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/SECURITY.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/about/contributors.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/about/copyright.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/api/cli.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/api/db.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/api/exporters.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/api/importers.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/api/index.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/api/metacommands.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/dev/adding_db_adapters.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/dev/adding_exporters.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/dev/adding_importers.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/dev/adding_metacommands.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/dev/architecture.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/getting-started/installation.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/getting-started/requirements.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/getting-started/syntax.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/guides/debugging.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/guides/documentation.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/guides/encoding.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/guides/examples.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/guides/formatter.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/guides/logging.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/guides/sql_syntax.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/guides/usage.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/guides/using_scripts.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/Compare_planets.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/actions.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/actions2.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/checkboxes.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/connect.b64 +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/connect.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/create_conf.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/data_error1_screenshot.jpg +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/entry_form.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/execsql_console.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/execsql_logo_01.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/fatals.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/logo_small.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/pause_terminal.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/pause_terminal_sm.b64 +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/pause_terminal_sm.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/prompt_compare.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/set_build_commands.jpg +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/unit_conversions.b64 +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/unit_conversions_029.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/unmatched.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/images/vim_execsql_highlight.png +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/index.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/docs/reference/security.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/extras/vscode-execsql/README.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/extras/vscode-execsql/package.json +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/justfile +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/scripts/generate_vscode_grammar.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/__main__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/cli/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/cli/dsn.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/cli/help.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/cli/lint.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/cli/run.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/access.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/dsn.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/factory.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/firebird.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/mysql.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/oracle.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/postgres.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/db/sqlserver.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/debug/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/debug/repl.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exceptions.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/base.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/delimited.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/duckdb.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/feather.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/html.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/json.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/latex.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/markdown.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/ods.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/parquet.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/pretty.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/protocol.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/raw.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/sqlite.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/templates.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/values.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/xls.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/xlsx.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/xml.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/yaml.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/exporters/zip.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/format.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/gui/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/importers/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/importers/base.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/importers/csv.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/importers/feather.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/importers/json.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/importers/ods.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/importers/xls.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/connect.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/control.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/data.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/debug.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/dispatch.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/io.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/io_fileops.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/io_write.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/prompt.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/script_ext.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/metacommands/system.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/py.typed +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/script/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/script/control.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/script/variables.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/state.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/utils/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/utils/auth.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/utils/crypto.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/utils/gui.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/utils/mail.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/utils/numeric.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/utils/regex.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/utils/strings.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/src/execsql/utils/timer.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/README.md +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/config_settings.sqlite +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/example_config_prompt.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/execsql.conf +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/make_config_db.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/md_compare.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/md_glossary.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/md_upsert.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/pg_compare.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/pg_glossary.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/pg_upsert.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/script_template.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/ss_compare.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/ss_glossary.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/templates/ss_upsert.sql +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/cli/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/cli/test_cli.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/cli/test_cli_e2e.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/cli/test_cli_run.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/cli/test_lint.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/cli/test_ping.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/cli/test_profile.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/conftest.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/db/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/db/test_base.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/db/test_duckdb.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/db/test_factory.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/db/test_postgres.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/db/test_sqlite.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_base.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_db.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_delimited.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_duckdb_exporter.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_exporters.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_feather.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_html_extended.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_html_latex.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_json.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_json_extended.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_latex_extended.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_markdown.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_ods.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_parquet.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_pretty_extended.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_raw_extended.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_sqlite_exporter.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_templates.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_templates_extended.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_values_extended.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_xls_xlsx.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_xlsx.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_xml.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_yaml.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/exporters/test_zip.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/gui/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/gui/test_backends.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/importers/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/importers/test_base_extended.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/importers/test_csv_importer.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/importers/test_feather_importer.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/importers/test_json_importer.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/importers/test_ods_importer.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/importers/test_xls_importer.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/integration/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/integration/conftest.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/integration/test_dsn.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/integration/test_duckdb.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/integration/test_mysql.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/integration/test_postgres.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/integration/test_sqlite.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_assert.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_breakpoint.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_connect.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_io_export.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_metacommands_connect.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_metacommands_data.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_metacommands_extended.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_metacommands_io.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_metacommands_script_ext.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_metacommands_system.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_metacommands_system_extra.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/metacommands/test_row_count.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_config.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_config_data.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_error_messages.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_exceptions.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_format.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_mail.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_models.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_package.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_registry.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_script.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_state.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/test_types.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/__init__.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_auth.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_auth_extra.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_crypto.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_errors_extra.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_fileio.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_numeric.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_regex.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_strings.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_timer.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/tests/utils/test_timer_extra.py +0 -0
- {execsql2-2.15.0 → execsql2-2.15.2}/zensical.toml +0 -0
|
@@ -33,12 +33,8 @@ coverage.xml
|
|
|
33
33
|
.tox/
|
|
34
34
|
htmlcov/
|
|
35
35
|
execsql.log
|
|
36
|
-
scripts/
|
|
37
|
-
scripts
|
|
38
|
-
scripts/test_import_sqlite.sql
|
|
39
|
-
scripts/test_script.sql
|
|
40
|
-
scripts/test.db
|
|
41
|
-
scripts/*.log
|
|
36
|
+
!scripts/generate_vscode_grammar.py
|
|
37
|
+
scripts/
|
|
42
38
|
|
|
43
39
|
# Distribution
|
|
44
40
|
*.whl
|
|
@@ -48,5 +44,6 @@ scripts/*.log
|
|
|
48
44
|
_execsql/
|
|
49
45
|
|
|
50
46
|
# Claude
|
|
51
|
-
.claude/
|
|
47
|
+
.claude/
|
|
52
48
|
ANALYSIS.md
|
|
49
|
+
FINDINGS.md
|
|
@@ -13,6 +13,63 @@ ______________________________________________________________________
|
|
|
13
13
|
|
|
14
14
|
______________________________________________________________________
|
|
15
15
|
|
|
16
|
+
## [2.15.2] - 2026-04-14
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- `DT_Integer`, `DT_Float`, and `DT_Decimal` data type matchers now use pre-compiled regex class attributes instead of recompiling on every call — reduces overhead during large imports.
|
|
21
|
+
- `DT_Boolean` match tuples are now cached and only rebuilt when the `boolean_words`/`boolean_int` config changes, instead of on every `_is_match()`/`_from_data()` call.
|
|
22
|
+
- SQLite and DuckDB adapter methods (`table_exists`, `table_columns`, `view_exists`, `schema_exists`) now use the `_cursor()` context manager to prevent cursor leaks on exceptions.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- `DT_Text.data_type_name` corrected from `"character"` to `"text"` — error messages now correctly identify the text data type instead of showing "character".
|
|
27
|
+
- `DT_Varchar._from_data()` now converts non-string data to string and enforces the 255-character length limit. Previously, non-string values passed through without conversion or length check.
|
|
28
|
+
- `WriteHooks.write_err()` no longer crashes on empty string input.
|
|
29
|
+
- `CondAstNode.eval()` now raises `CondParserError` for unknown node types instead of silently returning `None`.
|
|
30
|
+
- `NumericAstNode.eval()` now raises `NumericParserError` on division by zero instead of an unhandled `ZeroDivisionError`.
|
|
31
|
+
|
|
32
|
+
______________________________________________________________________
|
|
33
|
+
|
|
34
|
+
## [2.15.1] - 2026-04-14
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- Cell-level diff marking in `PROMPT COMPARE` dialog — when "Highlight Diffs" is toggled, differing cells within changed rows are prefixed with a bullet marker so users can see exactly which columns differ. Works across all three backends (Tkinter, Textual, and console).
|
|
39
|
+
- `macos_config_file` option in `execsql.conf` `[config]` section — specifies an additional configuration file to read on macOS (`sys.platform == "darwin"`). Behaves identically to `linux_config_file` with tilde expansion support.
|
|
40
|
+
- EXPORT operations now log structured `action` records to `execsql.log` with the query name, output file, and source line number.
|
|
41
|
+
|
|
42
|
+
### Removed
|
|
43
|
+
|
|
44
|
+
- `Logger.log_action_prompt_quit()` — dead code inherited from upstream, never called. Prompt halt events are already captured by `log_exit_halt()`.
|
|
45
|
+
- `constants.py` — 370 lines of map tile servers, XBM bitmaps, and X11 color names never imported by any module. Vestigial from the upstream monolith.
|
|
46
|
+
- `Tz` class in `types.py` — custom `tzinfo` subclass orphaned by the `python-dateutil` migration.
|
|
47
|
+
- Duplicate `file_size_date()`, `chainfuncs()`, and `as_none()` definitions in `conditions.py` — canonical versions in `utils/errors.py`. `chainfuncs()` and `as_none()` were also removed from `utils/errors.py` as they had zero callers.
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- `linux_config_file` config option now only applies on Linux (`sys.platform == "linux"`), not all POSIX systems. macOS users should use the new `macos_config_file` option instead.
|
|
52
|
+
- Date/time parsing now uses `python-dateutil` instead of 231 hardcoded `strptime` format strings. Handles ISO 8601 with `T` separator, microseconds, `Z` suffix, and named timezones that the old format list could not parse.
|
|
53
|
+
- Refactored `ConfigData` to use private helper methods (`_get_str`, `_get_enum`, `_get_bool`, `_get_int`, `_get_float`) — reduces ~370 lines of repetitive option parsing to ~80 lines with identical behavior.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- `NumericParser` now uses left-associative parsing for arithmetic operators. Previously, right-recursive descent caused `10 - 3 - 2` to evaluate as `10 - (3 - 2) = 9` instead of the correct `(10 - 3) - 2 = 5`. Same fix for division.
|
|
58
|
+
- Operator precedence bug in `DataTable` and `Database.populate_table()` empty-column check — a redundant `and conf.del_empty_cols` inside an already-guarded block caused incorrect short-circuit evaluation due to Python operator precedence.
|
|
59
|
+
- SQLite `populate_table()` now applies `trim_strings`, `replace_newlines`, and `empty_strings` processing before extracting column data. Previously, processing was applied after the insert data was copied, so trimming and null-conversion never took effect.
|
|
60
|
+
- `$CURRENT_DATABASE` and `$CURRENT_DBMS` system variables now refresh on `USE` metacommand. Previously they were only set at startup and on `CONNECT`, becoming stale after switching the active database with `USE`.
|
|
61
|
+
- Documentation: `$CONSOLE_WAIT_WHEN_ERROR_HALT_STATE` variable name corrected in substitution variables reference (was incorrectly documented as `$CONSOLE_WAIT_WHEN_ERROR_STATE`).
|
|
62
|
+
- `PROMPT COMPARE` diff logic now uses native Python equality instead of string comparison — `int(1)` vs `float(1.0)`, `Decimal("10.00")` vs `Decimal("10.0")`, and `True` vs `1` are correctly treated as equal instead of producing false diffs.
|
|
63
|
+
- `PROMPT COMPARE` diff logic now treats `None` (SQL NULL) as distinct from empty string `""`. Previously both were normalized to `""` and compared as equal.
|
|
64
|
+
- `PROMPT COMPARE` summary stats now match by column name instead of position — tables with the same columns in different order no longer produce false diffs.
|
|
65
|
+
- `PROMPT COMPARE` summary stats no longer include key columns in the diff comparison — only non-key shared columns are compared, consistent with the cell-level diff engine.
|
|
66
|
+
- `PROMPT COMPARE` diff engine now keeps the first row when duplicate PK values exist, instead of silently using the last.
|
|
67
|
+
- `compare_stats()` now delegates to `compute_row_diffs()` so the summary line and cell-level highlighting always agree.
|
|
68
|
+
- `PG_UPSERT` metacommand no longer writes pg-upsert output to `execsql.log`. Logging now only goes to the file specified by the `LOGFILE` keyword.
|
|
69
|
+
- `win_config_file` config option now works on Windows. Previously checked `os.name == "windows"` which is never true (Python returns `"nt"`). Inherited from upstream.
|
|
70
|
+
|
|
71
|
+
______________________________________________________________________
|
|
72
|
+
|
|
16
73
|
## [2.15.0] - 2026-04-09
|
|
17
74
|
|
|
18
75
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.15.
|
|
3
|
+
Version: 2.15.2
|
|
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
|
|
@@ -39,6 +39,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
39
39
|
Classifier: Topic :: Database
|
|
40
40
|
Classifier: Topic :: Database :: Front-Ends
|
|
41
41
|
Requires-Python: >=3.10
|
|
42
|
+
Requires-Dist: python-dateutil>=2.8
|
|
42
43
|
Requires-Dist: rich>=13.0
|
|
43
44
|
Requires-Dist: sqlglot>=25.0
|
|
44
45
|
Requires-Dist: textual>=0.47.0
|
|
@@ -63,13 +63,15 @@ ______________________________________________________________________
|
|
|
63
63
|
|
|
64
64
|
New options in `execsql.conf`:
|
|
65
65
|
|
|
66
|
-
| Option | Section
|
|
67
|
-
| -------------------------- |
|
|
68
|
-
| `use_keyring` | `[connect]`
|
|
69
|
-
| `show_progress` | `[input]`
|
|
70
|
-
| `import_progress_interval` | `[input]`
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
66
|
+
| Option | Section | Description |
|
|
67
|
+
| -------------------------- | ------------- | ----------------------------------------------------------------- |
|
|
68
|
+
| `use_keyring` | `[connect]` | Use the OS keyring for credential storage (default: `yes`). |
|
|
69
|
+
| `show_progress` | `[input]` | Enable Rich progress bar for IMPORT (default: `no`). |
|
|
70
|
+
| `import_progress_interval` | `[input]` | Log a status line every N rows during IMPORT (default: `0`). |
|
|
71
|
+
| `gui_framework` | `[interface]` | GUI backend: `tkinter` (default) or `textual` (terminal UI). |
|
|
72
|
+
| `log_sql` | `[config]` | Enable SQL audit logging (default: `no`). |
|
|
73
|
+
| `max_log_size_mb` | `[config]` | Rotate the log file at this size in MB (default: `0` = disabled). |
|
|
74
|
+
| `macos_config_file` | `[config]` | Additional config file path, active only on macOS. |
|
|
73
75
|
|
|
74
76
|
### Tools
|
|
75
77
|
|
|
@@ -79,14 +81,15 @@ New options in `execsql.conf`:
|
|
|
79
81
|
|
|
80
82
|
### GUI
|
|
81
83
|
|
|
82
|
-
| Feature | Description
|
|
83
|
-
| -------------------- |
|
|
84
|
-
| Textual TUI backend | Full terminal-UI backend via the `textual` library. Provides all dialog types (password, pause, message, entry, compare, action, etc.) in the terminal.
|
|
85
|
-
| Console fallback | Text-only backend that handles GUI calls in headless environments by printing to stdout.
|
|
86
|
-
| Table row counts | All GUI backends (Tkinter, Textual, Console) display a row count footer below every table widget (e.g. "3 rows", "1 row").
|
|
87
|
-
| Help URL button | Dialogs that accept the `HELP` keyword display a clickable Help button that opens the URL in the system browser.
|
|
88
|
-
| Compare diff summary | The compare dialog shows a one-line summary of matching, differing, and table-exclusive rows when key columns are specified.
|
|
89
|
-
|
|
|
84
|
+
| Feature | Description |
|
|
85
|
+
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
86
|
+
| Textual TUI backend | Full terminal-UI backend via the `textual` library. Provides all dialog types (password, pause, message, entry, compare, action, etc.) in the terminal. |
|
|
87
|
+
| Console fallback | Text-only backend that handles GUI calls in headless environments by printing to stdout. |
|
|
88
|
+
| Table row counts | All GUI backends (Tkinter, Textual, Console) display a row count footer below every table widget (e.g. "3 rows", "1 row"). |
|
|
89
|
+
| Help URL button | Dialogs that accept the `HELP` keyword display a clickable Help button that opens the URL in the system browser. |
|
|
90
|
+
| Compare diff summary | The compare dialog shows a one-line summary of matching, differing, and table-exclusive rows when key columns are specified. |
|
|
91
|
+
| Compare cell markers | When diff highlighting is active, individual cells that differ within a changed row are prefixed with a bullet marker across all backends (Tkinter, Textual, console). |
|
|
92
|
+
| Form validation | `PROMPT ENTRY_FORM` enforces `validation_regex` (on submit) and `validation_key_regex` (per-keystroke) across all backends. Required fields validated. |
|
|
90
93
|
|
|
91
94
|
### Authentication
|
|
92
95
|
|
|
@@ -107,11 +110,12 @@ New options in `execsql.conf`:
|
|
|
107
110
|
|
|
108
111
|
### Developer / Packaging
|
|
109
112
|
|
|
110
|
-
| Feature
|
|
111
|
-
|
|
|
112
|
-
| VS Code syntax highlighting
|
|
113
|
-
| `py.typed` marker
|
|
114
|
-
| Structured keyword registry
|
|
113
|
+
| Feature | Description |
|
|
114
|
+
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
115
|
+
| VS Code syntax highlighting | Auto-generated `tmLanguage.json` grammar from the dispatch table. |
|
|
116
|
+
| `py.typed` marker | PEP 561 marker enabling downstream static type checking. |
|
|
117
|
+
| Structured keyword registry | `--dump-keywords` introspects the dispatch table and outputs JSON used by the grammar generator and test suite. |
|
|
118
|
+
| `python-dateutil` dependency | Date/time parsing delegates to `dateutil.parser.parse()` instead of 231 hardcoded `strptime` format strings. Handles ISO 8601 `T` separators, microseconds, `Z` suffix, and named timezones. |
|
|
115
119
|
|
|
116
120
|
### Debugging { #debugging }
|
|
117
121
|
|
|
@@ -161,6 +165,10 @@ ______________________________________________________________________
|
|
|
161
165
|
|
|
162
166
|
The CLI framework changed from `optparse` to [Typer](https://typer.tiangolo.com/) with Rich-formatted help text. All original short flags (`-a` through `-z`) are preserved. The tool can be invoked as either `execsql` or `execsql2`.
|
|
163
167
|
|
|
168
|
+
### Configuration
|
|
169
|
+
|
|
170
|
+
- **`linux_config_file`** — now only active on Linux (`sys.platform == "linux"`). Upstream applied it to all POSIX systems, including macOS. A new `macos_config_file` option handles macOS specifically.
|
|
171
|
+
|
|
164
172
|
### Internal State Management
|
|
165
173
|
|
|
166
174
|
All 33 mutable runtime globals in `state.py` have been consolidated into a `RuntimeContext` object. The module uses a transparent proxy so existing code is unaffected, but the architecture now supports isolated contexts for testing and future concurrent execution.
|
|
@@ -223,17 +231,28 @@ These are behavioral changes driven by security or correctness issues in the ups
|
|
|
223
231
|
|
|
224
232
|
### Bug Fixes
|
|
225
233
|
|
|
226
|
-
| Area
|
|
227
|
-
|
|
|
228
|
-
| Oracle default port
|
|
229
|
-
| MySQL `LOAD DATA INFILE` encoding
|
|
230
|
-
| `dt_cast` type converters
|
|
231
|
-
| `FileWriter` CPU busy-loop
|
|
232
|
-
| Substitution variable cycles
|
|
233
|
-
| Script location in error messages
|
|
234
|
-
| `$ERROR_MESSAGE` not updated
|
|
235
|
-
| Metacommand error message lost
|
|
236
|
-
| Empty script name in error msg
|
|
234
|
+
| Area | Fix |
|
|
235
|
+
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
236
|
+
| Oracle default port | Corrected from `5432` (PostgreSQL) to `1521`. |
|
|
237
|
+
| MySQL `LOAD DATA INFILE` encoding | Python encoding names are now mapped to MySQL charset names. |
|
|
238
|
+
| `dt_cast` type converters | Base `Database` class auto-populates 8 type converters that were previously left empty after the refactor. |
|
|
239
|
+
| `FileWriter` CPU busy-loop | Uses blocking `queue.get(timeout=0.1)` instead of `get_nowait()` in a tight loop. |
|
|
240
|
+
| Substitution variable cycles | 100-iteration limit prevents infinite loops on cyclic variable references. |
|
|
241
|
+
| Script location in error messages | `ErrInfo.script_file` and `script_line_no` are now populated via `stamp_errinfo()` so error output includes "Line N of script foo.sql" context — restoring behavior present in the monolith. |
|
|
242
|
+
| `$ERROR_MESSAGE` not updated | `$ERROR_MESSAGE` is now set on every error path: `exit_now()`, non-halting SQL errors, and non-halting metacommand errors. Previously it was initialized to `""` and never changed. |
|
|
243
|
+
| Metacommand error message lost | When `halt_on_metacommand_err` is `ON`, the original handler `ErrInfo` is now re-raised; the generic "Unknown metacommand" message no longer replaces the specific error from the handler. |
|
|
244
|
+
| Empty script name in error msg | `_execute_script_direct()` and `_execute_script_textual_console()` no longer append "in script , line 0" to uncaught-exception messages when `current_script_line()` returns an empty string. |
|
|
245
|
+
| `PROMPT COMPARE` diff comparison | Diff engine uses native Python equality instead of string comparison — numeric types, Decimals, and booleans compare correctly. `None` is distinguished from empty string. Columns are matched by name (not position), key columns are excluded from comparison, and duplicate PKs keep the first row. |
|
|
246
|
+
| `win_config_file` broken | Checked `os.name == "windows"` which Python never returns (correct value is `"nt"`). Fixed to `os.name == "nt"`. Inherited from upstream. |
|
|
247
|
+
| `NumericParser` right-associative | Arithmetic operators were parsed right-to-left. `10 - 3 - 2` evaluated as `9` instead of `5`. Fixed to left-associative parsing. Inherited from upstream. |
|
|
248
|
+
| Empty-column check precedence | `DataTable` and `Database.populate_table()` had an operator precedence bug in the extra-column emptiness check — a redundant `and conf.del_empty_cols` caused incorrect short-circuit evaluation. Inherited from upstream. |
|
|
249
|
+
| SQLite import string processing | `SQLiteDatabase.populate_table()` applied `trim_strings`, `replace_newlines`, and `empty_strings` after copying row data, so processing never reached the INSERT. Fixed to process before extraction. Inherited from upstream. |
|
|
250
|
+
| `$CURRENT_DATABASE`/`$CURRENT_DBMS` stale after USE | These variables were only set at startup and on CONNECT, not refreshed when `USE` switched the active database. Now set in `set_static_system_vars()` so they update on any connection change. |
|
|
251
|
+
| `DT_Text.data_type_name` wrong | Was `"character"` (same as `DT_Character`), making error messages indistinguishable. Corrected to `"text"`. Inherited from upstream. |
|
|
252
|
+
| `DT_Varchar` non-string data unchecked | `_from_data()` only enforced the 255-char limit for `str` inputs; non-string values passed through without conversion or length check. Inherited from upstream. |
|
|
253
|
+
| `WriteHooks.write_err()` crash on empty string | `strval[-1]` raised `IndexError` on empty input. Fixed to use `str.endswith()`. Inherited from upstream. |
|
|
254
|
+
| `NumericParser` division by zero | `NumericAstNode.eval()` raised unhandled `ZeroDivisionError`. Now raises `NumericParserError` with a clear message. Inherited from upstream. |
|
|
255
|
+
| `CondAstNode.eval()` could return `None` | Missing fallthrough for unknown node types silently returned `None`. Now raises `CondParserError`. Inherited from upstream. |
|
|
237
256
|
|
|
238
257
|
______________________________________________________________________
|
|
239
258
|
|
|
@@ -312,7 +312,10 @@ The section and property names that may be used in a configuration file are list
|
|
|
312
312
|
: The number of seconds that *execsql* should wait between the time that a query is created in Access (which uses DAO) and the time that the next statement is executed using ODBC. This value must be greater than or equal to 5.0. The default is `5.0`.
|
|
313
313
|
|
|
314
314
|
`linux_config_file`
|
|
315
|
-
: The full name or path to an additional configuration file to be read if *execsql* is running on Linux. If only a path is specified, the name of the configuration file should be `execsql.conf`. The configuration file specified will be read immediately following the configuration file in which it is named. No configuration file will be read more than once. If the name or path are invalid, this setting will be silently ignored. This setting may include [substitution variables](substitution_vars.md#substitution_vars); at the time that configuration files are read, however, only environment variables and system variables related to the script name and path are defined.
|
|
315
|
+
: The full name or path to an additional configuration file to be read if *execsql* is running on Linux (`sys.platform == "linux"`). If only a path is specified, the name of the configuration file should be `execsql.conf`. The configuration file specified will be read immediately following the configuration file in which it is named. No configuration file will be read more than once. If the name or path are invalid, this setting will be silently ignored. This setting may include [substitution variables](substitution_vars.md#substitution_vars); at the time that configuration files are read, however, only environment variables and system variables related to the script name and path are defined.
|
|
316
|
+
|
|
317
|
+
`macos_config_file`
|
|
318
|
+
: The full name or path to an additional configuration file to be read if *execsql* is running on macOS (`sys.platform == "darwin"`). Behaves identically to `linux_config_file` but is only active on macOS. Tilde expansion (`~`) is supported.
|
|
316
319
|
|
|
317
320
|
`log_sql` { #log_sql }
|
|
318
321
|
: When set to "Yes", all executed SQL statements are written to the log file with a `sql` record type, including the database name, line number, and query text. The property value should be either "Yes" or "No". The default is "No". This can also be enabled via the `CONFIG LOG_SQL` metacommand.
|
|
@@ -2342,6 +2342,8 @@ The 'Show mismatches' button will highlight all the rows in each table that have
|
|
|
2342
2342
|
|
|
2343
2343
|

|
|
2344
2344
|
|
|
2345
|
+
The "Highlight Diffs" button toggles row-level coloring (green for matching rows, yellow for changed rows, red for rows only in one table) and cell-level markers — individual cells that differ within a changed row are prefixed with a bullet marker so you can see exactly which columns have different values. A one-line summary of matching, differing, and table-exclusive row counts is shown below the tables. Cell-level diff marking works across all backends (Tkinter, Textual, and console).
|
|
2346
|
+
|
|
2345
2347
|
If the 'Continue' button is selected, the script will continue to run. If the 'Cancel' button is selected, the script will immediately halt unless [CANCEL_HALT](#cancel_halt) is set to OFF. The Enter key also carries out the action of the 'Continue' button, and the Escape key carries out the action of the 'Cancel' button.
|
|
2346
2348
|
|
|
2347
2349
|
If a URL is provided with the HELP keyword, the dialog box will include a button that will open that URL when clicked. The URL must be double-quoted if it contains spaces.
|
|
@@ -75,7 +75,7 @@ $CANCEL_HALT_STATE
|
|
|
75
75
|
$CONSOLE_WAIT_WHEN_DONE_STATE
|
|
76
76
|
: The value of the status flag that is set by the `console_wait_when_done` configuration setting or by the [CONFIG CONSOLE WAIT_WHEN_DONE](metacommands.md#console_wait_when_done) metacommand. The value of this variable is always either "ON" or "OFF".
|
|
77
77
|
|
|
78
|
-
$
|
|
78
|
+
$CONSOLE_WAIT_WHEN_ERROR_HALT_STATE
|
|
79
79
|
: The value of the status flag that is set by the `console_wait_when_error_halt` configuration setting or by the [CONFIG CONSOLE WAIT_WHEN_ERROR](metacommands.md#console_wait_when_error) metacommand. The value of this variable is always either "ON" or "OFF".
|
|
80
80
|
|
|
81
81
|
$COUNTER_x
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "execsql2"
|
|
7
|
-
version = "2.15.
|
|
7
|
+
version = "2.15.2"
|
|
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" }
|
|
@@ -40,6 +40,7 @@ classifiers = [
|
|
|
40
40
|
]
|
|
41
41
|
requires-python = ">=3.10"
|
|
42
42
|
dependencies = [
|
|
43
|
+
"python-dateutil>=2.8",
|
|
43
44
|
"rich>=13.0",
|
|
44
45
|
"sqlglot>=25.0",
|
|
45
46
|
"textual>=0.47.0",
|
|
@@ -161,7 +162,7 @@ skip-magic-trailing-comma = false
|
|
|
161
162
|
line-ending = "auto"
|
|
162
163
|
|
|
163
164
|
[tool.bumpversion]
|
|
164
|
-
current_version = "2.15.
|
|
165
|
+
current_version = "2.15.2"
|
|
165
166
|
commit = true
|
|
166
167
|
commit_args = "--no-verify"
|
|
167
168
|
tag = true
|