execsql2 2.23.1__py3-none-any.whl → 2.24.0__py3-none-any.whl

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.
Files changed (56) hide show
  1. execsql/cli/__init__.py +17 -586
  2. execsql/cli/application.py +309 -0
  3. execsql/cli/commands/__init__.py +13 -0
  4. execsql/cli/commands/config.py +205 -0
  5. execsql/cli/commands/format.py +100 -0
  6. execsql/cli/commands/init.py +135 -0
  7. execsql/cli/commands/lint.py +233 -0
  8. execsql/cli/commands/listing.py +81 -0
  9. execsql/cli/commands/run.py +451 -0
  10. execsql/cli/dispatch.py +66 -0
  11. execsql/cli/help.py +175 -24
  12. execsql/cli/lint.py +513 -76
  13. execsql/cli/options.py +108 -0
  14. execsql/cli/run.py +41 -14
  15. execsql/config.py +251 -154
  16. execsql/config_validation.py +282 -0
  17. execsql/data/execsql.conf.template +24 -1
  18. execsql/data/script_header.sql +23 -0
  19. execsql/db/factory.py +2 -2
  20. execsql/debug/repl.py +51 -193
  21. execsql/exceptions.py +9 -0
  22. execsql/format.py +87 -75
  23. execsql/interactive.py +232 -0
  24. execsql/manifest.py +189 -0
  25. execsql/metacommands/conditions.py +1 -1
  26. execsql/metacommands/control.py +2 -3
  27. execsql/metacommands/effects.py +124 -0
  28. execsql/script/__init__.py +0 -9
  29. execsql/script/ast.py +1 -1
  30. execsql/script/engine.py +6 -93
  31. execsql/script/executor.py +153 -34
  32. execsql/state.py +11 -2
  33. execsql/state.pyi +3 -0
  34. execsql/utils/color.py +18 -0
  35. execsql/utils/errors.py +11 -1
  36. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/README.md +1 -1
  37. {execsql2-2.23.1.dist-info → execsql2-2.24.0.dist-info}/METADATA +111 -58
  38. {execsql2-2.23.1.dist-info → execsql2-2.24.0.dist-info}/RECORD +55 -39
  39. execsql2-2.24.0.dist-info/entry_points.txt +2 -0
  40. execsql2-2.23.1.dist-info/entry_points.txt +0 -3
  41. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/config_settings.sqlite +0 -0
  42. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
  43. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/make_config_db.sql +0 -0
  44. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/md_compare.sql +0 -0
  45. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/md_glossary.sql +0 -0
  46. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/md_upsert.sql +0 -0
  47. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/pg_compare.sql +0 -0
  48. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/pg_glossary.sql +0 -0
  49. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/pg_upsert.sql +0 -0
  50. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/script_template.sql +0 -0
  51. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/ss_compare.sql +0 -0
  52. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/ss_glossary.sql +0 -0
  53. {execsql2-2.23.1.data → execsql2-2.24.0.data}/data/execsql2_extras/ss_upsert.sql +0 -0
  54. {execsql2-2.23.1.dist-info → execsql2-2.24.0.dist-info}/WHEEL +0 -0
  55. {execsql2-2.23.1.dist-info → execsql2-2.24.0.dist-info}/licenses/LICENSE.txt +0 -0
  56. {execsql2-2.23.1.dist-info → execsql2-2.24.0.dist-info}/licenses/NOTICE +0 -0
execsql/state.pyi CHANGED
@@ -5,6 +5,7 @@ import threading
5
5
  from contextlib import AbstractContextManager
6
6
  from dataclasses import dataclass
7
7
  from typing import Any
8
+ from collections.abc import Callable
8
9
 
9
10
  from execsql.config import ConfigData, StatObj
10
11
  from execsql.db.base import DatabasePool
@@ -65,6 +66,7 @@ gui_manager_queue: Any
65
66
  gui_manager_thread: threading.Thread | None
66
67
  profile_data: list[tuple[Any, ...]] | None
67
68
  step_mode: bool
69
+ prompt_input: Callable[[tuple[list[str], list[Any]] | None], None] | None
68
70
  ast_scripts: dict[str, Any]
69
71
  include_chain: list[str]
70
72
  ast_exec_stack: list[ExecFrame]
@@ -99,6 +101,7 @@ class RuntimeContext:
99
101
  gui_manager_thread: threading.Thread | None
100
102
  profile_data: list[tuple[Any, ...]] | None
101
103
  step_mode: bool
104
+ prompt_input: Callable[[tuple[list[str], list[Any]] | None], None] | None
102
105
  ast_scripts: dict[str, Any]
103
106
  include_chain: list[str]
104
107
  ast_exec_stack: list[ExecFrame]
execsql/utils/color.py ADDED
@@ -0,0 +1,18 @@
1
+ """The user's color preference, as the environment states it.
2
+
3
+ One policy for every place execsql writes ANSI itself (the debug REPL, CLI
4
+ help): ``NO_COLOR`` (https://no-color.org) or ``EXECSQL_NO_COLOR`` set to any
5
+ value turns color off. Whether the stream is a terminal is a separate
6
+ question each caller answers for its own stream.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import os
12
+
13
+ __all__ = ["color_disabled_by_env"]
14
+
15
+
16
+ def color_disabled_by_env() -> bool:
17
+ """Return True when ``NO_COLOR`` or ``EXECSQL_NO_COLOR`` is set."""
18
+ return os.environ.get("NO_COLOR") is not None or os.environ.get("EXECSQL_NO_COLOR") is not None
execsql/utils/errors.py CHANGED
@@ -75,7 +75,7 @@ def stamp_errinfo(errinfo: ErrInfo) -> ErrInfo:
75
75
  """Attach script location from ``_state.last_command`` to an :class:`~execsql.exceptions.ErrInfo`.
76
76
 
77
77
  Reads the source file name, line number, command text, and command type from
78
- the most-recently-executed :class:`~execsql.script.engine.ScriptCmd` and
78
+ the most-recently-executed statement and
79
79
  populates any ``None`` fields on *errinfo*. This ensures that error messages
80
80
  include "Line N of script foo.sql" context even when the ErrInfo was originally
81
81
  created deep inside a handler that had no access to execution state.
@@ -125,6 +125,11 @@ def _run_deferred_script(spec: Any) -> None:
125
125
 
126
126
 
127
127
  def exit_now(exit_status: int, errinfo: ErrInfo | None, logmsg: str | None = None) -> None:
128
+ # An error in input typed at a BREAKPOINT prompt ends
129
+ # that input, not the run: the prompt reports it and reads the next one.
130
+ # HALT and a canceled prompt carry no error and still end the run.
131
+ if errinfo is not None and _state.prompt_input is not None:
132
+ raise errinfo
128
133
  em = None
129
134
  if errinfo is not None:
130
135
  stamp_errinfo(errinfo)
@@ -189,6 +194,11 @@ def exit_now(exit_status: int, errinfo: ErrInfo | None, logmsg: str | None = Non
189
194
  from execsql.utils.fileio import filewriter_end
190
195
 
191
196
  filewriter_end()
197
+ # Last, so the ON ERROR_HALT / ON CANCEL_HALT actions above are in it.
198
+ from execsql import manifest as _manifest
199
+
200
+ if (manifest := _manifest.current()) is not None:
201
+ manifest.finish(exit_status, errinfo)
192
202
  sys.exit(exit_status)
193
203
 
194
204
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Several types of templates are provided that may be useful in conjunction with execsql. These are:
4
4
 
5
- - **execsql.conf** — An annotated reference of every configuration setting with notes on its usage. Generate a fresh copy in any directory with `execsql --init-config > execsql.conf`; the canonical content ships inside the installed package and is loaded via `importlib.resources` (no need to find or copy a source file).
5
+ - **execsql.conf** — An annotated reference of every configuration setting with notes on its usage. Generate a fresh copy in any directory with `execsql config --init > execsql.conf`; the canonical content ships inside the installed package and is loaded via `importlib.resources` (no need to find or copy a source file).
6
6
 
7
7
  - **script_template.sql** — A framework for SQL scripts that make use of several execsql features. It includes sections for custom configuration settings, custom logfile creation, and reporting of unexpected script exits (through user cancellation or errors).
8
8
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: execsql2
3
- Version: 2.23.1
3
+ Version: 2.24.0
4
4
  Summary: Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables.
5
5
  Project-URL: Homepage, https://execsql2.readthedocs.io
6
6
  Project-URL: Repository, https://github.com/geocoug/execsql
@@ -42,7 +42,7 @@ Requires-Python: >=3.10
42
42
  Requires-Dist: python-dateutil>=2.8
43
43
  Requires-Dist: rich>=13.0
44
44
  Requires-Dist: textual>=1.0
45
- Requires-Dist: typer>=0.12
45
+ Requires-Dist: typer>=0.26
46
46
  Provides-Extra: all
47
47
  Requires-Dist: defusedxml>=0.7; extra == 'all'
48
48
  Requires-Dist: duckdb>=1.0; extra == 'all'
@@ -52,7 +52,7 @@ Requires-Dist: keyring>=25.0; extra == 'all'
52
52
  Requires-Dist: odfpy>=1.4; extra == 'all'
53
53
  Requires-Dist: openpyxl>=3.1; extra == 'all'
54
54
  Requires-Dist: oracledb>=3.0; extra == 'all'
55
- Requires-Dist: pg-upsert>=1.23.0; extra == 'all'
55
+ Requires-Dist: pg-upsert>=1.25.0; extra == 'all'
56
56
  Requires-Dist: polars>=1.0; extra == 'all'
57
57
  Requires-Dist: psycopg[binary]<4,>=3.1; extra == 'all'
58
58
  Requires-Dist: pymysql>=1.1; extra == 'all'
@@ -126,7 +126,7 @@ Requires-Dist: oracledb>=3.0; extra == 'oracle'
126
126
  Provides-Extra: postgres
127
127
  Requires-Dist: psycopg[binary]<4,>=3.1; extra == 'postgres'
128
128
  Provides-Extra: upsert
129
- Requires-Dist: pg-upsert>=1.23.0; extra == 'upsert'
129
+ Requires-Dist: pg-upsert>=1.25.0; extra == 'upsert'
130
130
  Description-Content-Type: text/markdown
131
131
 
132
132
  > [!NOTE]
@@ -154,7 +154,54 @@ Description-Content-Type: text/markdown
154
154
 
155
155
  ## Overview
156
156
 
157
- *execsql* runs SQL scripts against PostgreSQL, MySQL/MariaDB, SQLite, DuckDB, MS-SQL-Server, MS-Access, Firebird, Oracle, or an ODBC DSN. In addition to standard SQL, it supports a set of metacommands (embedded in SQL comments) for importing and exporting data, copying data between databases, conditional execution, looping, substitution variables, and interactive prompts. Because metacommands live in SQL comments, scripts remain valid SQL and are ignored by other tools such as `psql` or `sqlcmd`.
157
+ *execsql* is a toolchain for SQL scripts: **write** them with editor support, **format** them consistently, **lint** them without a database, and **run** them against nine DBMSs.
158
+
159
+ Scripts are ordinary SQL plus metacommands embedded in comments (`-- !x!`), which add importing and exporting data, copying between databases, conditional execution, looping, substitution variables, and interactive prompts. Because the metacommands live in comments, the scripts stay valid SQL and other tools (`psql`, `sqlcmd`, your editor) ignore them.
160
+
161
+ | Command | What it does | Needs a database? |
162
+ | ------------------------------------------ | ----------------------------------------------------------------------- | ----------------- |
163
+ | `execsql format` | Normalize keywords, indentation, and SQL layout | No |
164
+ | `execsql lint` | Static analysis: structure, undefined variables, bad targets | No |
165
+ | `execsql run` | Run the script against PostgreSQL, MySQL, SQLite, DuckDB, … | Yes |
166
+ | `execsql config` | Show every config option, its value, and the file that set it | No |
167
+ | `execsql list` | Metacommands, encodings, plugins, or the keyword vocabulary | No |
168
+ | `execsql init` | Set up a project: config file, a script with a header, pre-commit hooks | No |
169
+ | [VS Code extension](extras/vscode-execsql) | Syntax highlighting for metacommands and variables | No |
170
+
171
+ `format` and `lint` take files or directories.
172
+
173
+ > [!WARNING]
174
+ > The original positional form, `execsql script.sql myserver mydb`, still works
175
+ > but is deprecated: it prints a warning and stops working in execsql2 3.0. Use
176
+ > `execsql run script.sql myserver mydb`.
177
+
178
+ ## Quick start: no database required
179
+
180
+ `format` and `lint` work on a bare `.sql` file, with no server and no config. Try them first:
181
+
182
+ ```bash
183
+ pip install execsql2[formatter]
184
+
185
+ execsql format --check scripts/ # is it formatted?
186
+ execsql format -i scripts/ # format it
187
+ execsql lint scripts/ # find problems before they cost you a run
188
+ ```
189
+
190
+ `lint` reports unmatched blocks, undefined and unused substitution variables, unreachable branches, and `INCLUDE`/`SCRIPT` targets that do not exist: the failures that otherwise surface halfway through a run against a live database:
191
+
192
+ ```text
193
+ $ execsql lint load_data.sql
194
+ load_data.sql
195
+ 1 warning V002 variable !!site_cd!! is never used
196
+ 2 warning I001 INCLUDE file does not exist: common/setup.sql
197
+ 3 warning V001 undefined variable !!site_code!!
198
+
199
+ Found 3 issues in 1 file: 3 warnings (1 file checked)
200
+ ```
201
+
202
+ `V002` and `V001` together point at a typo: `site_cd` is defined and `site_code` is used. Every issue has a rule code for `--select` and `--ignore`; `--output-format concise` prints one `path:line` line per issue and `json` feeds CI tools. The [lint rules](https://execsql2.readthedocs.io/en/latest/reference/lint/) page explains each one.
203
+
204
+ `execsql format` also runs as a [pre-commit hook](#formatting-scripts), so formatting is enforced without anyone remembering to run it.
158
205
 
159
206
  ## Example
160
207
 
@@ -197,49 +244,54 @@ The `PROMPT` metacommand produces a GUI display of the data:
197
244
  ## Installation
198
245
 
199
246
  ```bash
200
- pip install execsql2 # core — SQLite works with no extras
247
+ pip install execsql2 # core: SQLite works with no extras
201
248
  pip install "execsql2[postgres]" # add a driver: postgres, mysql, mssql, duckdb, firebird, oracle, odbc
202
249
  pip install "execsql2[all]" # everything: all drivers plus all feature extras
203
250
  ```
204
251
 
205
- Feature extras cover spreadsheet and Parquet/Feather formats, keyring authentication, PostgreSQL upsert, and more — see the [installation guide](https://execsql2.readthedocs.io/en/latest/getting-started/installation/) for the full list.
252
+ Feature extras cover spreadsheet and Parquet/Feather formats, keyring authentication, PostgreSQL upsert, and more. See the [installation guide](https://execsql2.readthedocs.io/en/latest/getting-started/installation/) for the full list.
206
253
 
207
254
  ## Usage
208
255
 
209
256
  ```text
210
- execsql [OPTIONS] SQL_SCRIPT [SERVER DATABASE | DATABASE_FILE]
257
+ execsql run [OPTIONS] SQL_SCRIPT [SERVER DATABASE | DATABASE_FILE]
258
+ execsql format [--check | -i] [--indent N] FILE_OR_DIR...
259
+ execsql lint [OPTIONS] FILE_OR_DIR...
260
+ execsql config [SQL_SCRIPT] [--init] [--config FILE]
261
+ execsql list metacommands|encodings|plugins|keywords
262
+ execsql init [DIR] [--script NAME] [--no-script] [--no-config] [--no-pre-commit]
211
263
  ```
212
264
 
213
265
  Examples:
214
266
 
215
267
  ```bash
216
- execsql -tp script.sql myserver mydb # PostgreSQL
217
- execsql -tm script.sql myserver mydb # MySQL / MariaDB
218
- execsql -ts script.sql myserver mydb # SQL Server
219
- execsql -tl script.sql mydb.sqlite # SQLite
220
- execsql -tk script.sql mydb.duckdb # DuckDB
221
- execsql -to script.sql myserver myservice # Oracle
222
- execsql script.sql # read connection from config file
268
+ execsql run -tp script.sql myserver mydb # PostgreSQL
269
+ execsql run -tm script.sql myserver mydb # MySQL / MariaDB
270
+ execsql run -ts script.sql myserver mydb # SQL Server
271
+ execsql run -tl script.sql mydb.sqlite # SQLite
272
+ execsql run -tk script.sql mydb.duckdb # DuckDB
273
+ execsql run -to script.sql myserver myservice # Oracle
274
+ execsql run script.sql # read connection from config file
223
275
  ```
224
276
 
225
277
  ### Supported Databases
226
278
 
227
- | Flag | Database | Support |
228
- | ---- | --------------- | ------------------------------------------------ |
229
- | `p` | PostgreSQL | Supported — verified against a live server in CI |
230
- | `m` | MySQL / MariaDB | Supported — verified against a live server in CI |
231
- | `s` | MS SQL Server | Supported — verified against a live server in CI |
232
- | `l` | SQLite | Supported — verified against real files in CI |
233
- | `k` | DuckDB | Supported — verified against real files in CI |
234
- | `a` | MS Access | Best effort — not verified in CI |
235
- | `f` | Firebird | Best effort — not verified in CI |
236
- | `o` | Oracle | Best effort — not verified in CI |
237
- | `d` | ODBC DSN | Best effort — not verified in CI |
279
+ | Flag | Database | Support |
280
+ | ---- | --------------- | ----------------------------------------------- |
281
+ | `p` | PostgreSQL | Supported: verified against a live server in CI |
282
+ | `m` | MySQL / MariaDB | Supported: verified against a live server in CI |
283
+ | `s` | MS SQL Server | Supported: verified against a live server in CI |
284
+ | `l` | SQLite | Supported: verified against real files in CI |
285
+ | `k` | DuckDB | Supported: verified against real files in CI |
286
+ | `a` | MS Access | Best effort: not verified in CI |
287
+ | `f` | Firebird | Best effort: not verified in CI |
288
+ | `o` | Oracle | Best effort: not verified in CI |
289
+ | `d` | ODBC DSN | Best effort: not verified in CI |
238
290
 
239
291
  **Supported** adapters run against a live server or a real database file on
240
292
  every CI run; a regression blocks the release and bugs get fixed. **Best
241
293
  effort** adapters are carried forward from the upstream monolith and are not
242
- exercised anywhere in CI — the code is there and may work, but nothing proves
294
+ exercised anywhere in CI. The code is there and may work, but nothing proves
243
295
  it still does. Issues and pull requests are welcome for them; no guarantee is
244
296
  made. Opening a best-effort connection prints one informational line, which
245
297
  `support_tier_notice=No` in the `[interface]` section of `execsql.conf`
@@ -247,24 +299,24 @@ silences.
247
299
 
248
300
  ### Common options
249
301
 
250
- | Flag | Description |
251
- | ------------------------------------------------- | --------------------------------------------------------------- |
252
- | `-t {p,m,s,l,k,a,f,o,d}` | Database type |
253
- | `-u USER` | Database username |
254
- | `-p PORT` | Server port |
255
- | `--dsn URL` | Connection string (e.g. `postgresql://user:pass@host/db`) |
256
- | `-n` | Create a new SQLite or PostgreSQL database if it does not exist |
257
- | `-c SCRIPT` | Execute inline SQL or metacommand string |
258
- | `-a VALUE` | Set substitution variable `$ARG_x` |
259
- | `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
260
- | `--config FILE` | Load an explicit config file |
261
- | `--dry-run` | Parse the script and report commands without executing |
262
- | `--lint` | Static analysis: check structure and warn on issues (no DB) |
263
- | `--ping` | Test database connectivity and exit |
264
- | `--debug` | Start in step-through debug mode (REPL pauses before each stmt) |
265
- | `--no-system-cmd` / `--no-rm-file` / `--no-serve` | Disable the `SYSTEM_CMD` / `RM_FILE` / `SERVE` metacommands |
266
-
267
- See the [full options reference](https://execsql2.readthedocs.io/en/latest/getting-started/syntax/#options) or run `execsql --help` for the complete list, and `execsql -m` for all metacommands.
302
+ | Flag | Description |
303
+ | ------------------------------------------------- | -------------------------------------------------------------------------- |
304
+ | `-t {p,m,s,l,k,a,f,o,d}` | Database type |
305
+ | `-u USER` | Database username |
306
+ | `-p PORT` | Server port |
307
+ | `--dsn URL` | Connection string (e.g. `postgresql://user:pass@host/db`) |
308
+ | `-n` | Create a new SQLite or PostgreSQL database if it does not exist |
309
+ | `-c SCRIPT` | Execute inline SQL or metacommand string |
310
+ | `-a VALUE` | Set substitution variable `$ARG_x` |
311
+ | `--var NAME=VALUE` | Set the substitution variable `!!NAME!!` |
312
+ | `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
313
+ | `--config FILE` | Load an explicit config file |
314
+ | `--dry-run` | Parse the script and report commands without executing |
315
+ | `--manifest FILE` | Write a JSON record of the run: files read and written, statements, errors |
316
+ | `--debug` | Start in step-through debug mode (REPL pauses before each stmt) |
317
+ | `--no-system-cmd` / `--no-rm-file` / `--no-serve` | Disable the `SYSTEM_CMD` / `RM_FILE` / `SERVE` metacommands |
318
+
319
+ See the [full options reference](https://execsql2.readthedocs.io/en/latest/getting-started/syntax/#options) or run `execsql run --help` for the complete list, `execsql run --ping` to test a connection, `execsql config` to see which config files set what, and `execsql list metacommands` for all metacommands.
268
320
 
269
321
  ## Features
270
322
 
@@ -279,7 +331,7 @@ See the [full options reference](https://execsql2.readthedocs.io/en/latest/getti
279
331
  - Conditionally execute SQL and metacommands using `IF`/`ELSE`/`ENDIF` based on data values, DBMS type, or user input.
280
332
  - Loop over blocks of SQL and metacommands using `LOOP`/`ENDLOOP`; include or chain scripts with `INCLUDE` and `SCRIPT`.
281
333
  - Use substitution variables (`SUB`, `$ARG_x`, built-in variables like `$date_tag`) to parameterize scripts.
282
- - Validate data with `ASSERT` — halt the script with a clear error message if a condition is false (ideal for CI pipelines).
334
+ - Validate data with `ASSERT`: halt the script with a clear error message if a condition is false (ideal for CI pipelines).
283
335
 
284
336
  **Interaction & observability**
285
337
 
@@ -334,7 +386,7 @@ if not result.success:
334
386
  result.raise_on_error() # raises ExecSqlError
335
387
  ```
336
388
 
337
- Use a pre-existing database connection instead of a DSN — useful for reusing one connection across multiple `run()` calls, or when connection parameters come from your application's configuration rather than a URL:
389
+ Use a pre-existing database connection instead of a DSN. This is useful for reusing one connection across multiple `run()` calls, or when connection parameters come from your application's configuration rather than a URL:
338
390
 
339
391
  ```python
340
392
  from execsql import run
@@ -357,7 +409,7 @@ loaded = run(
357
409
  variables={"RUN_DATE": "2026-07-03"},
358
410
  )
359
411
 
360
- # run() does NOT close the connection — you manage its lifecycle
412
+ # run() does NOT close the connection; you manage its lifecycle
361
413
  conn.close()
362
414
 
363
415
  # SQLite works the same way
@@ -366,43 +418,44 @@ result = run(sql="SELECT 1;", connection=conn)
366
418
  conn.close()
367
419
  ```
368
420
 
369
- Factory functions exist for every supported backend (`db_Postgres`, `db_MySQL`, `db_SQLite`, `db_DuckDB`, `db_SqlServer`, `db_Oracle`, `db_Firebird`, `db_Access`, `db_Dsn`) — see [`execsql.db.factory`](https://execsql2.readthedocs.io/en/latest/api/db/).
421
+ Factory functions exist for every supported backend (`db_Postgres`, `db_MySQL`, `db_SQLite`, `db_DuckDB`, `db_SqlServer`, `db_Oracle`, `db_Firebird`, `db_Access`, `db_Dsn`). See [`execsql.db.factory`](https://execsql2.readthedocs.io/en/latest/api/db/).
370
422
 
371
423
  Each call to `run()` uses an isolated `RuntimeContext`, so multiple calls do not share state.
372
424
 
373
425
  ## Formatting Scripts
374
426
 
375
- The `execsql-format` command normalizes execsql script files: it uppercases metacommand keywords, corrects block indentation, and optionally reformats SQL via `sqlglot`. The metacommand / indent / keyword reformatting is built into `execsql2`; SQL reformatting requires the `[formatter]` extra (or pass `--no-sql` to skip it):
427
+ The `execsql format` command normalizes execsql script files: it uppercases metacommand keywords, corrects block indentation, and optionally reformats SQL via `sqlglot`. The metacommand / indent / keyword reformatting is built into `execsql2`; SQL reformatting requires the `[formatter]` extra (or pass `--no-sql` to skip it):
376
428
 
377
429
  ```bash
378
430
  # Install with the SQL-reformatting extra
379
431
  pip install execsql2[formatter]
380
432
 
381
433
  # Format files in place
382
- execsql-format --in-place scripts/
434
+ execsql format --in-place scripts/
383
435
 
384
436
  # Check formatting without writing (useful in CI)
385
- execsql-format --check scripts/
437
+ execsql format --check scripts/
386
438
 
387
- # Run the formatter without sqlglot — keyword/indent normalization only
388
- execsql-format --no-sql --in-place scripts/
439
+ # Run the formatter without sqlglot: keyword/indent normalization only
440
+ execsql format --no-sql --in-place scripts/
389
441
  ```
390
442
 
391
- `execsql-format` is also available as a [pre-commit](https://pre-commit.com/) hook:
443
+ `execsql format` and `execsql lint` are also available as [pre-commit](https://pre-commit.com/) hooks. The format hook id is unchanged, so existing configs keep working:
392
444
 
393
445
  ```yaml
394
446
  repos:
395
447
  - repo: https://github.com/geocoug/execsql
396
- rev: v2.23.1
448
+ rev: v2.24.0
397
449
  hooks:
398
450
  - id: execsql-format
451
+ - id: execsql-lint
399
452
  ```
400
453
 
401
- The hook rewrites `*.sql` files in place by default. See the [formatter documentation](https://execsql2.readthedocs.io/en/latest/guides/formatter/) for `--check`, `--indent`, and other options.
454
+ The format hook rewrites `*.sql` files in place by default; the lint hook fails the commit when a script has a lint error. See the [formatter documentation](https://execsql2.readthedocs.io/en/latest/guides/formatter/) for `--check`, `--indent`, and other options.
402
455
 
403
456
  ## VS Code Syntax Highlighting
404
457
 
405
- A VS Code extension for execsql syntax highlighting is included in [`extras/vscode-execsql`](extras/vscode-execsql). It injects a TextMate grammar into `.sql` files, adding highlighting for `-- !x!` metacommand markers, keywords (control flow, block, action, directive), variable substitutions (`!!var!!`, `!{var}!`), built-in functions, export formats, and config options — all layered on top of standard SQL highlighting.
458
+ A VS Code extension for execsql syntax highlighting is included in [`extras/vscode-execsql`](extras/vscode-execsql). It injects a TextMate grammar into `.sql` files, adding highlighting for `-- !x!` metacommand markers, keywords (control flow, block, action, directive), variable substitutions (`!!var!!`, `!{var}!`), built-in functions, export formats, and config options, all layered on top of standard SQL highlighting.
406
459
 
407
460
  To install, symlink the extension folder into your VS Code extensions directory:
408
461
 
@@ -1,29 +1,43 @@
1
1
  execsql/__init__.py,sha256=ZeVnpEWu8M2bn3qLmVM72NhWRueUGNbsX8UAPTermo0,901
2
2
  execsql/__main__.py,sha256=HdbK-SAhyUmfB6xINY5AzxdMSxGzWSGEG_2dv42Jn64,315
3
3
  execsql/api.py,sha256=gBNEINlQSncfhO1tvc-qD1MBXTuhDVIP16LhiqfnzQI,25334
4
- execsql/config.py,sha256=riUh3DVOoScpqF-GK2EAcycu_1Y9PhWTghDuJSSUJjs,34507
5
- execsql/exceptions.py,sha256=GlphAiR8iZu4UR4U50WgSqEUMd9_8AeQJ_hhPcJOeQU,9381
6
- execsql/format.py,sha256=OOxsOX6g7otVgL3gI6uGxa5WIh8GTvjJ8WO-_P91zXg,52886
4
+ execsql/config.py,sha256=Pj6wPOrZbCntI0UkYQoSGTH1dhatQ8z5PdVjw7eY5HY,38531
5
+ execsql/config_validation.py,sha256=a4ZszyJFGTNgs1jkvXE3yMCaYFtF1Uqih2ojMDVh1v8,10556
6
+ execsql/exceptions.py,sha256=aHavdblmP7m5ZLxyyKKmPSwwbdmP962j4ShP1Gd9r64,9651
7
+ execsql/format.py,sha256=RCnHI-L2T0F7zJeswYA4EWO99v88rpf6x8qPp4eILM0,53159
8
+ execsql/interactive.py,sha256=7vm7NAlcarBJJOIffcLOcJqH9ZCInvHB_CmC2sQsXf8,8241
9
+ execsql/manifest.py,sha256=1kpzKIJXRC11ff-NOlppGdc4KYyZrAwg6OwTPbM774U,7698
7
10
  execsql/models.py,sha256=-DWTVrPNwM-n1h3e3rXMoBv9-wpWVdZahyy4RB7fRRE,15502
8
11
  execsql/parser.py,sha256=aOxZ7Mzgvk7G4-nvy9Bgz7xlaZm6oo81cffDeBk_LCk,15597
9
12
  execsql/plugins.py,sha256=l82VWa5NpvOQWD6vcO-WKP-vtn0wp9__wWDFAbwxZg0,12838
10
13
  execsql/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- execsql/state.py,sha256=wu7T1fkXROiQ2LoBYLONYj-1BkDUdoYzV425aCeAwm4,22230
12
- execsql/state.pyi,sha256=YByEn5N7r0M4vDceOoDGTgb2tRJ_gNkYWGjlLiqQorI,3839
14
+ execsql/state.py,sha256=SXJqTsveOgBRzmP08aXwZBdvRcmi-cOKIooA5X5xRAY,22730
15
+ execsql/state.pyi,sha256=yahCOVaKt07Tyt6u7TDd_KewKU2z9i21AtzanlgXQ_Y,4028
13
16
  execsql/types.py,sha256=8rAoRaWwgBnR-ZhNEfahTTbZ_D4fB4vBuGeMEUnu7vE,32454
14
- execsql/cli/__init__.py,sha256=WPwEIELz-9XFG3Dpf-037eeYBdjtZStxWkT1bc3tMek,23112
17
+ execsql/cli/__init__.py,sha256=Yx_WZys7_5V_K6ijeA_AmbUEny5QbUU-_n2eyTnEPMY,3123
18
+ execsql/cli/application.py,sha256=qKjkhDMWB7fEjEbqOLZ3pNFw80piBnRSeW_DfZg-9MA,12448
19
+ execsql/cli/dispatch.py,sha256=ew10mZNXsFHwiNd_etvpSQYD3T8CiexXkjC3Ja94C4w,2697
15
20
  execsql/cli/dsn.py,sha256=svaZtrUXFRL2W5G6FRRiKtR6kehOp7urrVhIx_642Z8,2820
16
- execsql/cli/help.py,sha256=ThwdZuMIfLPxLAPpGWwXFY_UfyWvYOCjdlBNK20Vzd8,5718
17
- execsql/cli/lint.py,sha256=YqKzFNUhyb_Th69hYgKk1ZZVjCsZfJMIiUGqp06JwNs,17236
18
- execsql/cli/run.py,sha256=Yb-Ri3cds0st1hUn4_w-PHMphTsArHhC4fx919SW9gU,39390
21
+ execsql/cli/help.py,sha256=Edr3d2ahKv387a6WGgyJi5vKIFe39tGPgTv1GKp3itE,10848
22
+ execsql/cli/lint.py,sha256=fmWU93Bss2ClaPTVv0GXweFluFgGCZvjh6BUp7SZvLM,33038
23
+ execsql/cli/options.py,sha256=DwforvpFZ3eqL_J5ODcmrp3NQjoNioYcf8wQTzt4nfc,2883
24
+ execsql/cli/run.py,sha256=gYIyikNEuvVCL_labPm_NGuPgQof4VVWo6-_ee7fjYk,40457
25
+ execsql/cli/commands/__init__.py,sha256=wN5sbhKs11S8EZOTBd_GPP6TPjhYfiQkrI48Sy8n6U0,521
26
+ execsql/cli/commands/config.py,sha256=V7CGGkhSCqeJIlAXxAYyG_xNhnsORiwqth2XWEVPzss,8213
27
+ execsql/cli/commands/format.py,sha256=2pftY7nl8FexJ5tnvncxRG-7UjQ_NO0mHxmqAOKd-Nw,3948
28
+ execsql/cli/commands/init.py,sha256=kmuFgGz8sv_1KfiNh190E3A23evqkgYZeBRTU6vdjbs,5465
29
+ execsql/cli/commands/lint.py,sha256=Q9icZcfnmkqfq3Ol5b_xYtjQ13R2EhWQsvPlRkgwiNI,8480
30
+ execsql/cli/commands/listing.py,sha256=gWnjkgcw7uF-DJw3cMZbttOKdplDwAMlhmaBoI5drVw,2511
31
+ execsql/cli/commands/run.py,sha256=w-rjLYSDDTLCh8xuuKjxeqZqdGgJGaydKQBOaL8NYLs,15994
19
32
  execsql/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- execsql/data/execsql.conf.template,sha256=qqH_G3SiKBepljY3Go4rDDlhe3pIM6gOgsjAnLn0arg,11244
33
+ execsql/data/execsql.conf.template,sha256=9eJbFP1EitNokmRg2V-OrkStduF-pOmYR9R5LWRN_wM,11887
34
+ execsql/data/script_header.sql,sha256=a7WKScekNgJoxVEmMRTkWv8NsAzW1jJ4vJfGy9HVy0g,349
21
35
  execsql/db/__init__.py,sha256=jTbuafuKOqYtXFR1wvCOoKK5Lr3l1uErfaIbIr6UywI,1063
22
36
  execsql/db/access.py,sha256=2VlfEDXvV8xoi1t_hKzEaIidCJ1XGerYFPFvW5FqVBI,20489
23
37
  execsql/db/base.py,sha256=2bK1TBU9IAHnQQcdgJ-wEwm5TzrhnwO6j6BGjR9VAHg,40656
24
38
  execsql/db/dsn.py,sha256=hC_oWrBz2NSGyAOjZsROxGHs9eI_CSpnnken12wH1hU,6663
25
39
  execsql/db/duckdb.py,sha256=h8fh_5Ps1UcXvfyG9UlSyP32Yoa0W8sn246RlQ4xOMU,6970
26
- execsql/db/factory.py,sha256=C_cyi3GjNx0opuwc6maFFeCSkjfOfoUjuf68YT4VAHE,5377
40
+ execsql/db/factory.py,sha256=lkyy9_aK-RY6_VvhwyVb3F61PZXLe4RVY6zC6h6ZNzY,5441
27
41
  execsql/db/firebird.py,sha256=fbzlGB6DeR-S9RFLUD4tJYPN-_76tyRLBkQl5LRJTDo,9640
28
42
  execsql/db/mysql.py,sha256=vG_5NPoe82FLvdfY4e7ZnjX0-mgts4D3S40LwZKb7U8,20489
29
43
  execsql/db/oracle.py,sha256=jjXwhk_og1qHqdAB16i_dZYXY0Ze7Bg5EvKdCKwjQtE,12667
@@ -32,7 +46,7 @@ execsql/db/sqlite.py,sha256=zfe-KNAuTIHDh_qk3yzCo6fMerlmtt7UFmg-lbdZFm4,12167
32
46
  execsql/db/sqlserver.py,sha256=O4E9OD3V3Xowsjl3KMdYHNCBeETlkJS9HUzNKEKuA9A,8943
33
47
  execsql/db/tiers.py,sha256=PH2sUYwlYqcANGVKXprWQKVIlM6fpWU9q74djn8oFwc,2924
34
48
  execsql/debug/__init__.py,sha256=j6EGUR0dHzUhWN1mHHtf1-Lhjq3Sb1V-vmnq2Ztgj1M,178
35
- execsql/debug/repl.py,sha256=JObeoEXh15qyk4Q3WQCCqMcBtojlIcu_Xg-ZRDZJi5Q,25491
49
+ execsql/debug/repl.py,sha256=jnwrqRac4krc1pES7Ni-j1Dyw3mJIcWl5LQQIX1GkRw,20753
36
50
  execsql/exporters/__init__.py,sha256=-Cnji-OgodJV8ftcDcOyTof0kQMy9J5kKVC8GVFpc3o,670
37
51
  execsql/exporters/base.py,sha256=_GoO0YqwlTxrjogxHI3CxxRR64sMgIEjRogt0KCqzoY,6402
38
52
  execsql/exporters/delimited.py,sha256=v47Js8ZrQfTqx0aTDAD-9nkOx4ilAPnk_dZT3vAoCTw,33632
@@ -68,12 +82,13 @@ execsql/importers/json.py,sha256=fL47h09Zzx4Qw3TTQRQJbdPdD3qVMiU-kK9C7j1IQzg,553
68
82
  execsql/importers/ods.py,sha256=VsxIkr7opBamB0PbSFmMWt7G11w8lLUH1k_kRwz28zw,2847
69
83
  execsql/importers/xls.py,sha256=D7Ul42gIRYZZC5QxD35ft_wmqQv2f1jNMSbnqlzV0ZA,3851
70
84
  execsql/metacommands/__init__.py,sha256=H_D1Z5kN6zfYtxatejQhQhQV1tlVZ7rcdFZ_9uhXu2Q,13010
71
- execsql/metacommands/conditions.py,sha256=2bfdVV_LCl91quG4SRLur9Jk60NsIOStHlBCeJJ-Djc,30068
85
+ execsql/metacommands/conditions.py,sha256=RJF5vplY6nRPk7oRg_AJ9Q8UdivpCn1srv2ixkJ-pW0,30066
72
86
  execsql/metacommands/connect.py,sha256=SPk4h9yiUgTD3w1gNOT_oYx8VShggsO357by5Hoy6OI,15344
73
- execsql/metacommands/control.py,sha256=QT3CJyneANrHxgnbK7vlwmLbckRCbSSwSxy4D3oxN4A,9375
87
+ execsql/metacommands/control.py,sha256=9swW6X8jXDUpu5cHiAnQVx1ahFyWxlx7mjg4dqYfX5Y,9355
74
88
  execsql/metacommands/data.py,sha256=Rp18lHUKSTkwTFRjOQ7bDgZd42LNLVoTS3Zc_bcNEWY,12199
75
89
  execsql/metacommands/debug.py,sha256=MeVXAob8ItEg2QzuSUkKDaQCEABnH6u0XcAwJzw36CE,13015
76
90
  execsql/metacommands/dispatch.py,sha256=t7x0xWHJA0PeCrYf7jYeSMJgf0yxcZ_xh-_YAtBPHLw,87192
91
+ execsql/metacommands/effects.py,sha256=cRSo48R4nRJzkRR3OGHLhJzofcdAaNIobaxmn1N9TGw,3813
77
92
  execsql/metacommands/io.py,sha256=vlGBje5sgnqeilooMdhJDgSRIhysHy5_7LrKtik9Xjs,3011
78
93
  execsql/metacommands/io_export.py,sha256=YamxQwURRjZRpCG2z8W3QurncCmEmAyLFqDkxtHo5dY,14434
79
94
  execsql/metacommands/io_fileops.py,sha256=l1ZaTMzvsXa88zaQp-scWvUy4TMmN4WVVhr4V6-b-tE,11645
@@ -83,18 +98,19 @@ execsql/metacommands/prompt.py,sha256=7pPURC11qBFcKEI7IdhrttbiBKTc1txjH59QN3dvFy
83
98
  execsql/metacommands/script_ext.py,sha256=CsUbyq8QFPnnvfX_k7fPlYNvvRw1xLmAWER4Exo5pwc,3658
84
99
  execsql/metacommands/system.py,sha256=6X2qmMpGUHDzyEluEotXt0Ks9jKQTpc2x0eoYNgN12M,7997
85
100
  execsql/metacommands/upsert.py,sha256=wzoMpM8g49pEvU9GkHZ62fPvqV3w1UIUfxVA7HAsS_o,20317
86
- execsql/script/__init__.py,sha256=eGJPBDWj42aaId2lX_quSrqoKrvGwGElIrGDNCyoV1Y,3547
87
- execsql/script/ast.py,sha256=TQ4_7Lfw1F8_k6ycdvMZdzwNafrZiljSrthVRWUsuIk,20585
101
+ execsql/script/__init__.py,sha256=I7hVO6wm3iOocxRRGEcFHhjdtL1moKbUYLB-wKbjPdk,3267
102
+ execsql/script/ast.py,sha256=WqCpFxhxrT2IIGvbArTp3QS0BZryRZAb7IL4ri3I6xg,20591
88
103
  execsql/script/control.py,sha256=WqLy-HLPqHG3vEzYpKMiIJsD7LpORjyQuUWzFzcGz4w,2327
89
- execsql/script/engine.py,sha256=KbSB5aXkuDlazh3rRP4vRym_bVTDKmChLQ_OFf3-N8Q,21016
90
- execsql/script/executor.py,sha256=NEIro9TIIcOvugoqdtk2xs08DQnrzkeQIo1CUwaTbIY,37092
104
+ execsql/script/engine.py,sha256=-F_0qacvSq-hNh7fQJ5brk-cslh_mpKJx7p9Nmf_sYA,17603
105
+ execsql/script/executor.py,sha256=IA_1XMmVo7A-XlIZZS-JrgyKykSCUlcXcfZcs7DpMUg,41389
91
106
  execsql/script/parser.py,sha256=VhFTJK8kODNRWgIDc3LjYjA3_SMPFATkpjVl82dYnrM,35179
92
107
  execsql/script/variables.py,sha256=_hklqCeqPbdOT646Yg3ZcpmPke38_8bukMG3eZMTKZw,16384
93
108
  execsql/utils/__init__.py,sha256=0uR6JwVJQRX3vceByNBduCAf5dd5assKjeqJUWvpZoA,278
94
109
  execsql/utils/auth.py,sha256=8Wixkx5nayEBG7RT4WTUQpCiElIKS3yOTV_6_-hHTRs,8889
110
+ execsql/utils/color.py,sha256=goQqhnLg8yERpFolQikA9zYSVcuAm0unKTJiWTbQm-U,634
95
111
  execsql/utils/crypto.py,sha256=KlT6lPk-v0-qQQfAMfWvT9Q6kRdCD3_5JVaLajNocKM,3051
96
112
  execsql/utils/datetime.py,sha256=8BrD24KWeMoouJZiFaXK4HF7plc-O_xrzIw12qOEyp8,3629
97
- execsql/utils/errors.py,sha256=bDWooUmGdN8xqUt6csq466wPqKPLHHSi7U4hsmrFZxA,8577
113
+ execsql/utils/errors.py,sha256=LdIYp9C_m1BjdMhS_3XH4c0Why0ae41OIJr8y58r744,9059
98
114
  execsql/utils/fileio.py,sha256=ONLoXkq5PV4dvNc16UMgi9-EY2Wy4mNUFxneSrX91N0,35231
99
115
  execsql/utils/gui.py,sha256=X5aw6LVoeaAdHaQkymm4ba176jga0cS2GrqxSFWTWTg,23853
100
116
  execsql/utils/mail.py,sha256=SXZac24p62qxDbIviO8VdDZTbKljIoJWgWZfxIGu5zI,6260
@@ -102,23 +118,23 @@ execsql/utils/numeric.py,sha256=_7bi5R6pHjMCkOPne_Sh5nUj-B8e9g6WFmjptFHaunA,1573
102
118
  execsql/utils/regex.py,sha256=B3mSBhRRx_DpUnX_t9IoYd05KvWAebiLMCZqQAmEwcw,3885
103
119
  execsql/utils/strings.py,sha256=UQNjpRCEFa1UO6feU-M-9e24wWAvizs_iu_4fFusLxo,8516
104
120
  execsql/utils/timer.py,sha256=eDYf5VzCNFk7oo90InJucUm3XcBdhYMogjZMqeg9xzc,1899
105
- execsql2-2.23.1.data/data/execsql2_extras/README.md,sha256=vX4NTL095dUoA_hesyRMGYBorEZ_Y_tJ9qrd-MVV09I,5032
106
- execsql2-2.23.1.data/data/execsql2_extras/config_settings.sqlite,sha256=aY5cxR7Q7J6zJ4bC9lu5mHUrhy211Cq3MNKPQVCt02E,20480
107
- execsql2-2.23.1.data/data/execsql2_extras/example_config_prompt.sql,sha256=2e8KzzVWhho8KxYVHETSVmZdhW7wodioDsqBLSL6m4s,7487
108
- execsql2-2.23.1.data/data/execsql2_extras/make_config_db.sql,sha256=WwyC6dK-Eh5CAVppiBCDHqiI1_wEI9U95Ytpr4lsZkg,8726
109
- execsql2-2.23.1.data/data/execsql2_extras/md_compare.sql,sha256=qYYVAjSeHZzjszxV3Bv6bg8Ckbq2kMHl87_gh4sywMU,24140
110
- execsql2-2.23.1.data/data/execsql2_extras/md_glossary.sql,sha256=hkZ2Onn57LAKKsuXxzhR8tPtcWXkmWEQkwPE58-Tm2k,10796
111
- execsql2-2.23.1.data/data/execsql2_extras/md_upsert.sql,sha256=_CAK4BzEboRXTNy03SJR-oOjcEdSNMuRBPL6noWUptY,112560
112
- execsql2-2.23.1.data/data/execsql2_extras/pg_compare.sql,sha256=1zJd4hVUKHR0tncc2qTBC9B4qVV4Us2ITkJpsjN3tMw,24352
113
- execsql2-2.23.1.data/data/execsql2_extras/pg_glossary.sql,sha256=IKuwna-_8b20ljSkXZruuiQigrCpo7ueQdUqd1MXiuI,9908
114
- execsql2-2.23.1.data/data/execsql2_extras/pg_upsert.sql,sha256=HpPJtTHvpEjQy03j-3iPxDEOHMRkudOg7O4D4YR38UI,108315
115
- execsql2-2.23.1.data/data/execsql2_extras/script_template.sql,sha256=2J35ddZPguJ-vwTsz83wErv0jiWUyJcdW_JM0mNKDXA,11155
116
- execsql2-2.23.1.data/data/execsql2_extras/ss_compare.sql,sha256=j1qVNUPXQsEU7-DoVgDJCGcE0EuIl7whLBT3fgeiMAo,24833
117
- execsql2-2.23.1.data/data/execsql2_extras/ss_glossary.sql,sha256=2gLxv34xzKt0vy7hSzJH7a9JiMC3ETrv9MofxQwAibU,13065
118
- execsql2-2.23.1.data/data/execsql2_extras/ss_upsert.sql,sha256=G_8rQ0VzuKIZHWs24O_WrfzpC5S27R1JsL-bFBR3SUQ,117730
119
- execsql2-2.23.1.dist-info/METADATA,sha256=Zp_UKzwuqCVFmA3-yQrsaenr3QI_sFkgWAtNAQpl-OE,21504
120
- execsql2-2.23.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
121
- execsql2-2.23.1.dist-info/entry_points.txt,sha256=sUOxkM-dN1eBGGpSpDLsAaE0yNXYQKWZAfxPOlMkQyk,90
122
- execsql2-2.23.1.dist-info/licenses/LICENSE.txt,sha256=LBdhuxejF8_bLCHZ2kWfmDXpDGUu914Gbd6_3JjCRe0,676
123
- execsql2-2.23.1.dist-info/licenses/NOTICE,sha256=McYzgxYav3U1OaVsY4Su1sfBrfmplpRdA9b6-gCDQCg,342
124
- execsql2-2.23.1.dist-info/RECORD,,
121
+ execsql2-2.24.0.data/data/execsql2_extras/README.md,sha256=7SG9FbBpdqkgQTTt1aBTbCgymBZyV0rLrQMQrendzxs,5032
122
+ execsql2-2.24.0.data/data/execsql2_extras/config_settings.sqlite,sha256=aY5cxR7Q7J6zJ4bC9lu5mHUrhy211Cq3MNKPQVCt02E,20480
123
+ execsql2-2.24.0.data/data/execsql2_extras/example_config_prompt.sql,sha256=2e8KzzVWhho8KxYVHETSVmZdhW7wodioDsqBLSL6m4s,7487
124
+ execsql2-2.24.0.data/data/execsql2_extras/make_config_db.sql,sha256=WwyC6dK-Eh5CAVppiBCDHqiI1_wEI9U95Ytpr4lsZkg,8726
125
+ execsql2-2.24.0.data/data/execsql2_extras/md_compare.sql,sha256=qYYVAjSeHZzjszxV3Bv6bg8Ckbq2kMHl87_gh4sywMU,24140
126
+ execsql2-2.24.0.data/data/execsql2_extras/md_glossary.sql,sha256=hkZ2Onn57LAKKsuXxzhR8tPtcWXkmWEQkwPE58-Tm2k,10796
127
+ execsql2-2.24.0.data/data/execsql2_extras/md_upsert.sql,sha256=_CAK4BzEboRXTNy03SJR-oOjcEdSNMuRBPL6noWUptY,112560
128
+ execsql2-2.24.0.data/data/execsql2_extras/pg_compare.sql,sha256=1zJd4hVUKHR0tncc2qTBC9B4qVV4Us2ITkJpsjN3tMw,24352
129
+ execsql2-2.24.0.data/data/execsql2_extras/pg_glossary.sql,sha256=IKuwna-_8b20ljSkXZruuiQigrCpo7ueQdUqd1MXiuI,9908
130
+ execsql2-2.24.0.data/data/execsql2_extras/pg_upsert.sql,sha256=HpPJtTHvpEjQy03j-3iPxDEOHMRkudOg7O4D4YR38UI,108315
131
+ execsql2-2.24.0.data/data/execsql2_extras/script_template.sql,sha256=2J35ddZPguJ-vwTsz83wErv0jiWUyJcdW_JM0mNKDXA,11155
132
+ execsql2-2.24.0.data/data/execsql2_extras/ss_compare.sql,sha256=j1qVNUPXQsEU7-DoVgDJCGcE0EuIl7whLBT3fgeiMAo,24833
133
+ execsql2-2.24.0.data/data/execsql2_extras/ss_glossary.sql,sha256=2gLxv34xzKt0vy7hSzJH7a9JiMC3ETrv9MofxQwAibU,13065
134
+ execsql2-2.24.0.data/data/execsql2_extras/ss_upsert.sql,sha256=G_8rQ0VzuKIZHWs24O_WrfzpC5S27R1JsL-bFBR3SUQ,117730
135
+ execsql2-2.24.0.dist-info/METADATA,sha256=IR9FCVJ_TpwHfIa53JA3I3SkVKyjp-7Gj5aBQveBeiw,25173
136
+ execsql2-2.24.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
137
+ execsql2-2.24.0.dist-info/entry_points.txt,sha256=jOf53-4IVGjEZeNYUOF1GGaiPNfVZcNKxP3vDFKEyMA,58
138
+ execsql2-2.24.0.dist-info/licenses/LICENSE.txt,sha256=LBdhuxejF8_bLCHZ2kWfmDXpDGUu914Gbd6_3JjCRe0,676
139
+ execsql2-2.24.0.dist-info/licenses/NOTICE,sha256=McYzgxYav3U1OaVsY4Su1sfBrfmplpRdA9b6-gCDQCg,342
140
+ execsql2-2.24.0.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ execsql = execsql.cli.dispatch:dispatch
@@ -1,3 +0,0 @@
1
- [console_scripts]
2
- execsql = execsql.cli:_legacy_main
3
- execsql-format = execsql.format:main