Changelog¶
All notable changes to this project will be documented in this file. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Entries prior to 2.0.0 are from the upstream
execsql project by R.Dreas Nielsen.
[Unreleased]¶
[2.19.2] - 2026-06-03¶
Fixed¶
pre-commithookexecsql-formatnow installssqlglotinto its isolated env. Since 2.19.0 movedsqlglotto the[formatter]extra, the hook env (which installs the bare package) was missing it and crashed withModuleNotFoundError: No module named 'sqlglot'. Re-runpre-commit clean && pre-commit install --install-hooksafter upgrading to pick up the new dependency.
[2.19.1] - 2026-06-03¶
Fixed¶
execsql-formatno longer mangles quoted substitution variables:!'!var!'!and!"!var!"!were being parsed by sqlglot asNOToperators (e.g.!'!myvar!'!→NOT NOT '!myvar!'). All three quote forms plus deferred!{var}!are now hidden from SQL formatting.
[2.19.0] - 2026-06-02¶
Fixed¶
IMPORT … FORMAT xlsxrejects zip-bomb workbooks (per-member ratio over 100:1, or total uncompressed size over 500 MB). Convert large workbooks to CSV for import. Legacy.xlsis unaffected.EXPORT … FORMAT hdf5no longer truncatesBIGINTcolumns to 32-bit, andDT_Textcolumns now honour the configuredhdf5_text_len.BREAKPOINTREPL no longer ends the session on a bad SQL statement — errors print inline and the prompt returns.BREAKPOINTREPL handles DML / DDL / transaction-control statements: DML prints(N rows affected), DDL /BEGIN/COMMIT/ROLLBACKprint(statement executed).BREAKPOINTREPL accepts multi-line SQL — input is buffered until a line ends with;..cancel(or Ctrl-C / EOF) discards a partial buffer.
Changed¶
BREAKPOINTREPL dispatch is now two-way: input starting with.is a REPL command, everything else is SQL. Bare-name variable lookup is removed — use.vars VAR(e.g..vars logfile,.vars $ARG_1) to print one variable;.varsalone still lists all.sqlglotmoved to the new[formatter]extra. Installexecsql2[formatter]to useexecsql-format's SQL pass;execsql-format --no-sqlworks without.textualdependency floor raised to>=1.0(was>=0.47.0).
[2.18.1] - 2026-05-28¶
Changed¶
- Internal:
execsql.cli.lint_asthas been folded intoexecsql.cli.lint; the AST walker entry point is nowexecsql.cli.lint.lint(). Code that importedexecsql.cli.lint_ast.lint_astshould importexecsql.cli.lint.lintinstead.
Removed¶
- Internal: the unused
run_when_falseandrun_in_batchflags onMetaCommand(and the matching keyword arguments onMetaCommandList.add()) — neither has been consulted since v2.16.0. Code that still passes either kwarg tomcl.add()will raiseTypeError.
[2.18.0] - 2026-05-27¶
Added¶
IS_FALSE(<value>)conditional predicate — recognisesNo,N,False,F, and0as falsy (case-insensitive); inverse ofIS_TRUE. Previously documented but not implemented, soIF (IS_FALSE(...))raisedCondParserError.--no-rm-fileand--no-serveCLI flags disable theRM_FILEandSERVEmetacommands, symmetric with the existing--no-system-cmd. Matchingallow_rm_fileandallow_serveconfig keys are honoured in the[config]section ofexecsql.conf.- New
include_root,serve_root, andtemplate_rootconfig keys in the[config]section ofexecsql.conf. When set,INCLUDE/EXECUTE SCRIPT,SERVE, and Jinja2 /string.Templateloaders confine resolved paths under the named root and reject anything that escapes via.., absolute paths, drive letters, or UNC paths. Database.quote_literal(value)andDatabase.quote_qualified_identifier(*parts)helpers on the baseDatabaseclass. The defaultquote_literalescapes\and doubles'and rejects NUL bytes; subclasses can override for dialect-specific literal forms.Database.needs_explicit_commit_after_ddl()andDatabase.auto_commits_ddl()capability hooks. Firebird overrides the first (its driver leaves DDL pending until commit). Oracle, MySQL, SQL Server, and MS Access override the second (their drivers implicitly commit DDL —rollback()is a silent no-op for transactions whose boundary the DDL crossed).EncodedFilenow supports the context-manager protocol (with EncodedFile(...) as fh:); callers no longer have to remember an explicitclose()in atry/finallyblock.~/execsql.logis now created with mode0o600on POSIX so the substituted SQL,-avalues, env vars, and DSN URLs it captures are not world-readable. Previously the file inherited the umask default (typically0o644).-a NAME VALUEsubstitution-variable assignments are redacted to***in the log when the value contains a sensitive substring (PASSWORD,SECRET,TOKEN,PASSWD,PRIVATE_KEY,CREDENTIAL).- A warning is now printed when the
--dsnURL contains an embedded password, since it remains visible inps, shell history, and process accounting. EXPORT … FORMAT xlsxandIMPORT … FORMAT xlsxnow reject zip-bomb XLSX files via a newcheck_zip_decompression_ratiohelper that inspects the OOXML zip directory before openpyxl parses the file. Rejects individual members with a compression ratio above 100:1 (default) and aggregate uncompressed size above 500 MB (default).IMPORT … FORMAT odsandEXPORT … FORMAT odsdefuse the stdlib XML parsers viadefusedxml.defuse_stdlib()on firstOdsFileconstruction, protecting odfpy from billion-laughs / external-entity attacks. Thedefusedxmlpackage is now part of the[formats]extra.substitute_vars()now aborts when expanded output exceeds 10 MB (configurable via the newmax_substitution_byteskey in the[config]section), defending against exponential-expansion bombs where a chain of substitutions accumulates beyond a safe size before the iteration depth cap fires.IMPORT … ODS PATTERN <regex>andIMPORT … XLS PATTERN <regex>now raise a friendlyErrInfolisting the invalid pattern instead of letting an uncaughtre.errorbubble up fromre.compile.IMPORT … FROM JSONwith JSON Lines (JSONL) now reads the file line-by-line instead of buffering the entire text alongside the parsed records. The standard JSON-array path is unchanged (would require anijsondependency to stream).- New
execsql.utils.auth.is_plaintext_keyring()helper detects when the active OS keyring backend stores secrets in cleartext (e.g.keyrings.alt.file.PlaintextKeyringon headless Linux without a real Secret Service). The internal_keyring_set()path now emits a one-time stderr warning before writing into a plaintext backend so users know stored passwords are not meaningfully protected at rest. - On POSIX systems without
$DISPLAYor$WAYLAND_DISPLAY,enable_gui()now skips the Tkinter backend entirely and falls through to the Textual / Console backends, instead of failing with a cryptic_tkinter.TclErrorthat the broad-except previously swallowed. - Internal:
.github/workflows/ci-cd.ymlnow SHA-pins all third-party GitHub Actions with a trailing# vX.Y.Zcomment; new.github/dependabot.ymlfiles weekly bump PRs grouping minor/patch action updates. - Documented
$CURRENT_DATEand$CURRENT_SCRIPT_LINEsubstitution variables indocs/reference/substitution_vars.md; the[map]extra in the README installation list;RUN SCRIPTas an alias forEXECUTE SCRIPTindocs/reference/metacommands.md. All were functional, just undocumented. - Expanded
SECURITY.mdfrom a stub-policy page to a defense-in-depth catalogue covering substitution-variable quoters, path-containment, SQL-injection mitigations, file-format defenses (XLSX zip-bomb, ODS XML), credential/logging hygiene, and known limitations.
Changed¶
- Bundled
templates/{pg,md,ss}_{upsert,compare,glossary}.sqlnow use the safe!'!#var!'!substitution form instead of'!!#var!!', so single quotes in script-argument values are escaped when interpolated into SQL string literals. --output-diris now a containment boundary, not just a prefix. Absolute paths or..traversals that escape the configured root are rejected. Stdout passes through unchanged. The setting now also applies toEXPORT QUERY,EXPORT … WITH TEMPLATE,EXPORT METADATA, and the multi-sheetEXPORT ODS/EXPORT XLSXvariants, which previously ignored it.
Fixed¶
templates/script_template.sqlhad twoWRITElines (Committing:andCleaning up:) with unterminated double-quoted strings; the closing quotes are now present.ends_with(string, "")now returnsTruefor any string, matching Python'sstr.endswithsemantics. Previously it returnedTrueonly when the haystack was also empty.- ODBC DSN connections now brace-quote the DSN, UID, and PWD attribute values with
{…}(and double any embedded}) so a password or user containing;cannot inject additional connection-string attributes (CWE-91 / ODBC attribute injection). - The
!"!var!"!substitution operator now doubles embedded"so a value likefoo"; DROP TABLE x; --produces a single valid quoted identifier rather than a closing quote followed by a second statement. - The
!'!var!'!substitution operator now always escapes embedded\, not just on Windows. The previous Windows-only branch left MySQL default-mode and PostgreSQL E-string literals open to\'injection from POSIX hosts. - All three substitution forms (
!!var!!,!'!var!'!,!"!var!"!) now reject values containing NUL bytes, which most DBMS wire protocols silently truncate or reject. The check fires only for the variable actually being interpolated — a NUL byte in an unrelated, unreferenced variable no longer blocks every other substitution. EXPORT … FORMAT sqliteandEXPORT … FORMAT duckdbnow identifier-quote the table name inDROP TABLE/INSERT INTOand parameter-bind it in the existence check, closing two SQL-injection-via-tablename sites.- MySQL / MariaDB and SQL Server
Database.quote_identifier()now use the native backtick (`…`) and bracket ([…]) forms respectively, so identifier quoting works even if user SQL has resetsql_mode/QUOTED_IDENTIFIER. IMPORTinto a SQLite database now batches rows and usescursor.executemany()(honouringimport_row_buffer, default 1000) instead of issuing onecursor.execute()per row. Million-row imports are 10–100× faster.MySQL.table_exists(),column_exists(), andview_exists()now honour the server's@@lower_case_table_namessetting: on Linux with the default0, identifiers are compared case-sensitively as before; on Windows/macOS (1) or2, the input name is folded to lowercase so a query liketable_exists("MyTable")matches a row stored asmytable. The server variable is queried once and cached per connection.
Removed¶
EXPORTno longer adds a leading'to CSV / XLSX / ODS string cells starting with=,+,-,@, or tab; exports preserve string values verbatim. Thecsv_safe_formulasconfig key is removed.- Internal: the legacy flat-CommandList linter (
_lint_scriptand helpers inexecsql.cli.lint) has been deleted. The--lintCLI has used the AST-based linter (execsql.cli.lint_ast) since v2.13; only_print_lint_resultsand the issue-constructor helpers remain inexecsql.cli.lint. Breaking change for code that imported_lint_scriptfromexecsql.cli.lintdirectly.
[2.17.3] - 2026-05-26¶
Changed¶
- Optional
[upsert]extra now requirespg-upsert>=1.22.1(was>=1.22.0). 1.22.1 removed upper bounds on itstyperandpyyamldependencies, so installingexecsql2[upsert]alongside the latest Typer/PyYAML no longer triggers a resolver conflict.
[2.17.2] - 2026-05-26¶
Fixed¶
!'!var!'!substitution now wraps the value in single quotes, matching the documented behavior. Previously only embedded apostrophes were doubled.BREAKinside anEXECUTE SCRIPTbody raises an error instead of silently terminating the caller'sLOOP.WRITE SCRIPToutput is now re-includable: nestedIF/LOOP/BATCH/SQLblocks,INCLUDE,EXECUTE SCRIPT, and comments are all preserved, andBEGIN/END SCRIPTlines carry the-- !x!prefix.PROMPT MAPfalls back to the tabular view on any map-widget construction failure (headless display, missing dependencies).TABLE_EXISTS/VIEW_EXISTSagainst SQLite, Oracle, Firebird, and Access now match identifiers case-insensitively per each database's native semantics. Access also moved off the now-restrictedMSysObjectscatalog so the checks work on Access 2016+ default permissions.- Oracle
ROLE_EXISTSworks for non-DBA accounts (falls back tosession_roleswhendba_rolesisn't accessible). - SQL Server connection setup, PostgreSQL / MySQL fast-path
IMPORT, andDatabase.close()no longer crash withAttributeErrorwhen called before the execution log is initialised (library and pre-run code paths). - File-output operations complete instead of hanging if the background
FileWritersubprocess crashes mid-run.
Removed¶
- Internal: legacy command-list execution engine removed. Breaking change for code that imported
CommandList/IfLevelsfromexecsql.scriptor read_state.commandliststack/_state.if_stack/_state.savedscriptsdirectly; migrate to_state.current_localvars()/_state.current_paramvals()and theExecFramedata class on_state.ast_exec_stack.
[2.17.1] - 2026-05-22¶
Fixed¶
- VS Code grammar now highlights the single-quoted (
!'!name!'!) and double-quoted (!"!name!"!) substitution variable variants, not just the bare!!name!!form. Regenerate the bundled grammar withjust install-vscode. - Mermaid diagrams in the docs site now render as SVG (previously plain code blocks).
- Documentation accuracy sweep across
docs/reference/,docs/guides/,docs/getting-started/,docs/about/, anddocs/dev/: fixed nine broken cross-link anchors, corrected ~30 source-module docstrings (stale class/function/extras names), repaired API reference page rendering, and corrected the--profiledescription to mention--profile-limit.
Added¶
- New "Quoting Convention" section in
docs/reference/substitution_vars.mddocumenting howSUB, variable substitution, andEXECUTE SCRIPTargument parsing compose — and the common quote-stripping footgun withwo_quotes(). - Documented eight
DEBUG WRITE …variants, thePROMPT MAPmetacommand, theIS_FALSEconditional, andRUNas an alias forEXECUTEindocs/reference/metacommands.md. All were functional, just undocumented. - Documented five previously-undocumented CLI flags:
--progress,--profile-limit,--no-system-cmd,--config,--init-config.
[2.17.0] - 2026-05-07¶
Changed¶
- Behavior change.
PG_UPSERT,PG_UPSERT QA, andPG_UPSERT CHECKno longer raise a metacommand error when QA checks fail. The outcome is reported via$PG_UPSERT_QA_PASSED,$PG_UPSERT_TABLE_QA_PASSED, and$PG_UPSERT_RESULT_JSON, so the script controls flow withIForASSERT.EXPORT_FAILURESstill runs and the upsert is still skipped on QA failure. Migration: addASSERT !!$PG_UPSERT_QA_PASSED!! = TRUEat the call site to preserve the previous halt-on-failure behavior.
Fixed¶
!!$COUNTER_N!!references inside metacommands (WRITE,IF,SUB, etc.) now return the documented sequence1, 2, 3, …starting at 1. The same fix stabilizes!!$RANDOM!!and!!$UUID!!acrossBREAKdetection and dispatch.
[2.16.18] - 2026-05-05¶
Fixed¶
BEGIN SCRIPTparameter defaults now strip surrounding quotes, matching the existing handling at the call site. A default written asdefault_unit_set="Default"previously bound the literal string"Default"(quotes intact).
Changed¶
SHOW SCRIPTS <name>and.scripts <name>now display the full source path (including<inline>for-cscripts). List views continue to show basenames for column alignment.BEGIN SCRIPT WITH PARAMETERS (...)now accepts quoted default values containing spaces, commas, and other special characters. Unterminated quoted values are now rejected as malformed instead of being silently stored.
[2.16.17] - 2026-05-04¶
Fixed¶
- Formatter no longer treats inline
IF (cond) { command }as a block opener (lines after an inlineIFwere previously indented forever). - Formatter no longer escapes blank lines inside
BEGIN SQL/BEGIN BATCHblocks.
[2.16.16] - 2026-05-02¶
Added¶
--init-configCLI flag prints a defaultexecsql.conftemplate (all options commented out and documented) to stdout. Useexecsql --init-config > execsql.confto bootstrap.--no-system-cmdCLI flag disablesSYSTEM_CMD/SHELL. Also configurable viaallow_system_cmd = Noin[config]orallow_system_cmd=Falsein the library API.
Changed¶
- CLI
--helpnow groups options by category: connection, encoding, import/export, execution, GUI, configuration, information. execsql.conftemplate updated: added missing options (use_keyring,gui_framework,allow_system_cmd,log_sql,max_log_size_mb,show_progress,import_progress_interval,macos_config_file), fixed incorrect defaults (password_prompt,new_db,scan_lines), added DuckDB (k) to database types.
Fixed¶
SYSTEM_CMDno longer wraps arguments containing&in spurious double quotes (a Windowscmd.exeworkaround inherited from upstream that broke non-cmdtargets).
[2.16.15] - 2026-05-02¶
Changed¶
- Merged
SHOW SCRIPTSandSHOW SCRIPT <name>intoSHOW SCRIPTS [<name>]. Without a name, lists all registered scripts; with a name, shows detail.
[2.16.14] - 2026-05-01¶
Fixed¶
ELSEIFconditions now supportANDIF/ORIFmodifiers (previously silently attached to the parentIF).- Unknown AST node types now raise an error instead of being silently ignored.
- Cursor leak in
select_rowsource()andselect_rowdict(): cursor is now closed on query failure;EXPORTandCOPYexplicitly close the row generator on error.
[2.16.13] - 2026-05-01¶
Added¶
execsql-format:--indentnow controls SQL indentation in addition to metacommand indentation.execsql-format: new--leading-commaflag places commas at the start of lines.
Fixed¶
execsql-format: comments interleaved within multi-line SQL no longer corrupt the formatted output. Statements are no longer split at comment boundaries (which previously turned commas into semicolons and dropped content silently).execsql-format:/* */block comments containing-- !x!metacommand markers are no longer mangled.execsql-format: blank lines within multi-line SQL no longer split the statement into independent format blocks.execsql-format: if sqlglot produces more or fewer statements than the input, the formatter falls back to the original text instead of emitting corrupted SQL.
[2.16.12] - 2026-05-01¶
Changed¶
- Internal: added parser test coverage for
SHOW SCRIPTSand default-parameter handling. No user-visible changes.
[2.16.11] - 2026-05-01¶
Fixed¶
- Multi-line
/* */block comment docstrings inBEGIN SCRIPTare now captured in full (the doc collector previously classified comment continuation lines as non-comment and stopped early).
[2.16.10] - 2026-05-01¶
Fixed¶
EXECUTE SCRIPT !!#script_name!!(variable-substituted script target) now works. The parser regex previously rejected non-literal identifiers, causing dispatch to fail with "should be handled by the AST executor".
[2.16.9] - 2026-05-01¶
Added¶
SHOW SCRIPTSmetacommand lists all registered SCRIPT definitions with parameter signatures and source locations.SHOW SCRIPT <name>shows detail for one SCRIPT (parameters, source file/lines, docstring)..scriptsand.scripts <name>REPL commands — same as the metacommands.- Default parameter values:
BEGIN SCRIPT load(schema, table, batch=1000). Parameters with defaults can be omitted at the call site. Required parameters must precede optional ones. - Automatic docstring extraction for SCRIPT blocks.
--or/* */comments immediately afterBEGIN SCRIPTare captured as documentation; a blank line terminates it. Displayed bySHOW SCRIPTS,SHOW SCRIPT, and.scripts.
[2.16.8] - 2026-04-30¶
Fixed¶
- SQL comments (
--and/* */) inside multi-line SQL statements no longer split the statement. Comments between SELECT columns or before CASE clauses are now preserved as part of the statement text.
[2.16.7] - 2026-04-30¶
Fixed¶
ANDIF/ORIFconditions now short-circuit.IF (sub_defined(x)) ANDIF (not sub_empty(x))previously evaluatedsub_emptyeven whensub_definedreturned false, throwing "Unrecognized substitution variable" on undefined variables.IF,LOOP, andINCLUDEerror reports now show the correct source line instead of the previous command's location.
[2.16.6] - 2026-04-30¶
Fixed¶
execsql-formatno longer corrupts PL/pgSQL function bodies inside$$-delimited blocks. sqlglot was rewritingIF NOT EXISTS … END IFand similar PL/pgSQL constructs asCOMMIT;; the formatter now skips sqlglot for any block containing dollar-quoted content.- Debug REPL
.varsnow shows~local and#param variables from the current stack frame, not just globals..vars ~myvarand.set ~myvar valuealso read/write the stack frame's local scope.
[2.16.5] - 2026-04-30¶
Fixed¶
- Debug REPL
.vars,.setnow read/write~local and#param variables from the current stack frame instead of globals only.
[2.16.4] - 2026-04-30¶
Fixed¶
- Forward references in SCRIPT blocks now work:
EXECUTE SCRIPT foocan appear beforeBEGIN SCRIPT fooin the same file orINCLUDE'd file. The AST executor pre-scans for SCRIPT definitions, matching the legacy engine's two-pass behavior.
[2.16.3] - 2026-04-30¶
Fixed¶
BEGIN SCRIPT name(params)without a space before the opening parenthesis now parses correctly. The previous regex required whitespace and silently ignored the SCRIPT block, causingEND SCRIPTto fail.
[2.16.2] - 2026-04-30¶
Fixed¶
INCLUDEwith quoted paths (e.g.-- !x! INCLUDE "!!path!!/file.sql") now strips the surrounding quotes before resolving the file path.
[2.16.1] - 2026-04-30¶
Fixed¶
~(local) and+(outer-scope) substitution variables inside SCRIPT blocks now work correctly. Previously these wrote to a disconnected scope, causing the variable to be invisible to subsequent SQL and producing spurious "potential un-substituted variable" warnings.EXECUTE SCRIPTargument expressions likeval=!!#parent_param!!are now expanded in the caller's scope before the child frame is created, fixing nested script calls that pass~or#variables as arguments.
Changed¶
RuntimeContextis now stored inthreading.local()instead of a module-level global, making concurrentfrom execsql import runcalls thread-safe.
[2.16.0] - 2026-04-29¶
Added¶
--parse-treeCLI flag — parses a script into an Abstract Syntax Tree and prints a visual tree showing block nesting (IF/LOOP/BATCH/SCRIPT), source line ranges, compound conditions, and all metacommands. No database connection required.- Plugin system (
execsql.plugins) for extending execsql with custom metacommands, exporters, and importers via Python entry points:execsql.metacommands,execsql.exporters,execsql.importers. Discovered automatically at startup. --list-pluginsCLI flag shows all discovered plugins.- Python library API:
from execsql import runfor programmatic script execution from notebooks, pipelines, and applications. Returns aScriptResultwith success/failure, command count, timing, errors, and final variable state. Supports DSN strings, pre-existing connections, substitution variables, and error control. - Deprecation warning for
enc_passwordin config files — advises switching to keyring or environment variables. - Sensitive environment variables (
*SECRET*,*TOKEN*,*PASSWORD*, etc.) are now filtered from&-prefixed substitution variable exposure.
Changed¶
- Execution engine replaced. The legacy flat command-list engine has been replaced by the AST-based executor. Scripts are parsed into a tree of typed nodes and walked for execution.
INCLUDE'd files are parsed and executed natively with circular-include detection. Transparent to users. BREAKoutsideLOOPis now an error (exit 1) instead of being silently ignored.--lintnow uses the AST parser for structural validation. UnmatchedIF/LOOP/BATCH/SCRIPTblocks are caught at parse time with precise line ranges. No database connection required.- Default database type changed from Access (
-t a) to SQLite (-t l). Users targeting Access should pass-t aexplicitly.
Fixed¶
- **[Critical]**
WriteSpec.write()andMailSpec.send()error-recovery paths crashed becauseSubVarSet.substitute_all()returns(str, bool)but callers treated it as a plain string. All 14 call sites fixed. - [Critical] Error-recovery in
WriteSpec.write()andio_writecalled.encode()producing bytes passed tosys.stdout.write()which expectsstr. - SQL injection across all 8 database adapters in
exec_cmd()— stored procedure / function / view names are now quoted withquote_identifier(). DSNandSQL Serveradapters no longer encode SQL strings to bytes before execution.- Database adapters now clear
self.passwordafter successful connection, reducing credential exposure window. SubVarSet.substitute_all()enforces a 100-iteration depth limit to prevent infinite loops from cyclic variable references.
Removed¶
--ast/--no-astCLI flag — the AST executor is now the only execution engine.- Legacy flat command-list execution engine and its helpers (
_parse_script_lines,read_sqlfile,read_sqlstring,runscripts,ScriptFile,CommandListWhileLoop,CommandListUntilLoop).
[2.15.11] - 2026-04-27¶
Fixed¶
PAUSEconsole-mode fallback now checkssys.platformbefore attempting POSIX terminal imports, preventing hangs on Windows when stdin reports as a TTY.
[2.15.10] - 2026-04-27¶
Added¶
--config FILECLI flag specifies an explicit configuration file. Loaded after the implicit search paths (system, user, script-dir, working-dir) so its values take precedence; CLI arguments still override everything.$HOSTNAMEsystem substitution variable — the network name of the machine running execsql.
Fixed¶
- Config file chaining no longer mutates a list during iteration.
PAUSEconsole mode no longer crashes on Windows CI due to unconditionalimport termios.HAS_ROWS,ROW_COUNT_*condition predicates now quote table names with SQL identifier quoting, preventing injection when table names come from substitution variables.
[2.15.9] - 2026-04-27¶
Added¶
- Textual TUI now displays a progress bar and remaining-time countdown for
PROMPT PAUSEandPAUSEdialogs withCONTINUE AFTER/HALT AFTER(matching existing Tkinter behavior).
Fixed¶
PAUSEin console mode (no-v) now responds to single keypresses (Enter to continue, Esc to quit) instead of requiring Enter after every key.PAUSEwithCONTINUE AFTER/HALT AFTERin console mode displays a live SIGALRM-driven progress bar showing time remaining.- Double minutes-to-seconds conversion in the console
PAUSEpath: a 1-minute pause used to sleep for 60 minutes.
[2.15.8] - 2026-04-20¶
Added¶
PG_UPSERT/PG_UPSERT QA/PG_UPSERT CHECKnow support theSTRICT_COLUMNSkeyword. All missing columns in staging tables are treated as errors (not just PK and NOT NULL / no-default columns).- New
$PG_UPSERT_QA_WARNINGSsubstitution variable — comma-separated list of tables with WARNING-level QA findings.
Changed¶
$PG_UPSERT_RESULT_JSONnow includes aqa_warningsarray per table.- Minimum pg-upsert version bumped to
>=1.22.0.
Fixed¶
PG_UPSERT QAandPG_UPSERT CHECKnow capture all QA findings (errors + warnings) instead of only errors.
[2.15.7] - 2026-04-20¶
Fixed¶
CounterVars.substitutenow correctly searches the full string.re.Iwas mistakenly passed as theposargument tore.search, skipping the first two characters of every input.- SQL injection in MySQL
LOAD DATA INFILE: file path, field delimiter, and quote character are now escaped before being interpolated into SQL. - SQLite and DuckDB
exec_cmdno longer encodes the SQL string to bytes before passing toexecute()(always raisedTypeErrorin Python 3). - Cursor leaks across all database adapters — call sites that manually opened cursors now use the
with self._cursor()context manager. - Config file chaining is now capped at 20 files to prevent infinite loops from
config_filecycles. TempFileMgrnow usestempfile.mkstemp()instead ofNamedTemporaryFile().name, eliminating a TOCTOU race.- JSON export serializes column names with
json.dumps()(previously bare f-string interpolation broke on column names with quotes or backslashes). - PostgreSQL
VACUUMautocommit session state is restored in afinallyblock. - HTML export now HTML-escapes the description, author, and CSS href meta tag values.
shlex.spliton Windows now usesposix=Falseinstead of pre-escaping backslashes.- MySQL adapter no longer coerces
Nonearguments to the string"None"forserver_name,db_name,user_name.
[2.15.6] - 2026-04-16¶
Fixed¶
- Nested substitution variable names (e.g.
!!N_!!CHECK_GROUP!!_CHECKS!!) now resolve correctly. The single-pass token regex introduced in 2.15.0 could not find inner!!var!!tokens embedded in an outer variable name.
[2.15.5] - 2026-04-15¶
Fixed¶
DT_Timestamptype inference no longer claims time-only values like13:15:45.dateutil.parser.parse()silently filled in today's date for bare time strings, generating PostgreSQLInvalidDatetimeFormaterrors on CSV import.
[2.15.4] - 2026-04-15¶
Fixed¶
- Test data encoding typo causing assertion failure on Windows CI.
[2.15.3] - 2026-04-15¶
Added¶
- Optional dependency extras
auth-plaintextandauth-encryptedfor headless Linux keyring backends.pip install execsql2[auth-plaintext]installskeyring+keyrings.alt;[auth-encrypted]addspycryptodomefor the encrypted file backend.
[2.15.2] - 2026-04-14¶
Changed¶
- Performance:
DT_Integer,DT_Float,DT_Decimal,DT_Booleanmatchers now use pre-compiled regex / cached match tuples instead of rebuilding on every call — reduces overhead during large imports.
Fixed¶
DT_Text.data_type_namecorrected from"character"to"text"— error messages now identify the text type correctly.DT_Varchar._from_data()now converts non-string data to string and enforces the 255-character length limit.CondAstNode.eval()now raisesCondParserErrorfor unknown node types instead of silently returningNone.NumericAstNode.eval()now raisesNumericParserErroron division by zero instead of an unhandledZeroDivisionError.
[2.15.1] - 2026-04-14¶
Added¶
- Cell-level diff marking in
PROMPT COMPARE— when "Highlight Diffs" is toggled, differing cells within changed rows are prefixed with a bullet marker. Works across all three backends. macos_config_fileoption inexecsql.conf[config]section — additional config file to read on macOS, mirroringlinux_config_file.EXPORToperations now log structuredactionrecords with query name, output file, and source line number.
Changed¶
linux_config_filenow only applies on Linux (sys.platform == "linux"), not all POSIX. macOS users should use the newmacos_config_fileoption.- Date/time parsing now uses
python-dateutilinstead of 231 hardcodedstrptimeformat strings. Handles ISO 8601 withTseparator, microseconds,Zsuffix, and named timezones.
Removed¶
constants.py— 370 lines of map tile servers, XBM bitmaps, and X11 color names never imported anywhere. Vestigial from upstream.Tzclass intypes.py— customtzinfosubclass orphaned by thepython-dateutilmigration.
Fixed¶
NumericParsernow uses left-associative parsing. Previously10 - 3 - 2evaluated as10 - (3 - 2) = 9instead of5. Same fix for division.- SQLite
populate_table()now appliestrim_strings,replace_newlines, andempty_stringsprocessing before extracting column data (previously processing was applied after the insert data was copied, so it never took effect). $CURRENT_DATABASEand$CURRENT_DBMSsystem variables now refresh onUSE(previously stale after switching databases).PROMPT COMPAREdiff logic now uses native Python equality instead of string comparison —int(1)vsfloat(1.0),Decimal("10.00")vsDecimal("10.0"), andTruevs1are correctly treated as equal.PROMPT COMPAREtreatsNone(SQL NULL) as distinct from"". Summary stats now match by column name, exclude key columns from the diff, and keep the first row when duplicate PK values exist.PG_UPSERTno longer writes pg-upsert output toexecsql.log. Output goes only to the file specified byLOGFILE.win_config_filenow works on Windows. Previously checkedos.name == "windows"(Python returns"nt").
[2.15.0] - 2026-04-09¶
Added¶
PG_UPSERT"fix sheet" export: newEXPORT_FAILURES <dir>,EXPORT_FORMAT csv|json|xlsx, andEXPORT_MAX_ROWS <n>keywords write failing QA rows (one per unique violating staging row, with a consolidated_issuescolumn) to CSV, JSON, or XLSX. Works in all three modes (full pipeline, QA-only, schema check) and runs even when QA fails. New$PG_UPSERT_EXPORT_PATHsubstitution variable holds the directory written.
Changed¶
[upsert]extra now requirespg-upsert>=1.21.0(up from>=1.20.0) for the fix-sheet feature.
Fixed¶
PROMPT MESSAGE … CREDENTIALS <user_var> <pw_var>no longer crashes in console-fallback mode. The fallback now usesgetpass.getpass()for the password.
[2.14.1] - 2026-04-07¶
Fixed¶
- Windows CI: use
zf.namelist()[0]instead of path for zip entry lookup.
[2.14.0] - 2026-04-07¶
Added¶
- Row count footer in all GUI dialog tables (Textual TUI, Tkinter desktop, console fallback). Format: "3 rows" / "1 row" with thousands separators.
- Help URL button in all GUI dialogs that support the
HELPkeyword. - Diff summary line in compare dialogs ("3 matching | 1 differing | 2 only in Table 1").
PROMPT ENTRY_FORMnow enforcesvalidation_regex(on submit) andvalidation_key_regex(per-keystroke). Required fields are validated on submit. Tkinter shows a messagebox, Textual shows a notification, console re-prompts.- "Highlight Diffs" toggle in compare dialogs color-codes rows: green for matching, yellow for changed, red for rows only in one table.
Fixed¶
CONFIG GUI_LEVELnow accepts value3(open GUI console on start), matching thegui_levelconfig file setting.PROMPT COMPAREnow respectsANDvsBESIDE:ANDstacks tables vertically,BESIDEdisplays side-by-side. Previously both were side-by-side.PROMPT ENTRY_FORMnow renders all documentedentry_typevalues:listbox,radiobuttons,textarea,inputfile,outputfile. Previously onlycheckboxanddropdown/selectwere implemented.PROMPT ENTER_SUBHELP URL regex now correctly matches URLs containing+characters.- PostgreSQL and DSN
CONNECThandlers now unquote thePASSWORDparameter consistently with other database handlers.
Removed¶
FREEkeyword fromPROMPT DISPLAY— the non-blocking display behavior was only implemented in the console backend.
[2.13.2] - 2026-04-06¶
Changed¶
--lintstatic analysis improvements:SUB_EMPTY,SUB_ADD,SUB_APPEND, andSUBDATAnow register as variable definitions (eliminates false undefined-variable warnings).- Descends into
EXECUTE SCRIPT/EXEC SCRIPT/RUN SCRIPTso variables defined inside are visible to the caller. - Two-pass variable collection — definition order no longer matters.
- Reads
SUB_INIINI files and registers section keys as defined variables. - Warns when
EXECUTE SCRIPTtargets a non-existent script block (respectsIF EXISTS). - Sorts errors before warnings, both by line number; padded location columns for alignment.
[2.13.1] - 2026-04-04¶
Changed¶
- Bump pg-upsert minimum to
>=1.20.0.
[2.13.0] - 2026-04-04¶
Added¶
IMPORT … FROM JSONmetacommand — imports a JSON array of objects or JSON Lines file into a database table. Nested objects are flattened with dot-separated column names; nested arrays are stored as JSON strings. Missing keys become NULL.SHELL … CONTINUEnow sets$SYSTEM_CMD_PIDwith the PID of the background process.
Fixed¶
Mailer,WriteableZipfile,ZipWriternow support the context manager protocol (withstatement) for reliable resource cleanup.FileWriter,FileControl,Mailer,WriteableZipfile,ZipWriter__del__methods no longer raise during interpreter shutdown.
[2.12.7] - 2026-04-03¶
Fixed¶
- Bump pg-upsert minimum to
>=1.18.2— fixes the interactive FK check dialog showing only 1 violation row instead of all rows.
[2.12.6] - 2026-04-03¶
Added¶
PG_UPSERTnow supports per-table progress via pg-upsert's callback API. New substitution variables$PG_UPSERT_CURRENT_TABLE,$PG_UPSERT_TABLE_QA_PASSED,$PG_UPSERT_TABLE_ROWS_UPDATED,$PG_UPSERT_TABLE_ROWS_INSERTEDare updated as each table is processed.- New
CLEANUPkeyword forPG_UPSERT— drops allups_*temporary tables and views after execution. Without it, temp objects persist for inspection (default).
[2.12.5] - 2026-04-03¶
Fixed¶
- CLI test fixture: handle CliRunner's separate stderr capture.
[2.12.4] - 2026-04-03¶
Added¶
- New
PG_UPSERTmetacommand for QA-checked, FK-dependency-ordered upserts from a staging schema to a base schema on PostgreSQL. Integrates pg-upsert 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 …). SupportsMETHOD,COMMIT,INTERACTIVE,COMPACT,EXCLUDE,EXCLUDE_NULL,LOGFILEkeywords. Sets 12$PG_UPSERT_*substitution variables.
[2.12.3] - 2026-04-02¶
Changed¶
- Performance:
set_system_vars()split into static (once per script + onCONNECT/CHDIR) and dynamic (per statement) — eliminates ~14 redundant calls per statement. - Performance:
$RANDOMand$UUIDare now lazy — computed only when referenced. - Performance: CSV/TSV import uses Python's
csvmodule as a fast path for standard delimited formats (comma, tab, semicolon, pipe). Falls back to the character-at-a-time parser for non-standard formats.
[2.12.2] - 2026-04-02¶
Added¶
- Keyring setup guide for headless Linux servers (encrypted and plaintext file backends) in the Security reference.
Changed¶
ASSERTfailures now report**** Assertion failed.instead of**** Error in metacommand.to distinguish intentional script-level checks from metacommand errors.
[2.12.1] - 2026-04-02¶
Changed¶
- Performance: cached source paths on
ScriptCmd(eliminates per-statementPath.resolve()calls); batchedfetchmany()inselect_rowdict(); removed dead regex compilation.
Fixed¶
- Cursor leak in
select_rowsource()— generator now closes the cursor in afinallyblock.
[2.12.0] - 2026-04-01¶
Added¶
- Debug REPL
.where/.w— shows current script file, line number, and the upcoming statement text (truncated to 120 chars). The entry banner now includes the location ([Breakpoint] myscript.sql:42). - Debug REPL
.set VAR VAL— sets or updates a substitution variable interactively during aBREAKPOINTsession. - Debug REPL ANSI color output. Auto-detected via TTY; suppressed by
NO_COLOR/EXECSQL_NO_COLOR. - Debug REPL aliases:
.hfor.help,.vfor.vars,.v allfor.vars all. - Debug REPL step mode banner — shows "Step" instead of "Breakpoint" when re-entering via
.next. --profile-limit NCLI option — controls how many top statements appear in the--profiletiming summary (default: 20).
Changed¶
execsql.debug.replis now a dedicated package (src/execsql/debug/repl.py); previously atexecsql.metacommands.debug_repl. No public API change.
[2.11.1] - 2026-04-01¶
Fixed¶
x_assertcrash whenexec_logisNone.--pingversion-query loop exiting prematurely —breakwas at wrong indentation, skipping fallback queries.CONSOLE SET WIDTH/HEIGHTcrash —gui_console_width()/gui_console_height()restored as setter functions.$ERROR_MESSAGEnow contains fullerrmsg()(with script location and timestamp) for non-halting errors.- Non-halting SQL and metacommand errors now logged to
exec_log. - YAML
append=Truenow emits---document separator for valid multi-document streams.
[2.11.0] - 2026-04-01¶
Added¶
--debugCLI flag — starts the script in step-through debug mode. The debug REPL pauses before each statement, as ifBREAKPOINTwere inserted at the top with.nextalways active.
Changed¶
BREAKPOINTdebug REPL now pauses before each statement instead of after, so the upcoming statement can be inspected before it runs.
Fixed¶
BREAKPOINTREPL no longer wraps variable values in extra single quotes.- Error messages now include script file name and line number —
ErrInfofieldsscript_fileandscript_line_noare populated in all error paths. $ERROR_MESSAGEis now updated on every error (was initialized once to""and never changed).MetacommandStmt.run()now re-raises the original handlerErrInfowhenhalt_on_metacommand_erris True, instead of raising a generic "Unknown metacommand".write_warning()now acceptsalways=Trueto bypass theconf.write_warningsgate, so structural warnings (IF-level mismatch, unsubstituted variables) are always visible on stderr.
[2.10.1] - 2026-04-01¶
Fixed¶
BREAKPOINTvariable lookup —$logfilewas showing(undefined)becauseSUBstores keys without a sigil prefix. The debug REPL now strips$,&,@,#,~prefixes and retries when the exact name isn't found.
[2.10.0] - 2026-04-01¶
Added¶
BREAKPOINTmetacommand — pauses script execution and drops into an interactive debug REPL. Acceptscontinue/cto resume,abort/qto halt,varsto list substitution variables,$VARNAMEto print a single variable,SELECT …;to run ad-hoc SQL,next/nto step one statement at a time,stackto inspect the command-list stack,helpfor a summary. Silently skipped in non-TTY environments (CI, piped input).ROW_COUNT_GT(table, N),ROW_COUNT_GTE,ROW_COUNT_EQ,ROW_COUNT_LTconditional tests — compare row count of any table or view against an integer threshold usingIF,ELSEIF,ASSERT. IssuesSELECT count(*).
[2.9.0] - 2026-04-01¶
Added¶
--lintflag — parses a script and performs static analysis without connecting to a database. Reports unmatchedIF/ENDIF,LOOP/END LOOP,BEGIN BATCH/END BATCHas errors; potentially undefined!!$VAR!!references and missingINCLUDEtargets as warnings. Exits 0 if no errors are found (warnings don't affect exit code); exits 1 on any error.--pingflag — tests database connectivity without running a script.execsql --ping --dsn <URL>connects, queries the server version, prints a one-line summary, exits 0. No script file required.
[2.8.0] - 2026-04-01¶
Added¶
--profileflag — records wall-clock time for each SQL and metacommand statement and prints a timing summary after the script completes. Sorted by elapsed time descending (top 20).ASSERTmetacommand — evaluates anyIF-compatible condition and raises an error (halting the script whenHALT_ON_METACOMMAND_ERRORisON) if false. Optional quoted failure message; omitting it producesAssertion failed: <condition>. Silently skipped inside a falseIFblock.
Changed¶
--dry-runexpands substitution variables — the printed command list now shows resolved!!$VAR!!tokens for variables already populated at parse time (environment,--assign-arg, config, startup built-ins). Variables set during execution remain unexpanded.
[2.7.1] - 2026-04-01¶
Fixed¶
AttributeError: module 'execsql.state' has no attribute 'dedup_words'when importing CSV withDEDUP_COL_HDRSenabled.
[2.7.0] - 2026-04-01¶
Added¶
- Markdown export (
FORMAT MARKDOWN/FORMAT MD) — GitHub-flavored pipe tables with column alignment and pipe/backslash escaping. No dependencies. - YAML export (
FORMAT YAML) — list-of-dicts output with native type preservation. RequiresPyYAML(informatsextra). - XLSX export (
FORMAT XLSX) — single-sheet and multi-sheet Excel via openpyxl, with bold headers, native type preservation, and a "Datasheets" inventory sheet. Multi-sheet syntax:EXPORT table1, table2 TO file.xlsx AS XLSX.
[2.6.0] - 2026-04-01¶
Added¶
- Textual TUI
console_save()— writes console output to a file, matching Tkinter parity. - Keyboard shortcut hints on all major Textual TUI dialog screens (Escape to cancel, Enter to submit,
Footerwidget). RuntimeContextclass instate.py— groups all 33 mutable runtime globals into a single slotted object, enabling isolated contexts for testing and future concurrent execution.get_context()/set_context()public API for programmatic access to the active runtime context.- Divergence from Upstream documentation page (
docs/about/divergence.md).
Changed¶
state.pynow uses atypes.ModuleTypesubclass that transparently proxies attribute reads/writes to the activeRuntimeContext. All existing_state.foocall sites continue working unchanged.
[2.5.0] - 2026-04-01¶
Added¶
- Docstrings on 183 public API symbols across
db/,exporters/,importers/,config.py,models.py,types.py,parser.py. Public API coverage raised from 40% to 81%. - Developer architecture guide (
docs/dev/architecture.md) with Mermaid diagrams covering execution flow, module map, command stack, metacommand dispatch, conditionals, substitution variables, database abstraction, export/import, GUI, and global state. - Exporter
Protocoltypes (QueryExporter,RowsetExporter) inexporters/protocol.py.
Changed¶
- Cursor lifecycle in database adapters — all
exec_cmd()and PostgreSQLvacuum()now use the_cursor()context manager to prevent leaks.
[2.4.6] - 2026-03-31¶
Added¶
- End-to-end CLI tests (26 tests) covering
--version,--help,--dump-keywords,-c, file execution,--dry-run, error cases, andexecsql-format. - Exception chaining (
from None) on allraisestatements insideexceptblocks; ruff rule B904 enabled.
Changed¶
- Documentation reorganized into nav-aligned subdirectories:
getting-started/,reference/,guides/,about/. All 306 cross-references updated.
[2.4.5] - 2026-03-31¶
Added¶
- VS Code syntax highlighting section in the README.
- Pre-commit hook usage in the README formatting section.
Fixed¶
ON ERROR_HALT EXECUTE SCRIPTandON CANCEL_HALT EXECUTE SCRIPTwere not recognized — handlers existed but dispatch patterns were missing.EXTEND SCRIPT <X> WITH SCRIPT <Y>was not recognized — only theAPPEND SCRIPTsynonym was ported.PROMPT ASKwith single-quoted ('…') or bracket-delimited ([…]) questions, and with unquotedHELParguments, were not recognized.CONNECT TO SQLSERVERwith mixed quoting (e.g. quoted SERVER + unquoted DB) or quoted PASSWORD was not recognized.
[2.4.4] - 2026-03-30¶
Fixed¶
- PyPI publish URL — use
execsql2package name instead of repo name. - SQLite import-error test: patch
fatal_errorbefore__import__.
[2.4.3] - 2026-03-30¶
Added¶
- Pre-commit hook for
execsql-format— add the repo to.pre-commit-config.yamland pass--checkor--in-placeviaargs.
[2.4.2] - 2026-03-30¶
Changed¶
- Internal: raised test coverage floor 75 → 80%. No user-visible changes.
[2.4.1] - 2026-03-30¶
Fixed¶
--dsnnow correctly overrides connection settings from configuration files.- MySQL
LOAD DATA INFILEencoding — Python encoding names (e.g.utf-8) are now mapped to MySQL charset names (e.g.utf8mb4). - Importer error reporting: replaced removed
exception_info()withexception_desc().
Changed¶
- Integration tests moved to
tests/integration/with a shared conftest and parallel CI execution.
[2.4.0] - 2026-03-30¶
Added¶
- Python 3.14 support — added to CI matrix and PyPI classifiers.
- PostgreSQL integration tests (9 tests) — full lifecycle via
--dsnconnection strings. - MySQL/MariaDB integration tests (9 tests, 1 xfail for a pre-existing import adapter bug).
- CI integration test job with GitHub Actions services (PostgreSQL 16, MySQL 8).
Changed¶
Databaseis now an abstract base class (ABC) withopen_db()andexec_cmd()as@abstractmethod. Subclasses missing either raiseTypeErrorat instantiation time instead ofDatabaseNotImplementedErrorat call time.- Cursor lifecycle:
execute(),select_data(),schema_exists(),table_exists(),column_exists(),table_columns(),view_exists(),import_entire_file()now use a context manager that guarantees cleanup. - Metacommand dispatch uses keyword-indexed lookup, reducing dispatch from O(205) regex scans to O(K) where K ≈ 1–5.
- Variable substitution uses a single combined regex to find tokens in one pass, then dict lookup for the value — reducing
substitute()from O(V) to O(1) per call.
Fixed¶
- ODS import/export —
import odf as ofwas previouslyimport of as of. ODS support was broken since the modular refactor. --dsnpassword is now passed through to all database backends (MySQL, SQL Server, Oracle, Firebird, DSN). Previously only PostgreSQL received it.- Importer error reporting:
exception_info()(tuple) replaced withexception_desc()(string) in 6 call sites. Previously causedAttributeError: 'tuple' has no attribute 'replace'on any import failure. - MySQL
LOAD DATA LOCAL INFILEencoding name mapping (Python encoding → MySQL charset). --dsnnow overrides conf-file connection settings (server, database, user, port). Previously conf-file values took precedence.
[2.3.0] - 2026-03-30¶
Added¶
- Security documentation (
docs/security.md) covering trust model, SHELL execution, credential handling, file system access, SMTP, and SQL variable substitution.
Fixed¶
- Plaintext passwords (
Pwd=***) redacted from ODBC connection strings in log output for Access and SQL Server adapters.
Changed¶
- Removed lazy-import anti-pattern from 6 modules — stdlib imports moved to module level; optional deps (
xlrd,openpyxl,jinja2) use instance attributes instead ofglobal.
[2.2.1] - 2026-03-26¶
Fixed¶
- Skip
TimerHandleralarm tests on Windows wheresignal.setitimeris unavailable. UnicodeDecodeErrorin CLI subprocess tests on Windows — specify UTF-8 encoding.
[2.2.0] - 2026-03-26¶
Added¶
py.typedmarker for PEP 561 downstream type checking.--progressCLI flag andCONFIG SHOW_PROGRESSmetacommand — Rich progress bar during longIMPORToperations. Also configurable viashow_progressinexecsql.conf.log_sqlconfig option andCONFIG LOG_SQLmetacommand — opt-in SQL query audit logging. All executed statements written to the log with asqlrecord type, database name, line number, and query text.--dump-keywordsCLI option — outputs all metacommand keywords, conditional functions, config options, export formats, database types, and variable patterns as structured JSON. Enables tooling (e.g. editor grammar generators) to consume keyword data directly from the dispatch table.- VS Code syntax highlighting extension at
extras/vscode-execsql/. The grammar is auto-generated from the dispatch table viajust generate-vscode-grammar. - Keyring credential storage documentation in the usage notes.
Changed¶
- CLI reorganized from flat
_cli_*.pyfiles into acli/subpackage (cli/__init__.py,cli/run.py,cli/dsn.py,cli/help.py). All existingfrom execsql.cli import …paths preserved. - Exception hierarchy:
ErrInfo,DataTypeError,DbTypeError,DatabaseNotImplementedErrornow inherit fromExecSqlError. - Exception chaining:
from eadded to 115raisestatements across 38 files. metacommands/io.py(1304 lines) split intoio_export.py,io_import.py,io_write.py,io_fileops.py. All existing import paths preserved.
Fixed¶
- ODS export/import was completely broken when
odfpywas installed —import odf as ofwas previouslyimport of as of. - File-handle leaks in many exporters and metacommands —
try/finallyadded to guarantee close on error inexporters/raw.py,xml.py,json.py,templates.py,values.py,pretty.py,html.py,latex.py, andmetacommands/debug.py,control.py,prompt.py. - XML export injection: cell values are now escaped via
xml.sax.saxutils.escape(); column headers and table names used as XML element names have invalid characters replaced with underscores. - HTML export XSS: column headers and cell values are now escaped via
html.escape(). - JSON export injection: descriptions and column names are now serialized with
json.dumps(). - Jinja2 template injection:
templates.pynow usesjinja2.sandbox.SandboxedEnvironment. - SQL injection in metadata queries:
role_exists(),schema_exists(),table_exists(),column_exists(),table_columns(),view_exists()across all adapters now use parameterized queries orquote_identifier()for SQL identifiers. - SQL injection in
import_entire_file()across 6 database backends — thecolumn_nameparameter is now quoted withquote_identifier(). - SQL injection in PostgreSQL
create_db()— database name and encoding now usequote_identifier(); COPY delimiter and quote character are escaped/validated. - HTTP header injection in
SERVEmetacommand —Content-Dispositionfilename is sanitized (newlines/CRs stripped, quotes escaped). $SHEETS_TABLES_VALUESSQL injection: ODS/XLS sheet names are now escaped (single quotes doubled) before embedding in SQL.- CPU busy-loop in
utils/fileio.py:FileWriter.run()now uses blockingqueue.get(timeout=0.1)instead ofget_nowait()in a tight loop. - Substitution variable cycle detection —
substitute_vars()enforces a 100-iteration cap. - Empty
dt_casttype-cast mapping inDatabasebase class — the monolith populated this with 8 type converters; the refactored version was initialized to{}. Now lazily populated on first access. WriteSpec.write()file-descriptor leak inexporters/base.py:EncodedFile(...).open("a").write(msg)was opening and discarding the handle without closing.- Missing
PARQUETin EXPORT format regex —EXPORT … AS PARQUETwas unreachable despite the handler existing. CONNECT TO DSNwas unreachable — thex_connect_dsnhandler was imported but never registered withmcl.add().- Missing WRITE metacommand delimiter patterns (tilde, hash, backtick, bracket, single-quote) and bare (non-CONFIG) settings aliases that were present in the monolith.
- Backward-compatible
TXT-AND/TEXT-ANDexport format aliases.
[2.1.2] - 2026-03-25¶
Added¶
- DuckDB integration tests (15 end-to-end tests) covering basic SQL, substitution variables, CSV export/import, conditionals,
WRITE, round-trip, and DuckDB-specific features (views, schemas, native types).
Fixed¶
- Config parser now accepts
k(DuckDB) as a validdb_typeinexecsql.conf. Previously only the CLI flag-t kworked. - Read the Docs build: added
mkdocstrings-pythonand editable project install somkdocstringsresolves API references.
[2.1.1] - 2026-03-25¶
Added¶
- Keyring credential retry on auth failure — when a keyring-stored password is rejected, the stale entry is auto-deleted, the user is re-prompted for the current password, the connection is retried, and the new password is saved. Applies to all database adapters. New public helpers
password_from_keyring(),clear_stored_password(), andskip_keyringparameter onget_password(). - Security warning in
docs/substitution_vars.mdabout environment variable exposure via&-prefixed substitution variables, with mitigation guidance. - Automatic changelog versioning on
bump-my-version—CHANGELOG.mdis now bumpversion-managed (the[Unreleased]section is replaced with a dated heading and a fresh[Unreleased]is preserved).
Fixed¶
ExecSqlTimeoutErrornow inherits fromExecSqlErrorinstead ofException, so genericexcept ExecSqlErrorhandlers catch timeouts. Accepts an optional message (defaults to "Operation timed out").- ODS import/export was silently non-functional —
import odf as ofwas previouslyimport of as of. - Python 3.10 compatibility: replaced
datetime.UTC(3.11+) withdatetime.timezone.utc. - SQLite connection leaks:
state.reset()now callsdbs.closeall()before discarding theDatabasePool;export_sqlite()usestry/finallyto guarantee close on error.
[2.1.0]¶
Added¶
--dsn/--connection-stringCLI option — accepts a standard database URL (e.g.postgresql://user:pass@host:5432/db) and populates connection parameters automatically. Supported schemes:postgresql,postgres,mysql,mariadb,mssql,sqlserver,oracle,firebird,sqlite,duckdb. Overrides-t/-u/-pand positional server/db arguments.--dry-runoutput now displays multi-line SQL statements and metacommands with proper indentation, showing continuation lines aligned under the first line instead of truncating or wrapping text.--output-dir DIRCLI option — sets a default base directory forEXPORToutput files. Relative paths inEXPORTare joined to this directory; absolute paths andstdoutare unaffected.- Feather, Parquet, and HDF5 export support (via
polars/tables, included in theformatsextra). - OS keyring integration for database password storage (
utils/auth.py) — whenkeyringis installed,get_password()checks the OS credential store (macOS Keychain, Windows Credential Manager, Linux SecretService) before prompting. Controlled byuse_keyringconfig option (defaultyes). Requires theauthextra. max_log_size_mbconfig setting (default0= disabled) — when positive, the log file is rotated to.1before each new run if it exceeds the threshold.import_progress_intervalconfig option — logs a status line every N rows duringIMPORToperations.0= silent (default). A final completion line is also written.- Per-event ISO 8601 timestamps in log records (
status,connect,action,user_msg). - Run duration in the
exitlog record (elapsed wall-clock time as the last field). - Run ID millisecond precision: format changed from
%Y%m%d_%H%M_%Sto%Y%m%d_%H%M_%S_NNNto prevent collisions. - API reference section in the docs (
docs/api/) coveringcli,db,exporters,importers,metacommands. ExecSqlErrorbase class inexceptions.py—ConfigError,ColumnError,DataTableError,OdsFileError,XlsFileError,XlsxFileError,ConsoleUIError,CondParserError, andNumericParserErrornow inherit from it.
Changed¶
- Consolidated optional dependency extras: replaced
ods,excel,jinja,feather,parquet,hdf5extras with a singleformatsbundle. Renamedkeyringextra toauth. Addedall-dbconvenience group for all database drivers. - Replaced
os.pathcalls withpathlib.Pathequivalents across 21 source files.os.path.expandvars()is retained where used (nopathlibequivalent). SubVarSetrefactored: internal storage changed from list-of-tuples to dict for O(1) lookups; regex patterns pre-compiled onadd_substitution()instead of recompiled on everysubstitute()call.PostgresDatabaseandSQLiteDatabasenow accept connection timeout parameters (default 30s);Database.quote_identifier()added for safe SQL identifier quoting.utils/crypto.py: added prominent security warnings to module andEncryptclass docstrings documenting that XOR "encryption" is obfuscation only.
Fixed¶
IMPORTcompletion log message is now always written when a log is active, regardless ofimport_progress_interval. Previously the completion record was suppressed in silent mode, leaving no trace of successful imports.Logger.exit_typedefaults to"unknown"instead ofNone— prevents the literal string"None"from appearing in theexitlog record.- SQL injection in
schema_exists(),table_exists(),column_exists(),table_columns(),view_exists(),role_exists()acrossdb/base.py,db/postgres.py,db/oracle.py,db/duckdb.py,db/sqlite.py— now uses parameterized queries andquote_identifier(). config.py: five misnamed attribute writes (only_strings,fold_column_headers,replace_newlines,import_row_buffer,css_styles) all wrote to the wrong target.models.py: missing opening[inreplace_newlinesregex pattern;column_type()referenced undefinedac.maxlenfor all-NULL columns.- DuckDB temporal type mappings (
DT_TimestampTZ,DT_Timestamp,DT_Date,DT_Time) now use native DuckDB types (TIMESTAMPTZ,TIMESTAMP,DATE,TIME) instead ofTEXT.
Removed¶
AirspeedTemplateReportandFORMAT airspeedtemplate export variant. The Airspeed library has been unmaintained since ~2018. UseFORMAT jinjainstead.
[2.0.1] - 2026-03-23¶
Fixed¶
- Windows
PermissionErrorwhen exporting to HTML in append mode — the file descriptor fromtempfile.mkstemp()is now closed before the file is opened for writing. - Windows
PermissionErrorwhen exporting to LaTeX — the file descriptor fromtempfile.mkstemp()is now closed beforeEncodedFileopens the same path.
[2.0.0] - 2026-03-23¶
Changed¶
- Forked from execsql by R.Dreas Nielsen; repackaged as execsql2.
- Added support for Python 3.10, 3.11, 3.12, 3.13; dropped Python 2 compatibility.
- Distributed as the
execsql2package on PyPI; CLI entry point remainsexecsql.
[1.130.0] - 2024-12-18¶
Added¶
- Variable substitution to the
config_filesettings read fromexecsql.conf.
[1.129.0] - 2024-05-21¶
Added¶
PROMPT MESSAGEmetacommand that only displays a message in a dialog box.
[1.128.0] - 2024-05-12¶
Added¶
- Sash between the tables displayed by the
PROMPT COMPAREmetacommand so they can be resized.
[1.127.0] - 2024-04-09¶
Added¶
- Menu item to table displays allowing columns to be hidden or shown.
[1.126.1] - 2024-02-16¶
Added¶
- Templates and scripts to the distribution, to be placed in the
execsql_extrasdirectory.
Changed¶
- Improved sorting in tables shown by the
PROMPT DISPLAYand other metacommands.
Fixed¶
- Width specification for listboxes in the
PROMPT ENTRY_FORMmetacommand.
[1.126.0] - 2024-02-15¶
Added¶
- Horizontal scrollbar to listboxes used with the
PROMPT ENTRY_FORMmetacommand. - Radio button support for the
PROMPT ENTRY_FORMmetacommand.
[1.125.3] - 2024-02-09¶
Fixed¶
- Spurious warnings when running under Python 3.12.
[1.125.0] - 2023-12-13¶
Added¶
- Command-line and configuration settings to use an
execsql.logfile in the user's home directory.
[1.124.0] - 2023-12-12¶
Added¶
- Optional
HELPclauses for most metacommands that produce GUI dialogs.
[1.123.0] - 2023-08-22¶
Added¶
RESET DIALOG_CANCELEDmetacommand.
[1.122.0] - 2023-07-27¶
Added¶
FREEkeyword to thePROMPT DISPLAYmetacommand.$SCRIPT_START_TIME_UTCand$CURRENT_TIME_UTCsubstitution variables.
[1.120.0] - 2023-07-16¶
Changed¶
- Extended the
PROMPT ENTRY_FORMspecifications to allow listboxes, specification of height for listboxes and text areas, and specification of columns to create a multi-column form.
[1.119.0] - 2023-07-15¶
Changed¶
WRITEmetacommand now runs in a separate process.
[1.118.0] - 2023-07-09¶
Added¶
- 'Save as' menu items to the
PROMPT COMPAREUI.
Changed¶
- Performance improvement for the data type evaluator used by
IMPORTandCOPYmetacommands.
[1.117.0] - 2023-06-10¶
Added¶
- Support for DuckDB databases.
EXPORTmetacommand extended to export data to SQLite and DuckDB databases.
[1.115.0] - 2023-04-06¶
Added¶
- Export of multiple tables to an ODS workbook with a single
EXPORTmetacommand.
[1.114.0] - 2023-04-01¶
Added¶
DELETE_EMPTY_COLUMNSconfiguration metacommand and setting.
[1.113.0] - 2023-03-26¶
Added¶
BREAKmetacommand to allow early exit of loops and sub-scripts.
[1.112.0] - 2023-03-20¶
Added¶
!"!replacement delimiter for substitution variables.
[1.111.0] - 2023-01-09¶
Added¶
PROMPT CREDENTIALSmetacommand.
[1.110.0] - 2022-12-20¶
Added¶
$SHEETS_IMPORTED,$SHEETS_TABLES, and$SHEETS_TABLES_VALUESsystem variables.
[1.109.0] - 2022-12-13¶
Added¶
CONFIG WRITE_PREFIXandCONFIG WRITE_SUFFIXmetacommands and configuration settings.
[1.108.0] - 2022-11-17¶
Changed¶
- Renamed the
EMITmetacommand toSERVE.
[1.107.0] - 2022-11-02¶
Added¶
CGI-HTMLtype for theEXPORTmetacommand.SUB_QUERYSTRINGandEMITmetacommands to support use of execsql as a CGI script.
[1.106.0] - 2022-10-27¶
Changed¶
table_exists()andview_exists()conditionals for Postgres now only look for tables in the temporary-table schema or in a schema on Postgres' search path.
[1.105.0] - 2022-10-19¶
Added¶
CDmetacommand.
[1.104.0] - 2022-10-15¶
Added¶
trim_column_headersconfiguration setting and configuration metacommand.
[1.103.0] - 2022-07-23¶
Changed¶
- Extended the
EXPORT_METADATAmetacommand to insert metadata into a database table.
[1.102.0] - 2022-06-21¶
Added¶
- Import from data files in Feather format.
[1.101.0] - 2022-06-18¶
Added¶
- Import from data files in Parquet format.
[1.100.3] - 2022-04-30¶
Fixed¶
PROMPT ENTRY_FORMno longer closes the form when the 'Enter' key is pressed while a checkbox has focus.
[1.100.1] - 2022-02-22¶
Added¶
- Bottom border to the header row and top-alignment of body cells to ODS export.
[1.100.0] - 2022-02-20¶
Added¶
INITIALLYclause to thePROMPT ENTER_SUBmetacommand.
[1.99.0] - 2022-02-19¶
Added¶
- Variant
IMPORTmetacommands that use aSHEETS MATCHING <regex>clause to import multiple sheets from an OpenDocument or Excel workbook in one step.
[1.98.0] - 2022-01-12¶
Added¶
FOLD_COLUMN_HEADERSconfiguration setting.
Changed¶
- Column header cleaning now adds an underscore to the beginning of any column header that starts with a digit.
[1.97.0] - 2022-01-08¶
Added¶
CONTAINS,ENDS_WITH, andSTARTS_WITHconditional tests.
Changed¶
textareacontrol in anENTRY_FORMnow allows newlines to be inserted and strips trailing newlines.- SQL statement evaluator now ignores multiple terminating semicolons.
[1.96.0] - 2022-01-03¶
Changed¶
- Reading of
.xlsxfiles now uses theopenpyxllibrary (new requirement).
[1.95.0] - 2021-12-03¶
Changed¶
SYSTEM_CMDmetacommand now logs the command toexecsql.log.
[1.94.0] - 2021-10-19¶
Added¶
$PATHSEPsystem variable.
Changed¶
INCLUDEandIMPORTmetacommands now recognize leading tildes on the filename.
[1.93.0] - 2021-10-02¶
Added¶
USERvariant of theCONNECTmetacommand.
[1.92.0] - 2021-09-19¶
Added¶
TRIM_STRINGSandREPLACE_NEWLINESsettings.
[1.91.0] - 2021-09-16¶
Added¶
DIALOG_CANCELED()conditional.
[1.90.0] - 2021-08-08¶
Changed¶
- Metacommand patterns are now dynamically re-ordered to match usage.
[1.89.1] - 2021-05-18¶
Changed¶
- Column name
userrenamed tousernamein the output of theEXPORT_METADATAmetacommand.
[1.89.0] - 2021-03-17¶
Added¶
TEEclause to theHALTmetacommand.
[1.88.0] - 2021-02-13¶
Added¶
EXPORT_METADATAmetacommand.
[1.87.0] - 2021-02-10¶
Added¶
ZIPmetacommand.
[1.86.0] - 2021-02-09¶
Added¶
create_column_headersconfiguration setting and configuration metacommand.
[1.85.0] - 2021-02-09¶
Added¶
zip_buffer_mbconfiguration setting and configuration metacommand.
[1.84.0] - 2021-02-06¶
Added¶
EXPORTdirectly to a zip file for most export formats.
[1.83.0] - 2021-01-09¶
Changed¶
- Interpretation of both
config_fileandlinux_config_filesettings now expands a leading~to the user's home directory.
[1.82.0] - 2020-11-14¶
Added¶
- Console window size configuration options in
execsql.conf.
Changed¶
- Console height and width configuration metacommands now change settings for any future console windows as well as any currently open console.
[1.81.0] - 2020-11-08¶
Added¶
only_stringsconfiguration setting and metacommand.
[1.80.0] - 2020-10-26¶
Added¶
linux_config_fileandwin_config_fileconfiguration settings.
[1.79.0] - 2020-08-29¶
Added¶
ENCODINGclause to theWRITE CREATE_TABLEmetacommand for text files.
[1.78.0] - 2020-08-08¶
Changed¶
PROMPT SELECT_ROWSmetacommand now sets a grey background on selected rows.
[1.77.0] - 2020-07-29¶
Added¶
$STARTING_SCRIPT_REVTIMEsystem variable.
[1.76.0] - 2020-07-18¶
Added¶
- Configuration option and metacommand to deduplicate repeated column headers in IMPORTed data.
Changed¶
- Column header cleaning now strips leading and trailing spaces.
[1.75.0] - 2020-07-16¶
Added¶
- More quoting characters for the
WRITEmetacommand.
[1.74.3] - 2020-07-11¶
Fixed¶
ASKmetacommand under Python 3 on Windows.
[1.74.1] - 2020-07-08¶
Added¶
import_row_buffersetting andCONFIG IMPORT_ROW_BUFFERmetacommand to allow buffer size customization.
Changed¶
IMPORTmetacommand now buffers input rows for slightly better performance.
[1.73.0] - 2020-05-01¶
Changed¶
execsql.logis now set to read-only on exit.
[1.72.2] - 2020-03-31¶
Fixed¶
- Correction to 2020-03-30 modification.
[1.72.0] - 2020-03-30¶
Added¶
export_row_buffersetting andCONFIG EXPORT_ROW_BUFFERmetacommand to allow buffer size customization.
Changed¶
- Export buffer size modified for better performance.
[1.71.2] - 2020-03-29¶
Added¶
- Encoding name translations to allow more encoding name aliases when using the
EXPORTmetacommand with Postgres.
[1.71.0] - 2020-03-21¶
Added¶
CONFIG LOG_DATAVARSmetacommand andlog_datavarsconfiguration setting.
[1.70.0] - 2020-03-14¶
Added¶
"!'!"substitution delimiter.SUB_EMPTYconditional test.
[1.69.0] - 2020-03-07¶
Added¶
- Export to HDF5 files.
[1.68.0] - 2020-03-03¶
Added¶
IF EXISTSclause to theEXECUTE SCRIPTmetacommand.
[1.67.0] - 2020-02-22¶
Added¶
EXTEND SCRIPT WITH SQLandEXTEND SCRIPT WITH METACOMMANDmetacommands.APPEND SCRIPTaliased toEXTEND SCRIPT...WITH SCRIPT.
[1.66.0] - 2020-02-22¶
Added¶
DISCONNECTmetacommand.
[1.65.0] - 2020-02-22¶
Added¶
CONFIG SCAN_LINESandCONFIG GUI_LEVELmetacommands.
[1.64.0] - 2020-02-22¶
Added¶
LOCALandUSERkeywords to theDEBUG LOG SUBVARSmetacommand.
[1.63.0] - 2020-02-15¶
Changed¶
CONFIGmetacommands now accept0or1as arguments.
[1.62.0] - 2020-02-13¶
Added¶
CONFIG DAO_FLUSH_DELAY_SECSmetacommand anddao_flush_delay_secsconfiguration file setting.
[1.61.0] - 2020-02-05¶
Added¶
PROMPT PAUSEmetacommand.- execsql version number is now written to
execsql.log.
[1.60.0] - 2020-02-01¶
Added¶
LOOPmetacommand.
[1.59.0] - 2020-01-31¶
Added¶
$STARTING_PATHand$CURRENT_PATHsystem variables.
[1.58.0] - 2020-01-28¶
Changed¶
PAUSEandASKmetacommands now allow apostrophes and square brackets as string delimiters.
[1.57.0] - 2020-01-25¶
Changed¶
- Evaluation of conditionals now accepts Boolean literals.
[1.56.0] - 2019-12-27¶
Added¶
ROLE_EXISTSconditional.
[1.55.0] - 2019-12-26¶
Added¶
CONTINUEkeyword to theSYSTEM_CMDmetacommand.
[1.54.0] - 2019-12-20¶
Added¶
BEGIN/END SQLmetacommands.
[1.53.0] - 2019-10-27¶
Added¶
- Oracle database support.
[1.52.0] - 2019-10-11¶
Added¶
- Export to XML.
[1.51.0] - 2019-10-10¶
Added¶
WHILEandUNTILloop control toEXECUTE SCRIPT.- Deferred variable substitution.
[1.50.0] - 2019-10-05¶
Added¶
- Numeric expression parser for the
SUB_ADDandSET COUNTERmetacommands.
[1.49.0] - 2019-10-04¶
Added¶
- Conditional expression parser for the
IFmetacommands.
[1.48.0] - 2019-09-27¶
Added¶
CONFIG EMPTY_ROWSmetacommand andempty_rowsconfiguration setting.
[1.47.0] - 2019-09-21¶
Added¶
FROMkeyword toPROMPT OPENFILE,SAVEFILE, andDIRECTORYmetacommands.
[1.46.0] - 2019-09-04¶
Added¶
COMPACTkeyword to thePROMPT ACTIONmetacommand.
[1.45.0] - 2019-09-01¶
Added¶
SCRIPT_EXISTSconditional.PROMPT ACTIONmetacommand.
[1.43.0] - 2019-08-27¶
Added¶
PROMPT SELECT_ROWSmetacommand.
[1.42.1] - 2019-08-22¶
Fixed¶
EXPORT...AS VALUESnow correctly writesNULLfor null data.
[1.42.0] - 2019-08-18¶
Added¶
APPEND SCRIPTmetacommand.
[1.41.0] - 2019-08-17¶
Added¶
- Export option to produce a JSON table schema.
[1.40.0] - 2019-08-16¶
Added¶
USERkeyword to theDEBUG WRITE SUBVARSmetacommand.
[1.39.0] - 2019-08-16¶
Added¶
SUB_INImetacommand.
[1.38.8] - 2019-06-30¶
Added¶
- Input and output filename prompt options to the entry form specifications.
[1.37.7] - 2019-05-10¶
Fixed¶
- Error messages containing bad data are now protected from encoding errors.
[1.37.6] - 2019-05-07¶
Changed¶
- Removed Unicode conversion of data when loaded into Tkinter Treeview control.
- Added
MARS_Connection=Yesto SQL Server ODBC connections.
[1.37.4] - 2019-05-04¶
Added¶
- SQL Server ODBC drivers 13.1 and 17.
Changed¶
- Improved efficiency of
COPYmetacommand.
Fixed¶
int/longconversion for Python 3 with Access.
[1.37.0] - 2019-03-16¶
Added¶
PASSWORDkeyword to theCONNECTmetacommand for SQL Server.
[1.36.0] - 2019-03-11¶
Changed¶
- Switched to three-part semantic version number.
[1.35.2.0] - 2019-02-27¶
Added¶
WITH COMMIT|ROLLBACKclause to theAUTOCOMMIT ONmetacommand.
[1.35.1.0] - 2019-02-23¶
Added¶
- Warning if a SQL statement is incomplete when a metacommand is encountered.
- Error if a SQL statement is incomplete at the end of a script file.
CONFIG WRITE_WARNINGSmetacommand.
[1.35.0.0] - 2019-02-21¶
Changed¶
- Substitution metacommands now accept a
+prefix to reference local variables in outer scopes.
[1.34.9.0] - 2019-02-18¶
Added¶
ON ERROR_HALT EXECUTE SCRIPTandON CANCEL_HALT EXECUTE SCRIPTmetacommands.
[1.34.8.0] - 2019-02-12¶
Changed¶
- Improved reporting of origin lines of mismatched
IFconditionals.
[1.34.7.0] - 2019-02-09¶
Added¶
- System variables for execsql's primary, secondary, and tertiary version numbers.
- Script name can now be specified on the
END SCRIPTmetacommand.
Changed¶
- Quotes are now optional on the arguments to the
is_true,equal, andidenticalconditionals.
[1.34.4.0] - 2019-02-08¶
Added¶
- Configuration option to clean IMPORTed column headers of non-alphanumeric characters.
[1.34.2.0] - 2019-02-03¶
Added¶
- Raises an exception if there is an incomplete SQL statement at
END SCRIPT. - Issues a warning if
IFlevels are unbalanced within a script. - Issues a warning if a command appears to have an unsubstituted variable.
[1.34.0.0] - 2019-02-02¶
Added¶
- Optional
WITH ARGUMENTSextension to theEXECUTE SCRIPTmetacommand. - Optional
WITH PARAMETERSextension to theBEGIN SCRIPTmetacommand.
[1.33.0.0] - 2019-01-19¶
Added¶
PROMPT ASK...COMPAREmetacommand.
Changed¶
- All
ASKmetacommands and theSUBDATAmetacommand can now set local variables.
[1.32.0.0] - 2018-12-16¶
Added¶
- Export to the Feather file format.
[1.31.13.0] - 2018-11-07¶
Added¶
quote_all_textoutput setting andCONFIG QUOTE_ALL_TEXTmetacommand.
[1.31.12.0] - 2018-11-03¶
Added¶
CONSOLE WIDTHandCONSOLE HEIGHTmetacommands.
Changed¶
PROMPT ENTRY_FORMnow recognizes local variables.- All
CONFIGmetacommands that take Boolean arguments now recognize bothYes/NoandOn/Off.
[1.31.10.0] - 2018-10-30¶
Added¶
- Asterisks to denote required entries on
PROMPT ENTRY_FORM.
[1.31.9.0] - 2018-10-29¶
Added¶
- Fifth variable to
PROMPT OPENFILEandPROMPT SAVEFILEto get the base filename without path or extension.
[1.31.8.0] - 2018-10-25¶
Changed¶
RM_FILEmetacommand now accepts wildcards.
[1.31.7.0] - 2018-10-23¶
Added¶
- Optional second, third, and fourth substitution variable names to
PROMPT SAVEFILEfor filename-only, path-only, and extension.
[1.31.6.0] - 2018-10-22¶
Added¶
- Optional third and fourth substitution variable names to
PROMPT OPENFILEfor path-only and extension.
[1.31.5.0] - 2018-10-15¶
Added¶
- Optional second substitution variable name to
PROMPT OPENFILEfor filename without path.
[1.31.4.0] - 2018-10-14¶
Added¶
ENCODINGclause to theIMPORT...FROM EXCELmetacommand.
[1.31.3.0] - 2018-10-14¶
Added¶
- Sorting of tabular displays by clicking on column headers.
Changed¶
- All path separators returned by
PROMPT OPENFILE,SAVEFILE, andDIRECTORYare converted from/to\\on Windows.
[1.31.1.0] - 2018-10-09¶
Added¶
LOCALclause toDEBUG WRITE SUBVARS.
[1.31.0.0] - 2018-10-07¶
Added¶
- Local variables.
[1.30.6.0] - 2018-09-30¶
Added¶
- Button to show unmatched rows in the
PROMPT COMPAREdisplay. IF EXISTSclause to theINCLUDEmetacommand.IF CONSOLE_ONconditional test.
[1.30.3.0] - 2018-09-29¶
Added¶
IN <alias>clauses to thePROMPT COMPAREmetacommand.- Checkbox to the
PROMPT COMPAREGUI to allow highlighting of matches in both tables.
[1.30.1.0] - 2018-09-23¶
Changed¶
PROMPT COMPAREcommand now highlights all matching rows in the other table, not just the first.
[1.30.0.0] - 2018-09-22¶
Changed¶
- Binary data length is now written as a description when binary data are used with
PROMPT DISPLAYorEXPORT AS TXT.
[1.29.3.0] - 2018-09-22¶
Changed¶
WRITEmetacommand now uses themake_export_dirsconfiguration setting.
[1.29.2.0] - 2018-09-19¶
Added¶
SUB_ADDmetacommand.
Changed¶
WITHkeyword is now optional in theIMPORTmetacommand.
[1.29.0.0] - 2018-09-12¶
Added¶
IMPORT_FILEmetacommand.
[1.28.0.0] - 2018-08-19¶
Added¶
- Python 3.x compatibility (in addition to 2.7).
[1.27.4.0] - 2018-08-19¶
Changed¶
- Python version number is now written to
execsql.log.
[1.27.3.0] - 2018-07-31¶
Changed¶
- Configuration files are now read from both the script directory and the starting directory, if different.
[1.27.2.0] - 2018-07-30¶
Added¶
SUB_EMPTYmetacommand.
[1.27.1.0] - 2018-07-29¶
Changed¶
ON ERROR_HALT WRITEandON CANCEL_HALT WRITEmetacommands now allow single quotes and square brackets.
[1.27.0.0] - 2018-07-29¶
Changed¶
- Internal script processing routines rewritten.
[1.26.8.0] - 2018-07-25¶
Changed¶
WRITEmetacommand now allows single quotes and square brackets.- Data format evaluation used by
IMPORTnow takes account of theempty_stringsconfiguration setting.
Fixed¶
- Stripping of extra spaces from input data when input is not strings.
[1.26.5.0] - 2018-07-20¶
Added¶
$PYTHON_EXECUTABLEsystem variable.
Changed¶
- Strings of only spaces are now treated as empty strings when
empty_strings=False.
Fixed¶
- Trailing space is now trimmed from the last column header of an IMPORTed CSV file.
[1.26.4.3] - 2018-07-12¶
Fixed¶
- Handling of double-quoted filenames by the
ON ERROR_HALT WRITEandON CANCEL_HALT WRITEmetacommands.
[1.26.4.2] - 2018-07-09¶
Fixed¶
- Handling of double-quoted filenames by the
WRITEandRM_FILEmetacommands.
[1.26.4.0] - 2018-06-27¶
Added¶
$STARTING_SCRIPT_NAMEand$CURRENT_SCRIPT_NAMEsystem variables.IS_TRUEconditional.
[1.26.2.0] - 2018-06-25¶
Added¶
$CURRENT_SCRIPT_PATHsystem variable that returns the path only of the current script file.
[1.26.1.0] - 2018-06-13¶
Changed¶
HALTmetacommands now set the exit code to 3.
Fixed¶
- Hang on uppercase counter references.
[1.26.0.0] - 2018-06-13¶
Added¶
ON CANCEL_HALT WRITEandON CANCEL_HALT EMAILmetacommands.
[1.25.0.0] - 2018-06-10¶
Added¶
PROMPT COMPAREmetacommand.
[1.24.12.0] - 2018-06-09¶
Added¶
MAKE_EXPORT_DIRSmetacommand.
Changed¶
- All metacommands corresponding to configuration options are grouped under a common
CONFIGprefix. - Configuration file size and date are now written to
execsql.logwhen a configuration file is read.
[1.24.9.0] - 2018-06-03¶
Changed¶
IMPORTmetacommand now writes the file name, file size, and file date toexecsql.log.
[1.24.8.0] - 2018-06-03¶
Changed¶
- Added filename to error message when the
IMPORTmetacommand cannot find a file. SUBDATAnow only removes the substitution variable (rather than raising an exception) when there are no rows in the specified table or view.
Fixed¶
is_null(),equals(), andidentical()now correctly strip quotes.
[1.24.7.0] - 2018-04-03¶
Added¶
$SYSTEM_CMD_EXIT_STATUSsystem variable.
[1.24.6.0] - 2018-04-01¶
Added¶
B64format to theEXPORTandEXPORT_QUERYmetacommands.
[1.24.5.0] - 2018-03-15¶
Added¶
textareaentry type to thePROMPT ENTRY_FORMmetacommand.
[1.24.4.0] - 2017-12-31¶
Added¶
-ocommand-line option to display online help.
Changed¶
CREATE SCRIPTis now an alias forBEGIN SCRIPT.DEBUG WRITE SCRIPTis now an alias forWRITE SCRIPT.
[1.24.2.0] - 2017-12-30¶
Added¶
TYPEandLCASE/UCASEkeywords to thePROMPT ENTER_SUBmetacommand.
Changed¶
- Modified characters allowed in user names for Postgres and ODBC connections.
[1.24.0.0] - 2017-11-04¶
Added¶
include_requiredandinclude_optionalconfiguration settings.
[1.23.3.0] - 2017-11-03¶
Added¶
CONSOLE_WAIT_WHEN_ERROR_HALTsetting, associated metacommand, and system variable.
[1.23.2.0] - 2017-11-02¶
Added¶
$ERROR_MESSAGEsystem variable.
[1.23.1.0] - 2017-10-20¶
Added¶
ASKmetacommand.
[1.23.0.0] - 2017-10-09¶
Added¶
ON ERROR_HALT EMAILmetacommand.
[1.22.0.0] - 2017-10-07¶
Added¶
ON ERROR_HALT WRITEmetacommand.
[1.21.13.0] - 2017-09-29¶
Added¶
SUB_APPENDandWRITE SCRIPTmetacommands.
Changed¶
- All metacommand messages now allow multiline text.
[1.21.12.0] - 2017-09-24¶
Added¶
PG_VACUUMmetacommand.
[1.21.11.0] - 2017-09-23¶
Changed¶
- Error message content and format.
[1.21.10.0] - 2017-09-12¶
Added¶
error_responseconfiguration setting for encoding mismatches.
[1.21.9.0] - 2017-09-06¶
Changed¶
- Now handles trailing comments on SQL script lines.
[1.21.8.0] - 2017-08-11¶
Changed¶
CONNECTmetacommand for MySQL now allows a password to be specified.
[1.21.7.0] - 2017-08-05¶
Added¶
DEBUGmetacommands.
Changed¶
IMPORTmetacommand now allows CSV files with more columns than the target table.
[1.21.1.0] - 2017-07-04¶
Changed¶
- Column headers are now passed to template processors as a separate object.
[1.21.0.0] - 2017-07-01¶
Added¶
EXPORTmetacommand extended to allow several different template processors to be used.
[1.20.0.0] - 2017-06-30¶
Added¶
EMAIL,SUB_ENCRYPT, andSUB_DECRYPTmetacommands.- Configuration properties to support emailing.
METACOMMAND_ERROR_HALTmetacommand.$METACOMMAND_ERROR_HALT_STATEsystem variable.METACOMMAND_ERROR()conditional.
[1.18.0.0] - 2017-06-24¶
Changed¶
- Improved speed of import of CSV files to Postgres and MySQL/MariaDB.
EXPORT...APPEND...AS HTMLmetacommand now appends tables inside the first</body>tag.
[1.17.0.0] - 2017-05-28¶
Changed¶
PROMPT ENTRY_FORMspecifications extended to allow checkboxes.
[1.16.9.0] - 2017-05-27¶
Added¶
DESCRIPTIONkeyword to theEXPORTmetacommands.
[1.16.8.0] - 2017-05-20¶
Added¶
VALUESexport format.
[1.16.7.0] - 2017-05-20¶
Added¶
BOOLEAN_INTandBOOLEAN_WORDSmetacommands.console_wait_when_doneconfiguration parameter.
Changed¶
PAUSEmetacommand now accepts fractional timeout arguments.- Server name is now added to the password prompt.
[1.16.3.0] - 2017-04-23¶
Added¶
- Configuration option allowing specification of additional configuration files to read.
MAX_INTconfiguration parameter and metacommand.
[1.16.0.0] - 2017-03-25¶
Added¶
BEGIN SCRIPT,END SCRIPT, andEXECUTE SCRIPTmetacommands.
[1.15.0.0] - 2017-03-09¶
Added¶
TEEkeyword to theWRITE,EXPORT, andEXPORT QUERYmetacommands.
[1.13.0.0] - 2017-03-05¶
Added¶
LOG_WRITE_MESSAGESmetacommand and configuration parameter.
[1.12.0.0] - 2017-03-04¶
Added¶
boolean_wordsconfiguration option.- Reading of CSV files with newlines within delimited text data.
SKIPkeyword to theIMPORTmetacommand for CSV, ODS, and Excel data.COLUMN_EXISTSconditional.
[1.8.15.0] - 2017-01-14¶
Added¶
$LAST_ROWCOUNTsystem variable.
[1.8.14.0] - 2016-11-13¶
Added¶
- Evaluation of numeric types in input.
empty_stringsconfiguration parameter and metacommand.
Fixed¶
- Corrections to
IMPORTmetacommand for Firebird.
[1.8.13.0] - 2016-11-07¶
Added¶
-bcommand-line option and configuration parameter.
[1.8.12.0] - 2016-10-22¶
Added¶
RM_SUBmetacommand.
[1.8.11.0] - 2016-10-19¶
Added¶
SET COUNTERmetacommand.
[1.8.10.2] - 2016-10-17¶
Added¶
$RUN_IDsystem variable.
Changed¶
- Now recognizes as text any imported data that contains only numeric values where the first digit of any value is a zero.
[1.8.8.0] - 2016-09-28¶
Added¶
$CURRENT_ALIAS,$RANDOM, and$UUIDsystem variables.
[1.8.4.0] - 2016-08-13¶
Added¶
- Import from MS-Excel.
Changed¶
- Logging of database close when autocommit is off.
Fixed¶
- Parsing of numeric time zones.
[1.7.3.0] - 2016-08-05¶
Added¶
$OSsystem variable.
[1.7.2.0] - 2016-06-11¶
Added¶
DIRECTORY_EXISTSconditional.- Option to automatically make directories used by the
EXPORTmetacommand.
[1.7.0.0] - 2016-05-20¶
Added¶
NEWER_DATEandNEWER_FILEconditionals.
[1.6.0.0] - 2016-05-15¶
Added¶
CONSOLE SAVEmetacommand.- DSN connections.
COPY QUERYandEXPORT QUERYmetacommands.
[1.4.4.0] - 2016-05-02¶
Added¶
CONSOLE HIDE/SHOWmetacommands.
Changed¶
CONSOLE WAITmetacommand now accepts<Enter>to continue without closing.
[1.4.2.0] - 2016-05-02¶
Added¶
- "Save as..." menu to the GUI console.
Changed¶
PAUSEandHALTmetacommands now use a GUI if the console is on.
[1.4.0.0] - 2016-04-30¶
Added¶
- GUI console with a status bar and progress bar to which
WRITEoutput and exported text will be written.
[1.3.3.0] - 2016-04-09¶
Added¶
- Additional 'Save as...' options in
PROMPT DISPLAYmetacommand. - Date/time values exported to ODS.
[1.3.2.0] - 2016-02-28¶
Added¶
- Backslash as a line continuation character for SQL statements.
[1.3.1.0] - 2016-02-20¶
Added¶
PROMPT ENTRY_FORMandLOGmetacommands.
[1.2.15.0] - 2016-02-14¶
Added¶
$DB_NAME,$DB_NEED_PWD,$DB_SERVER, and$DB_USERsystem variables.RAWexport format for binary data.PASSWORDkeyword to thePROMPT ENTER_SUBmetacommand.- Password support in the
CONNECTmetacommand for Access.
[1.2.10.0] - 2016-01-23¶
Added¶
ENCODINGkeyword toIMPORTmetacommand.TIMERmetacommand and$TIMERsystem variable.
[1.2.8.2] - 2016-01-21¶
Fixed¶
- Extra quoting in drop table method.
strcoercion in TXT export.
[1.2.8.0] - 2016-01-11¶
Changed¶
- Column headers are suppressed when EXPORTing to CSV and TSV with
APPEND. - Eliminated
%H%Mpattern to match time values in IMPORTed data.
[1.2.7.1] - 2016-01-03¶
Added¶
AUTOCOMMITmetacommand.
Changed¶
- Modified import of integers to Postgres.
BATCHmetacommand modified.- Now explicitly rolls back any uncommitted changes on exit.
Fixed¶
- Miscellaneous bug fixes.
[1.2.4.6] - 2015-12-19¶
Changed¶
- Modified quoting of column names for the
COPYandIMPORTmetacommands.
[1.2.4.5] - 2015-12-17¶
Fixed¶
- Asterisks in
PROMPT ENTER_SUB.
[1.2.4.4] - 2015-12-14¶
Fixed¶
- Regexes for quoted filenames.
[1.2.4.3] - 2015-12-13¶
Fixed¶
-yoption display.- Parsing of
WRITE CREATE_TABLEcomment option. - Parsing of backslashes in substitution strings on Windows.
[1.2.4.0] - 2015-11-21¶
Added¶
- Connections to PostgreSQL, SQL Server, MySQL, MariaDB, SQLite, and Firebird.
- Numerous metacommands and conditional tests.
- Reading of configuration files.
[0.4.4.0] - 2010-06-20¶
Added¶
INCLUDE,WRITE,EXPORT,SUB,EXECUTE,HALT, andIF(HASROWS,SQL_ERROR) metacommands.
[0.3.1.0] - 2008-12-19¶
Added¶
- Internal documentation.
[0.3.0.0] - 2008-05-20¶
Added¶
cp1252encoding for data read from Access.
[0.2.0.0] - 2008-04-26¶
Added¶
- Creation and deletion of temporary views (queries).
- Export of final query to Excel.
[0.1.2.0] - 2008-04-22¶
Changed¶
- Added regular expressions to match
create temp view...SQL command preface.
[0.1.1.0] - 2008-04-20¶
Changed¶
- Converted to use DAO instead of the dbconnect library.
[0.1.0.0] - 2008-01-01¶
Added¶
- Writing of the output of the last SQL command to a CSV file.
[0.0.1.0] - 2007-11-11¶
Added¶
- Initial release; executes SQL against Access.