execsql2 2.10.1__py3-none-any.whl → 2.11.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.
- execsql/cli/__init__.py +6 -0
- execsql/cli/run.py +5 -1
- execsql/metacommands/debug_repl.py +105 -44
- execsql/script/engine.py +10 -6
- execsql/utils/errors.py +41 -2
- {execsql2-2.10.1.dist-info → execsql2-2.11.0.dist-info}/METADATA +2 -1
- {execsql2-2.10.1.dist-info → execsql2-2.11.0.dist-info}/RECORD +26 -26
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/README.md +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/config_settings.sqlite +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/execsql.conf +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/make_config_db.sql +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/md_compare.sql +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/md_glossary.sql +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/md_upsert.sql +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/pg_compare.sql +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/pg_glossary.sql +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/pg_upsert.sql +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/script_template.sql +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/ss_compare.sql +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/ss_glossary.sql +0 -0
- {execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/ss_upsert.sql +0 -0
- {execsql2-2.10.1.dist-info → execsql2-2.11.0.dist-info}/WHEEL +0 -0
- {execsql2-2.10.1.dist-info → execsql2-2.11.0.dist-info}/entry_points.txt +0 -0
- {execsql2-2.10.1.dist-info → execsql2-2.11.0.dist-info}/licenses/LICENSE.txt +0 -0
- {execsql2-2.10.1.dist-info → execsql2-2.11.0.dist-info}/licenses/NOTICE +0 -0
execsql/cli/__init__.py
CHANGED
|
@@ -278,6 +278,11 @@ def main(
|
|
|
278
278
|
"--profile",
|
|
279
279
|
help="Record per-statement execution times and print a timing summary after the script completes.",
|
|
280
280
|
),
|
|
281
|
+
debug: bool = typer.Option(
|
|
282
|
+
False,
|
|
283
|
+
"--debug",
|
|
284
|
+
help="Start in step-through debug mode. The debug REPL pauses before each statement.",
|
|
285
|
+
),
|
|
281
286
|
version: bool | None = typer.Option(
|
|
282
287
|
None,
|
|
283
288
|
"--version",
|
|
@@ -446,6 +451,7 @@ def main(
|
|
|
446
451
|
profile=profile,
|
|
447
452
|
ping=ping,
|
|
448
453
|
lint=lint,
|
|
454
|
+
debug=debug,
|
|
449
455
|
)
|
|
450
456
|
|
|
451
457
|
|
execsql/cli/run.py
CHANGED
|
@@ -214,6 +214,7 @@ def _run(
|
|
|
214
214
|
profile: bool = False,
|
|
215
215
|
ping: bool = False,
|
|
216
216
|
lint: bool = False,
|
|
217
|
+
debug: bool = False,
|
|
217
218
|
) -> None:
|
|
218
219
|
"""Initialise state, connect to the database, load the script, and run it.
|
|
219
220
|
|
|
@@ -547,6 +548,9 @@ def _run(
|
|
|
547
548
|
if profile:
|
|
548
549
|
_state.profile_data = []
|
|
549
550
|
|
|
551
|
+
if debug:
|
|
552
|
+
_state.step_mode = True
|
|
553
|
+
|
|
550
554
|
_execute_script_direct(conf, profile=profile)
|
|
551
555
|
|
|
552
556
|
|
|
@@ -653,7 +657,7 @@ def _execute_script_direct(conf: ConfigData, *, profile: bool = False) -> None:
|
|
|
653
657
|
lno = strace[0][1]
|
|
654
658
|
msg = f"{Path(sys.argv[0]).name}: Uncaught exception {sys.exc_info()[0]} ({sys.exc_info()[1]}) on line {lno}"
|
|
655
659
|
script, slno = current_script_line()
|
|
656
|
-
if script
|
|
660
|
+
if script:
|
|
657
661
|
msg += f" in script {script}, line {slno}"
|
|
658
662
|
from execsql.utils.errors import exit_now
|
|
659
663
|
|
|
@@ -13,6 +13,11 @@ The REPL allows the user to:
|
|
|
13
13
|
- Step through the script one statement at a time.
|
|
14
14
|
- Resume or abort execution.
|
|
15
15
|
|
|
16
|
+
All REPL commands are dot-prefixed (``.continue``, ``.vars``, ``.next``)
|
|
17
|
+
to avoid ambiguity with variable names and SQL. Anything not starting
|
|
18
|
+
with ``.`` is treated as either a variable lookup (if it matches a known
|
|
19
|
+
variable) or SQL (if it ends with ``;``).
|
|
20
|
+
|
|
16
21
|
In non-interactive environments (CI, piped input, ``sys.stdin.isatty()`` is
|
|
17
22
|
``False``) the metacommand is silently skipped so automated pipelines are not
|
|
18
23
|
blocked.
|
|
@@ -30,15 +35,19 @@ __all__ = ["x_breakpoint"]
|
|
|
30
35
|
# ---------------------------------------------------------------------------
|
|
31
36
|
|
|
32
37
|
_HELP_TEXT = """\
|
|
33
|
-
execsql debug REPL commands
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
next n
|
|
40
|
-
stack Show the command-list stack (script name, line, depth)
|
|
41
|
-
help Show this help text
|
|
38
|
+
execsql debug REPL — all commands start with '.'
|
|
39
|
+
|
|
40
|
+
.continue .c Resume script execution
|
|
41
|
+
.abort .q Halt the script (exit 1)
|
|
42
|
+
.vars List user, system, local, and counter variables
|
|
43
|
+
.vars all Include environment variables (&) in the listing
|
|
44
|
+
.next .n Execute the next statement then pause again (step mode)
|
|
45
|
+
.stack Show the command-list stack (script name, line, depth)
|
|
46
|
+
.help Show this help text
|
|
47
|
+
|
|
48
|
+
Everything else:
|
|
49
|
+
varname Print a variable's value (e.g. logfile, $ARG_1, &HOME)
|
|
50
|
+
SELECT ...; Run ad-hoc SQL against the current database
|
|
42
51
|
"""
|
|
43
52
|
|
|
44
53
|
|
|
@@ -64,7 +73,7 @@ def x_breakpoint(**kwargs: Any) -> None:
|
|
|
64
73
|
def _debug_repl() -> None:
|
|
65
74
|
"""Interactive read-eval-print loop for script debugging.
|
|
66
75
|
|
|
67
|
-
Reads commands from stdin until the user types
|
|
76
|
+
Reads commands from stdin until the user types ``.continue`` or ``.abort``,
|
|
68
77
|
or until EOF / KeyboardInterrupt.
|
|
69
78
|
"""
|
|
70
79
|
try:
|
|
@@ -72,7 +81,7 @@ def _debug_repl() -> None:
|
|
|
72
81
|
except ImportError:
|
|
73
82
|
pass # readline not available on Windows; continue without it
|
|
74
83
|
|
|
75
|
-
_write("\n[Breakpoint] Script paused. Type 'help' for commands, '
|
|
84
|
+
_write("\n[Breakpoint] Script paused. Type '.help' for commands, '.c' to resume.\n")
|
|
76
85
|
|
|
77
86
|
while True:
|
|
78
87
|
try:
|
|
@@ -87,27 +96,48 @@ def _debug_repl() -> None:
|
|
|
87
96
|
if not line:
|
|
88
97
|
continue
|
|
89
98
|
|
|
90
|
-
|
|
99
|
+
# Dot-prefixed → REPL command
|
|
100
|
+
if line.startswith("."):
|
|
101
|
+
_handle_dot_command(line)
|
|
102
|
+
if line.lower().lstrip(".") in ("continue", "c"):
|
|
103
|
+
return
|
|
104
|
+
if line.lower().lstrip(".") in ("abort", "q", "quit"):
|
|
105
|
+
# _handle_dot_command already raised SystemExit, but guard anyway
|
|
106
|
+
return
|
|
107
|
+
if line.lower().lstrip(".") in ("next", "n"):
|
|
108
|
+
return
|
|
109
|
+
continue
|
|
91
110
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
elif lower in ("abort", "q", "quit"):
|
|
95
|
-
raise SystemExit(1)
|
|
96
|
-
elif lower == "help":
|
|
97
|
-
_write(_HELP_TEXT)
|
|
98
|
-
elif lower == "vars":
|
|
99
|
-
_print_all_vars()
|
|
100
|
-
elif lower == "stack":
|
|
101
|
-
_print_stack()
|
|
102
|
-
elif lower in ("next", "n"):
|
|
103
|
-
_enable_step_mode()
|
|
104
|
-
return
|
|
105
|
-
elif line[0] in ("$", "&", "@"):
|
|
106
|
-
_print_var(line)
|
|
107
|
-
elif line.rstrip().endswith(";"):
|
|
111
|
+
# SQL (ends with semicolon)
|
|
112
|
+
if line.rstrip().endswith(";"):
|
|
108
113
|
_run_sql(line)
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
continue
|
|
115
|
+
|
|
116
|
+
# Everything else → variable lookup
|
|
117
|
+
_print_var(line)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _handle_dot_command(line: str) -> None:
|
|
121
|
+
"""Dispatch a dot-prefixed REPL command."""
|
|
122
|
+
# Strip the leading dot and normalize
|
|
123
|
+
cmd = line[1:].strip().lower()
|
|
124
|
+
|
|
125
|
+
if cmd in ("continue", "c"):
|
|
126
|
+
return # caller checks and returns from _debug_repl
|
|
127
|
+
elif cmd in ("abort", "q", "quit"):
|
|
128
|
+
raise SystemExit(1)
|
|
129
|
+
elif cmd == "help":
|
|
130
|
+
_write(_HELP_TEXT)
|
|
131
|
+
elif cmd == "vars all":
|
|
132
|
+
_print_all_vars(include_env=True)
|
|
133
|
+
elif cmd == "vars":
|
|
134
|
+
_print_all_vars()
|
|
135
|
+
elif cmd == "stack":
|
|
136
|
+
_print_stack()
|
|
137
|
+
elif cmd in ("next", "n"):
|
|
138
|
+
_enable_step_mode()
|
|
139
|
+
else:
|
|
140
|
+
_write(f" Unknown command: {line!r}. Type '.help' for available commands.\n")
|
|
111
141
|
|
|
112
142
|
|
|
113
143
|
# ---------------------------------------------------------------------------
|
|
@@ -125,8 +155,8 @@ def _write(text: str) -> None:
|
|
|
125
155
|
sys.stdout.flush()
|
|
126
156
|
|
|
127
157
|
|
|
128
|
-
def _print_all_vars() -> None:
|
|
129
|
-
"""Print
|
|
158
|
+
def _print_all_vars(*, include_env: bool = False) -> None:
|
|
159
|
+
"""Print substitution variables grouped by type."""
|
|
130
160
|
subvars = _state.subvars
|
|
131
161
|
if subvars is None:
|
|
132
162
|
_write(" (no substitution variables defined)\n")
|
|
@@ -135,17 +165,52 @@ def _print_all_vars() -> None:
|
|
|
135
165
|
if not items:
|
|
136
166
|
_write(" (no substitution variables defined)\n")
|
|
137
167
|
return
|
|
138
|
-
|
|
139
|
-
|
|
168
|
+
|
|
169
|
+
# Group by prefix.
|
|
170
|
+
user_vars: list[tuple[str, str]] = []
|
|
171
|
+
system_vars: list[tuple[str, str]] = []
|
|
172
|
+
counter_vars: list[tuple[str, str]] = []
|
|
173
|
+
local_vars: list[tuple[str, str]] = []
|
|
174
|
+
env_vars: list[tuple[str, str]] = []
|
|
175
|
+
|
|
140
176
|
for name, value in sorted(items):
|
|
141
|
-
|
|
177
|
+
if name.startswith("&"):
|
|
178
|
+
env_vars.append((name, value))
|
|
179
|
+
elif name.startswith("~"):
|
|
180
|
+
local_vars.append((name, value))
|
|
181
|
+
elif name.startswith("@"):
|
|
182
|
+
counter_vars.append((name, value))
|
|
183
|
+
elif name.startswith("$"):
|
|
184
|
+
system_vars.append((name, value))
|
|
185
|
+
else:
|
|
186
|
+
user_vars.append((name, value))
|
|
187
|
+
|
|
188
|
+
def _print_group(label: str, group: list[tuple[str, str]]) -> None:
|
|
189
|
+
if not group:
|
|
190
|
+
return
|
|
191
|
+
_write(f" {label}:\n")
|
|
192
|
+
max_name = max(len(n) for n, _ in group)
|
|
193
|
+
for name, value in group:
|
|
194
|
+
_write(f" {name:<{max_name}} = {value}\n")
|
|
195
|
+
|
|
196
|
+
_print_group("User variables", user_vars)
|
|
197
|
+
_print_group("System variables ($)", system_vars)
|
|
198
|
+
_print_group("Local variables (~)", local_vars)
|
|
199
|
+
_print_group("Counter variables (@)", counter_vars)
|
|
200
|
+
if include_env:
|
|
201
|
+
_print_group("Environment variables (&)", env_vars)
|
|
202
|
+
|
|
203
|
+
if not any([user_vars, system_vars, local_vars, counter_vars]):
|
|
204
|
+
if env_vars:
|
|
205
|
+
_write(" (no script variables defined — use '.vars all' to see environment variables)\n")
|
|
206
|
+
else:
|
|
207
|
+
_write(" (no variables defined)\n")
|
|
142
208
|
|
|
143
209
|
|
|
144
210
|
def _print_var(varname: str) -> None:
|
|
145
211
|
"""Print the value of a single substitution variable.
|
|
146
212
|
|
|
147
|
-
|
|
148
|
-
varname: The variable reference as typed by the user, e.g. ``$FOO``.
|
|
213
|
+
Tries the name as typed, then with the sigil prefix stripped.
|
|
149
214
|
"""
|
|
150
215
|
subvars = _state.subvars
|
|
151
216
|
if subvars is None:
|
|
@@ -153,14 +218,14 @@ def _print_var(varname: str) -> None:
|
|
|
153
218
|
return
|
|
154
219
|
# Try the name as typed first, then without the sigil prefix ($, &, @, #, ~).
|
|
155
220
|
# SUB creates variables without a prefix (e.g., "logfile"), but users
|
|
156
|
-
#
|
|
221
|
+
# may type "$logfile" at the prompt.
|
|
157
222
|
value = subvars.varvalue(varname)
|
|
158
223
|
if value is None and len(varname) > 1 and varname[0] in "$&@#~":
|
|
159
224
|
value = subvars.varvalue(varname[1:])
|
|
160
225
|
if value is None:
|
|
161
226
|
_write(f" {varname}: (undefined)\n")
|
|
162
227
|
else:
|
|
163
|
-
_write(f" {varname} = {value
|
|
228
|
+
_write(f" {varname} = {value}\n")
|
|
164
229
|
|
|
165
230
|
|
|
166
231
|
def _print_stack() -> None:
|
|
@@ -177,11 +242,7 @@ def _print_stack() -> None:
|
|
|
177
242
|
|
|
178
243
|
|
|
179
244
|
def _run_sql(sql: str) -> None:
|
|
180
|
-
"""Execute ad-hoc SQL against the current database and pretty-print the results.
|
|
181
|
-
|
|
182
|
-
Args:
|
|
183
|
-
sql: A complete SQL statement ending with a semicolon.
|
|
184
|
-
"""
|
|
245
|
+
"""Execute ad-hoc SQL against the current database and pretty-print the results."""
|
|
185
246
|
dbs = _state.dbs
|
|
186
247
|
if dbs is None:
|
|
187
248
|
_write(" (no database connection is active)\n")
|
execsql/script/engine.py
CHANGED
|
@@ -306,6 +306,7 @@ class SqlStmt:
|
|
|
306
306
|
e = ErrInfo(type="exception", exception_msg=exception_desc())
|
|
307
307
|
if e:
|
|
308
308
|
_state.subvars.add_substitution("$LAST_ERROR", cmd)
|
|
309
|
+
_state.subvars.add_substitution("$ERROR_MESSAGE", str(e))
|
|
309
310
|
_state.status.sql_error = True
|
|
310
311
|
if _state.status.halt_on_err:
|
|
311
312
|
from execsql.utils.errors import exit_now
|
|
@@ -350,8 +351,11 @@ class MetacommandStmt:
|
|
|
350
351
|
if e:
|
|
351
352
|
_state.status.metacommand_error = True
|
|
352
353
|
_state.subvars.add_substitution("$LAST_ERROR", cmd)
|
|
354
|
+
_state.subvars.add_substitution("$ERROR_MESSAGE", str(e))
|
|
353
355
|
if _state.status.halt_on_metacommand_err:
|
|
354
|
-
raise ErrInfo
|
|
356
|
+
# Re-raise the original ErrInfo so its message is preserved, not
|
|
357
|
+
# replaced with the generic "Unknown metacommand" text.
|
|
358
|
+
raise e
|
|
355
359
|
if _state.if_stack.all_true():
|
|
356
360
|
# but nothing applies, because we got here.
|
|
357
361
|
_state.status.metacommand_error = True
|
|
@@ -489,6 +493,11 @@ class CommandList:
|
|
|
489
493
|
_state.subvars.add_substitution("$CURRENT_SCRIPT_NAME", Path(cmditem.source).name)
|
|
490
494
|
_state.subvars.add_substitution("$CURRENT_SCRIPT_LINE", str(cmditem.line_no))
|
|
491
495
|
_state.subvars.add_substitution("$SCRIPT_LINE", str(cmditem.line_no))
|
|
496
|
+
if _state.step_mode:
|
|
497
|
+
_state.step_mode = False
|
|
498
|
+
from execsql.metacommands.debug_repl import _debug_repl
|
|
499
|
+
|
|
500
|
+
_debug_repl()
|
|
492
501
|
_profiling = _state.profile_data is not None
|
|
493
502
|
if _profiling:
|
|
494
503
|
import time as _time
|
|
@@ -506,11 +515,6 @@ class CommandList:
|
|
|
506
515
|
cmditem.command.commandline()[:100],
|
|
507
516
|
),
|
|
508
517
|
)
|
|
509
|
-
if _state.step_mode:
|
|
510
|
-
_state.step_mode = False
|
|
511
|
-
from execsql.metacommands.debug_repl import _debug_repl
|
|
512
|
-
|
|
513
|
-
_debug_repl()
|
|
514
518
|
self.cmdptr += 1
|
|
515
519
|
|
|
516
520
|
def run_next(self) -> None:
|
execsql/utils/errors.py
CHANGED
|
@@ -30,6 +30,7 @@ __all__ = [
|
|
|
30
30
|
"exception_desc",
|
|
31
31
|
"exit_now",
|
|
32
32
|
"fatal_error",
|
|
33
|
+
"stamp_errinfo",
|
|
33
34
|
"write_warning",
|
|
34
35
|
"file_size_date",
|
|
35
36
|
"chainfuncs",
|
|
@@ -70,9 +71,37 @@ def exception_desc() -> str:
|
|
|
70
71
|
return f"{exc_type}: {exc_strval} in {exc_filename} on line {exc_lineno} of execsql."
|
|
71
72
|
|
|
72
73
|
|
|
74
|
+
def stamp_errinfo(errinfo: ErrInfo) -> ErrInfo:
|
|
75
|
+
"""Attach script location from ``_state.last_command`` to an :class:`~execsql.exceptions.ErrInfo`.
|
|
76
|
+
|
|
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
|
|
79
|
+
populates any ``None`` fields on *errinfo*. This ensures that error messages
|
|
80
|
+
include "Line N of script foo.sql" context even when the ErrInfo was originally
|
|
81
|
+
created deep inside a handler that had no access to execution state.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
errinfo: The :class:`~execsql.exceptions.ErrInfo` to stamp.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
The same *errinfo* object, with location fields populated.
|
|
88
|
+
"""
|
|
89
|
+
lc = _state.last_command
|
|
90
|
+
if lc is not None and errinfo.script_file is None:
|
|
91
|
+
errinfo.script_file = lc.source
|
|
92
|
+
errinfo.script_line_no = lc.line_no
|
|
93
|
+
if errinfo.cmd is None:
|
|
94
|
+
errinfo.cmd = lc.command.commandline() if hasattr(lc.command, "commandline") else None
|
|
95
|
+
errinfo.cmdtype = lc.command_type
|
|
96
|
+
return errinfo
|
|
97
|
+
|
|
98
|
+
|
|
73
99
|
def exit_now(exit_status: int, errinfo: ErrInfo | None, logmsg: str | None = None) -> None:
|
|
74
100
|
em = None
|
|
75
101
|
if errinfo is not None:
|
|
102
|
+
stamp_errinfo(errinfo)
|
|
103
|
+
if _state.subvars is not None:
|
|
104
|
+
_state.subvars.add_substitution("$ERROR_MESSAGE", errinfo.errmsg())
|
|
76
105
|
em = errinfo.write()
|
|
77
106
|
if _state.err_halt_writespec is not None:
|
|
78
107
|
try:
|
|
@@ -147,10 +176,20 @@ def fatal_error(error_msg: str | None = None) -> None:
|
|
|
147
176
|
exit_now(1, ErrInfo("error", other_msg=error_msg))
|
|
148
177
|
|
|
149
178
|
|
|
150
|
-
def write_warning(warning_msg: str) -> None:
|
|
179
|
+
def write_warning(warning_msg: str, *, always: bool = False) -> None:
|
|
180
|
+
"""Write a non-fatal warning message to the log and optionally to stderr.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
warning_msg: The warning text to emit.
|
|
184
|
+
always: When ``True``, always write to stderr regardless of the
|
|
185
|
+
``conf.write_warnings`` setting. Use this for structural warnings
|
|
186
|
+
(e.g. IF-level mismatch, unsubstituted variables) that should always
|
|
187
|
+
be visible. When ``False`` (default), stderr output is gated by
|
|
188
|
+
``conf.write_warnings``.
|
|
189
|
+
"""
|
|
151
190
|
if _state.exec_log is not None:
|
|
152
191
|
_state.exec_log.log_status_warning(warning_msg)
|
|
153
|
-
if _state.
|
|
192
|
+
if _state.output is not None and (always or (_state.conf is not None and _state.conf.write_warnings)):
|
|
154
193
|
_state.output.write_err(f"**** Warning {warning_msg}")
|
|
155
194
|
|
|
156
195
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.11.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: Repository, https://github.com/geocoug/execsql
|
|
6
6
|
Project-URL: Issues, https://github.com/geocoug/execsql/issues
|
|
@@ -223,6 +223,7 @@ execsql script.sql # read connection from config file
|
|
|
223
223
|
| `--dry-run` | Parse the script and report commands without executing |
|
|
224
224
|
| `--lint` | Static analysis: check structure and warn on issues (no DB) |
|
|
225
225
|
| `--progress` | Show a progress bar for long-running IMPORT operations |
|
|
226
|
+
| `--debug` | Start in step-through debug mode (REPL pauses before each stmt) |
|
|
226
227
|
| `--dump-keywords` | Print metacommand keywords as JSON and exit |
|
|
227
228
|
| `--gui-framework {tkinter,textual}` | GUI framework for interactive prompts |
|
|
228
229
|
|
|
@@ -9,11 +9,11 @@ execsql/parser.py,sha256=mbNSMiAMR1NvNvFtQAZq6nxBOupMGJZXSimLWLtZeNs,15537
|
|
|
9
9
|
execsql/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
execsql/state.py,sha256=ovUQOr78R3LzsDUzBLL9Bq9ZdHiiFVlBvCNzilQ-K-s,15055
|
|
11
11
|
execsql/types.py,sha256=HVWb4umIB9lpxCGgqk3xy1hoGYPfN39xci5mHF0Izq4,31882
|
|
12
|
-
execsql/cli/__init__.py,sha256=
|
|
12
|
+
execsql/cli/__init__.py,sha256=dPKq7KOY7soD1GfBEztoRWcKuDLY5QyhzgC6PuyeyII,16270
|
|
13
13
|
execsql/cli/dsn.py,sha256=svaZtrUXFRL2W5G6FRRiKtR6kehOp7urrVhIx_642Z8,2820
|
|
14
14
|
execsql/cli/help.py,sha256=Sn_TgSJiQeBx-xZH0fuP5OvR_wasSTumjWF9UHfIX5k,5414
|
|
15
15
|
execsql/cli/lint.py,sha256=KluYROdjGJNUrVbO3cJym-H296zbih4no-F10HF0P4U,16165
|
|
16
|
-
execsql/cli/run.py,sha256=
|
|
16
|
+
execsql/cli/run.py,sha256=p4QWuBO7WvMPAJDyLtwiVZAdpwjgq1H3wz__WgUiRKA,30218
|
|
17
17
|
execsql/db/__init__.py,sha256=jTbuafuKOqYtXFR1wvCOoKK5Lr3l1uErfaIbIr6UywI,1063
|
|
18
18
|
execsql/db/access.py,sha256=L79gUnAnnM9EJ_f4k42jr7DI0qGcKtLOnJTlBC7uPm0,17879
|
|
19
19
|
execsql/db/base.py,sha256=hfMFj8fXY0T1aXLvWJHqb0aU4EQUDFOc-YrS29HH8U4,30405
|
|
@@ -65,7 +65,7 @@ execsql/metacommands/connect.py,sha256=Nsm0D91i3RX-R2rzQQ-Br-gULaI6Uvdn9fqb7DOAV
|
|
|
65
65
|
execsql/metacommands/control.py,sha256=CBCg0ZKSR-BGejBW5cXwk6aJ9VrYBzCg9C40ofi8qi8,8776
|
|
66
66
|
execsql/metacommands/data.py,sha256=tRQBGTAuW-eJ2tBNWaoZI9OjTyNNyHJISo7gOdL-sm8,11370
|
|
67
67
|
execsql/metacommands/debug.py,sha256=nmfQ2ijUbTQO3drnyV9EzFueGSTfMl-CddP_NlQyI14,8178
|
|
68
|
-
execsql/metacommands/debug_repl.py,sha256=
|
|
68
|
+
execsql/metacommands/debug_repl.py,sha256=TA4aDWgl_wvR63R9ddBIF-vUB2wRamsxdxzeM8F3WZo,9805
|
|
69
69
|
execsql/metacommands/dispatch.py,sha256=1Mae6yqrea6wViFLBsvVt33Zgx4xP8tnhOuB_aQC89c,84054
|
|
70
70
|
execsql/metacommands/io.py,sha256=Duh60caM4go9JczbGYNMKKYpcMimwPzF6EQ_tshKxdE,2971
|
|
71
71
|
execsql/metacommands/io_export.py,sha256=7lkCSnPhXy9FVau9_hT1u68NOVdG2DsWmvUh9hM1QWI,18359
|
|
@@ -77,13 +77,13 @@ execsql/metacommands/script_ext.py,sha256=TUgAldB2LSJAwZrCvDDi804hQ1d9BDQD2GDqHN
|
|
|
77
77
|
execsql/metacommands/system.py,sha256=sUR5kLL7idTVg8WXIMdd-Kv7nkERIiaeL0beWsz8NyY,7293
|
|
78
78
|
execsql/script/__init__.py,sha256=pIo0EJ7-vg67rSMbOvbri_BOUgLoGoSEUfJgxUN7ZS0,3380
|
|
79
79
|
execsql/script/control.py,sha256=s-1eZdGARM6H1FwZ6VDdO_f50j7bvvRtTHesfUm9tbc,6144
|
|
80
|
-
execsql/script/engine.py,sha256=
|
|
80
|
+
execsql/script/engine.py,sha256=PqR8_5CUoHu1Wm8uLfudGN08h_vWD_3diYzlKhuqdgU,40633
|
|
81
81
|
execsql/script/variables.py,sha256=MOT9XEHucpuuuHQZM5bklxGMBQcwHzwTBxd0q3aO0XY,11641
|
|
82
82
|
execsql/utils/__init__.py,sha256=0uR6JwVJQRX3vceByNBduCAf5dd5assKjeqJUWvpZoA,278
|
|
83
83
|
execsql/utils/auth.py,sha256=onXzNkNZQZxGC5w7eey06sjvAIAX_Lf9g7nUJtcsel0,7009
|
|
84
84
|
execsql/utils/crypto.py,sha256=2OnBWwn9bCBGc1ZkyRv16TvhottoCNYtXqgbE3mG3Sg,2960
|
|
85
85
|
execsql/utils/datetime.py,sha256=V_itd5vVvUPjT86P_z_hh4mlerMDGhDzI5MwPMDBaI4,7715
|
|
86
|
-
execsql/utils/errors.py,sha256=
|
|
86
|
+
execsql/utils/errors.py,sha256=YKhYD27-3timuZavc2vIrRIfHa71vzih-KVPsAKgvkU,8163
|
|
87
87
|
execsql/utils/fileio.py,sha256=F6M4osE0Mb2ycTcvwwcYnhBXH1L36v6d7Oxdab6J16s,24110
|
|
88
88
|
execsql/utils/gui.py,sha256=kCfHvqY60jdoJa1k5HlxhrmzM4HPp7uajV6nxz3_Qh4,17583
|
|
89
89
|
execsql/utils/mail.py,sha256=75A1cMnEfyP0_QMMWuSLv8hrcIjc9cGBCrttLpr2TXQ,5372
|
|
@@ -91,24 +91,24 @@ execsql/utils/numeric.py,sha256=xh02ANSRk3nUpQ-rtm66ILoMqoi7HtzCoRMIOT9U8QI,1570
|
|
|
91
91
|
execsql/utils/regex.py,sha256=diEzTZqU_HHwVMadPAvN1Vgzhl7I03eVaEFGCXyGGL8,3770
|
|
92
92
|
execsql/utils/strings.py,sha256=5Dvzrk-9SIw2lpxXZQkiJbNyo1sy7iXXAtSULlZ0KG8,8488
|
|
93
93
|
execsql/utils/timer.py,sha256=eDYf5VzCNFk7oo90InJucUm3XcBdhYMogjZMqeg9xzc,1899
|
|
94
|
-
execsql2-2.
|
|
95
|
-
execsql2-2.
|
|
96
|
-
execsql2-2.
|
|
97
|
-
execsql2-2.
|
|
98
|
-
execsql2-2.
|
|
99
|
-
execsql2-2.
|
|
100
|
-
execsql2-2.
|
|
101
|
-
execsql2-2.
|
|
102
|
-
execsql2-2.
|
|
103
|
-
execsql2-2.
|
|
104
|
-
execsql2-2.
|
|
105
|
-
execsql2-2.
|
|
106
|
-
execsql2-2.
|
|
107
|
-
execsql2-2.
|
|
108
|
-
execsql2-2.
|
|
109
|
-
execsql2-2.
|
|
110
|
-
execsql2-2.
|
|
111
|
-
execsql2-2.
|
|
112
|
-
execsql2-2.
|
|
113
|
-
execsql2-2.
|
|
114
|
-
execsql2-2.
|
|
94
|
+
execsql2-2.11.0.data/data/execsql2_extras/README.md,sha256=sxwVyU0ZahCfANv56LahkyuM505kFjrMhe-1SvWE69E,4845
|
|
95
|
+
execsql2-2.11.0.data/data/execsql2_extras/config_settings.sqlite,sha256=aY5cxR7Q7J6zJ4bC9lu5mHUrhy211Cq3MNKPQVCt02E,20480
|
|
96
|
+
execsql2-2.11.0.data/data/execsql2_extras/example_config_prompt.sql,sha256=SY3Jxn1qcVm4kPW9xmmTfknHfvURXmeEYTbRjYrjGSw,7487
|
|
97
|
+
execsql2-2.11.0.data/data/execsql2_extras/execsql.conf,sha256=_45iJ-KWZnB8uMW_gEg067MM5pmGJ-dVl7VbAZMunAE,9530
|
|
98
|
+
execsql2-2.11.0.data/data/execsql2_extras/make_config_db.sql,sha256=WwyC6dK-Eh5CAVppiBCDHqiI1_wEI9U95Ytpr4lsZkg,8726
|
|
99
|
+
execsql2-2.11.0.data/data/execsql2_extras/md_compare.sql,sha256=B8Wd7LZ0vnMY2qvA139JIEBkPObgRH2i5xj6PejTQt8,24092
|
|
100
|
+
execsql2-2.11.0.data/data/execsql2_extras/md_glossary.sql,sha256=DJRHcU5NbFpxTTX-IwH3yRlsboj1q6BBGrUAHKn4Cuo,10796
|
|
101
|
+
execsql2-2.11.0.data/data/execsql2_extras/md_upsert.sql,sha256=v_7GbWh_N1mBTmw3gvTrkagOVp2q0KmXvM8hE-DlFxY,112524
|
|
102
|
+
execsql2-2.11.0.data/data/execsql2_extras/pg_compare.sql,sha256=9dWa8hnfy5dVJI-z2iGpd9JzQmI4j2ziMlEdpnr66ro,24352
|
|
103
|
+
execsql2-2.11.0.data/data/execsql2_extras/pg_glossary.sql,sha256=pKjIIDsROAgJq2H-1qNEcRMAWManivcZ_AEVHzUUlic,9908
|
|
104
|
+
execsql2-2.11.0.data/data/execsql2_extras/pg_upsert.sql,sha256=k7AFiGTLBy3nf-qO5QIaZrEYTAKvdxxU3JDLx9jqkzs,108315
|
|
105
|
+
execsql2-2.11.0.data/data/execsql2_extras/script_template.sql,sha256=1Estacb_vm1FgK41k_G9nuduP1yiA-fQ1Kn4Z4mv5Ao,11153
|
|
106
|
+
execsql2-2.11.0.data/data/execsql2_extras/ss_compare.sql,sha256=TsVxWm3cEpR5-EiMYXNhtaY0arSNeKZhsJdHdLA7xeI,24833
|
|
107
|
+
execsql2-2.11.0.data/data/execsql2_extras/ss_glossary.sql,sha256=cLM7nN8JOIu9ZVP9oY9qdSK3hrnWJiDcX6nZmQQbQWI,13065
|
|
108
|
+
execsql2-2.11.0.data/data/execsql2_extras/ss_upsert.sql,sha256=BCqmBykXBF-BpCgOFeG1qhf2XfScKsxPD17wd1hYfHw,120647
|
|
109
|
+
execsql2-2.11.0.dist-info/METADATA,sha256=Cmn0y2Xx2ZC-S3lsADP1gSyoCCfAsUGj8wlbyVJ6e8c,17062
|
|
110
|
+
execsql2-2.11.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
111
|
+
execsql2-2.11.0.dist-info/entry_points.txt,sha256=sUOxkM-dN1eBGGpSpDLsAaE0yNXYQKWZAfxPOlMkQyk,90
|
|
112
|
+
execsql2-2.11.0.dist-info/licenses/LICENSE.txt,sha256=LBdhuxejF8_bLCHZ2kWfmDXpDGUu914Gbd6_3JjCRe0,676
|
|
113
|
+
execsql2-2.11.0.dist-info/licenses/NOTICE,sha256=sqVrM73Ys9zfvWC_P797lHfTnoPW_ETeBSrUTFaob0A,339
|
|
114
|
+
execsql2-2.11.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{execsql2-2.10.1.data → execsql2-2.11.0.data}/data/execsql2_extras/example_config_prompt.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|