execsql2 2.6.0__py3-none-any.whl → 2.8.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 +95 -7
- execsql/exporters/__init__.py +3 -3
- execsql/exporters/delimited.py +2 -2
- execsql/exporters/markdown.py +126 -0
- execsql/exporters/xlsx.py +317 -0
- execsql/exporters/yaml.py +87 -0
- execsql/metacommands/__init__.py +25 -2
- execsql/metacommands/control.py +33 -0
- execsql/metacommands/dispatch.py +42 -0
- execsql/metacommands/io.py +2 -0
- execsql/metacommands/io_export.py +75 -0
- execsql/script/engine.py +16 -0
- execsql/state.py +10 -0
- {execsql2-2.6.0.dist-info → execsql2-2.8.0.dist-info}/METADATA +6 -2
- {execsql2-2.6.0.dist-info → execsql2-2.8.0.dist-info}/RECORD +35 -32
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/README.md +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/config_settings.sqlite +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/execsql.conf +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/make_config_db.sql +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/md_compare.sql +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/md_glossary.sql +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/md_upsert.sql +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/pg_compare.sql +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/pg_glossary.sql +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/pg_upsert.sql +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/script_template.sql +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/ss_compare.sql +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/ss_glossary.sql +0 -0
- {execsql2-2.6.0.data → execsql2-2.8.0.data}/data/execsql2_extras/ss_upsert.sql +0 -0
- {execsql2-2.6.0.dist-info → execsql2-2.8.0.dist-info}/WHEEL +0 -0
- {execsql2-2.6.0.dist-info → execsql2-2.8.0.dist-info}/entry_points.txt +0 -0
- {execsql2-2.6.0.dist-info → execsql2-2.8.0.dist-info}/licenses/LICENSE.txt +0 -0
- {execsql2-2.6.0.dist-info → execsql2-2.8.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
YAML export for execsql.
|
|
5
|
+
|
|
6
|
+
Provides :func:`write_query_to_yaml` which serialises a query result set as a
|
|
7
|
+
YAML sequence of mappings (one mapping per row).
|
|
8
|
+
|
|
9
|
+
Requires the ``PyYAML`` package (``pip install PyYAML`` or
|
|
10
|
+
``pip install 'execsql2[formats]'``).
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
import execsql.state as _state
|
|
16
|
+
from execsql.exceptions import ErrInfo
|
|
17
|
+
from execsql.exporters.zip import ZipWriter
|
|
18
|
+
from execsql.utils.errors import exception_desc
|
|
19
|
+
from execsql.utils.fileio import filewriter_close
|
|
20
|
+
|
|
21
|
+
__all__ = ["write_query_to_yaml"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def write_query_to_yaml(
|
|
25
|
+
select_stmt: str,
|
|
26
|
+
db: Any,
|
|
27
|
+
outfile: str,
|
|
28
|
+
append: bool = False,
|
|
29
|
+
desc: str | None = None,
|
|
30
|
+
zipfile: str | None = None,
|
|
31
|
+
) -> None:
|
|
32
|
+
"""Execute *select_stmt* and write the result set to *outfile* as YAML.
|
|
33
|
+
|
|
34
|
+
The output is a YAML sequence of mappings — one mapping per row with
|
|
35
|
+
column headers as keys. Python types are preserved: integers stay
|
|
36
|
+
integers, floats stay floats, ``None`` becomes ``null``.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
select_stmt: SQL SELECT statement to execute.
|
|
40
|
+
db: Database connection object exposing ``select_rowsource()``.
|
|
41
|
+
outfile: Destination file path, or ``"stdout"``.
|
|
42
|
+
append: When ``True`` the YAML sequence is appended to an existing
|
|
43
|
+
file. Note that concatenating two bare YAML sequences in one
|
|
44
|
+
file produces a multi-document stream; callers are responsible
|
|
45
|
+
for ensuring the resulting file is valid for their use-case.
|
|
46
|
+
desc: Optional description string. Ignored in plain YAML output
|
|
47
|
+
(YAML does not have a standard metadata header), but accepted
|
|
48
|
+
for API consistency with other exporters.
|
|
49
|
+
zipfile: When provided, write *outfile* as a member of this zip
|
|
50
|
+
archive instead of writing to the filesystem directly.
|
|
51
|
+
"""
|
|
52
|
+
try:
|
|
53
|
+
import yaml # type: ignore[import-untyped]
|
|
54
|
+
except ImportError as exc:
|
|
55
|
+
raise ErrInfo(
|
|
56
|
+
"error",
|
|
57
|
+
other_msg=("PyYAML is required for FORMAT YAML export. Install it with: pip install PyYAML"),
|
|
58
|
+
) from exc
|
|
59
|
+
|
|
60
|
+
conf = _state.conf
|
|
61
|
+
try:
|
|
62
|
+
hdrs, rows = db.select_rowsource(select_stmt)
|
|
63
|
+
except ErrInfo:
|
|
64
|
+
raise
|
|
65
|
+
except Exception as e:
|
|
66
|
+
raise ErrInfo("db", select_stmt, exception_msg=exception_desc()) from e
|
|
67
|
+
|
|
68
|
+
# Build the list of dicts in memory. YAML output is human-readable and
|
|
69
|
+
# typically used for small-to-medium result sets; loading into memory is
|
|
70
|
+
# acceptable and required by yaml.dump().
|
|
71
|
+
uhdrs = [str(h) for h in hdrs]
|
|
72
|
+
data = [dict(zip(uhdrs, row)) for row in rows]
|
|
73
|
+
yaml_text = yaml.dump(data, default_flow_style=False, allow_unicode=True)
|
|
74
|
+
|
|
75
|
+
if zipfile is None:
|
|
76
|
+
filewriter_close(outfile)
|
|
77
|
+
from execsql.utils.fileio import EncodedFile
|
|
78
|
+
|
|
79
|
+
ef = EncodedFile(outfile, conf.output_encoding)
|
|
80
|
+
f = ef.open("at" if append else "wt")
|
|
81
|
+
else:
|
|
82
|
+
f = ZipWriter(zipfile, outfile, append)
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
f.write(yaml_text)
|
|
86
|
+
finally:
|
|
87
|
+
f.close()
|
execsql/metacommands/__init__.py
CHANGED
|
@@ -36,6 +36,7 @@ from execsql.metacommands.connect import (
|
|
|
36
36
|
x_daoflushdelay,
|
|
37
37
|
)
|
|
38
38
|
from execsql.metacommands.control import (
|
|
39
|
+
x_assert,
|
|
39
40
|
x_if,
|
|
40
41
|
x_if_orif,
|
|
41
42
|
x_if_andif,
|
|
@@ -105,6 +106,7 @@ from execsql.metacommands.io import (
|
|
|
105
106
|
x_export_query_with_template,
|
|
106
107
|
x_export_with_template,
|
|
107
108
|
x_export_ods_multiple,
|
|
109
|
+
x_export_xlsx_multiple,
|
|
108
110
|
x_export_metadata,
|
|
109
111
|
x_export_metadata_table,
|
|
110
112
|
x_import,
|
|
@@ -237,6 +239,7 @@ __all__ = [
|
|
|
237
239
|
"x_pg_vacuum",
|
|
238
240
|
"x_daoflushdelay",
|
|
239
241
|
# control handlers
|
|
242
|
+
"x_assert",
|
|
240
243
|
"x_if",
|
|
241
244
|
"x_if_orif",
|
|
242
245
|
"x_if_andif",
|
|
@@ -303,6 +306,7 @@ __all__ = [
|
|
|
303
306
|
"x_export_query_with_template",
|
|
304
307
|
"x_export_with_template",
|
|
305
308
|
"x_export_ods_multiple",
|
|
309
|
+
"x_export_xlsx_multiple",
|
|
306
310
|
"x_export_metadata",
|
|
307
311
|
"x_export_metadata_table",
|
|
308
312
|
"x_import",
|
|
@@ -427,12 +431,31 @@ TEXT_FORMATS = ["TXT", "TXT-AND", "PLAIN"]
|
|
|
427
431
|
JSON_VARIANT_FORMATS = ["JSON_TS", "JSON_TABLESCHEMA"]
|
|
428
432
|
|
|
429
433
|
QUERY_EXPORT_FORMATS = (
|
|
430
|
-
DELIMITED_FORMATS
|
|
434
|
+
DELIMITED_FORMATS
|
|
435
|
+
+ TEXT_FORMATS
|
|
436
|
+
+ ["ODS", "XLSX", "JSON", "HTML", "CGI-HTML", "VALUES", "LATEX", "RAW", "B64", "FEATHER", "YAML", "MARKDOWN", "MD"]
|
|
431
437
|
)
|
|
432
438
|
TABLE_EXPORT_FORMATS = (
|
|
433
439
|
DELIMITED_FORMATS
|
|
434
440
|
+ TEXT_FORMATS
|
|
435
|
-
+ [
|
|
441
|
+
+ [
|
|
442
|
+
"JSON",
|
|
443
|
+
"XML",
|
|
444
|
+
"VALUES",
|
|
445
|
+
"HTML",
|
|
446
|
+
"CGI-HTML",
|
|
447
|
+
"SQLITE",
|
|
448
|
+
"DUCKDB",
|
|
449
|
+
"LATEX",
|
|
450
|
+
"RAW",
|
|
451
|
+
"B64",
|
|
452
|
+
"FEATHER",
|
|
453
|
+
"HDF5",
|
|
454
|
+
"XLSX",
|
|
455
|
+
"YAML",
|
|
456
|
+
"MARKDOWN",
|
|
457
|
+
"MD",
|
|
458
|
+
]
|
|
436
459
|
)
|
|
437
460
|
SERVE_FORMATS = ["BINARY", "CSV", "TXT", "TEXT", "ODS", "JSON", "HTML", "PDF", "ZIP"]
|
|
438
461
|
METADATA_FORMATS = ["CSV", "TAB", "TSV", "TABQ", "TSVQ", "TXT", "TEXT"]
|
execsql/metacommands/control.py
CHANGED
|
@@ -34,6 +34,39 @@ from execsql.utils.fileio import EncodedFile, check_dir
|
|
|
34
34
|
from execsql.utils.gui import GUI_HALT, GuiSpec, enable_gui, gui_console_isrunning
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def x_assert(**kwargs: Any) -> None:
|
|
38
|
+
"""Evaluate a condition and raise ErrInfo if it is false.
|
|
39
|
+
|
|
40
|
+
Syntax::
|
|
41
|
+
|
|
42
|
+
-- !x! ASSERT <condition> ["message"]
|
|
43
|
+
-- !x! ASSERT <condition> ['message']
|
|
44
|
+
-- !x! ASSERT <condition>
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
**kwargs: Keyword arguments injected by the dispatch table.
|
|
48
|
+
``condtest`` — the condition expression string.
|
|
49
|
+
``message`` — optional user-supplied failure message; may be None.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
ErrInfo: When the condition evaluates to False (or raises internally
|
|
53
|
+
for an unrecognized condition).
|
|
54
|
+
"""
|
|
55
|
+
condition: str = kwargs["condtest"].strip()
|
|
56
|
+
raw_message: str | None = kwargs.get("message")
|
|
57
|
+
if raw_message:
|
|
58
|
+
# Strip surrounding quotes that the regex captured
|
|
59
|
+
message: str = raw_message.strip("'\"")
|
|
60
|
+
else:
|
|
61
|
+
message = f"Assertion failed: {condition}"
|
|
62
|
+
|
|
63
|
+
result = _state.xcmd_test(condition)
|
|
64
|
+
if result:
|
|
65
|
+
_state.exec_log.log_user_msg(f"ASSERT passed: {condition}")
|
|
66
|
+
else:
|
|
67
|
+
raise ErrInfo(type="cmd", other_msg=message)
|
|
68
|
+
|
|
69
|
+
|
|
37
70
|
def x_if(**kwargs: Any) -> None:
|
|
38
71
|
tf_value = _state.xcmd_test(kwargs["condtest"])
|
|
39
72
|
if tf_value:
|
execsql/metacommands/dispatch.py
CHANGED
|
@@ -36,6 +36,7 @@ from execsql.metacommands.connect import (
|
|
|
36
36
|
x_use,
|
|
37
37
|
)
|
|
38
38
|
from execsql.metacommands.control import (
|
|
39
|
+
x_assert,
|
|
39
40
|
x_begin_batch,
|
|
40
41
|
x_break,
|
|
41
42
|
x_end_batch,
|
|
@@ -107,6 +108,7 @@ from execsql.metacommands.io import (
|
|
|
107
108
|
x_export_metadata,
|
|
108
109
|
x_export_metadata_table,
|
|
109
110
|
x_export_ods_multiple,
|
|
111
|
+
x_export_xlsx_multiple,
|
|
110
112
|
x_export_query,
|
|
111
113
|
x_export_query_with_template,
|
|
112
114
|
x_export_row_buffer,
|
|
@@ -395,6 +397,16 @@ def build_dispatch_table() -> MetaCommandList:
|
|
|
395
397
|
),
|
|
396
398
|
x_export_ods_multiple,
|
|
397
399
|
)
|
|
400
|
+
mcl.add(
|
|
401
|
+
ins_table_list_rxs(
|
|
402
|
+
r"^\s*EXPORT\s+",
|
|
403
|
+
ins_fn_rxs(
|
|
404
|
+
r"\s+(?P<tee>TEE\s+)?(?P<append>APPEND\s+)?TO\s+",
|
|
405
|
+
r'\s+AS\s+XLSX(?:\s+DESCRIP(?:TION)?\s+"(?P<description>[^"]*)")?\s*$',
|
|
406
|
+
),
|
|
407
|
+
),
|
|
408
|
+
x_export_xlsx_multiple,
|
|
409
|
+
)
|
|
398
410
|
|
|
399
411
|
# ------------------------------------------------------------------
|
|
400
412
|
# IMPORT_FILE
|
|
@@ -1648,6 +1660,36 @@ def build_dispatch_table() -> MetaCommandList:
|
|
|
1648
1660
|
category="action",
|
|
1649
1661
|
)
|
|
1650
1662
|
|
|
1663
|
+
# ------------------------------------------------------------------
|
|
1664
|
+
# ASSERT
|
|
1665
|
+
# ------------------------------------------------------------------
|
|
1666
|
+
# Two registrations; MetaCommandList.add() prepends, so register the
|
|
1667
|
+
# broader (no-message) pattern first and the more specific (with-message)
|
|
1668
|
+
# pattern second — the second registration wins because it is prepended
|
|
1669
|
+
# last and therefore tried first during dispatch.
|
|
1670
|
+
#
|
|
1671
|
+
# with-message: the trailing quoted token is captured as `message`;
|
|
1672
|
+
# everything between ASSERT and the message becomes `condtest`.
|
|
1673
|
+
# This handles conditions that themselves contain quoted strings, e.g.:
|
|
1674
|
+
# ASSERT $VAR = 'expected' 'wrong value'
|
|
1675
|
+
# The non-greedy (.+?) stops before the LAST quoted token on the line.
|
|
1676
|
+
#
|
|
1677
|
+
# no-message: full remainder after ASSERT goes into `condtest`.
|
|
1678
|
+
mcl.add(
|
|
1679
|
+
r"^\s*ASSERT\s+(?P<condtest>.+?)\s*$",
|
|
1680
|
+
x_assert,
|
|
1681
|
+
description="ASSERT",
|
|
1682
|
+
category="action",
|
|
1683
|
+
run_when_false=False,
|
|
1684
|
+
)
|
|
1685
|
+
mcl.add(
|
|
1686
|
+
r"^\s*ASSERT\s+(?P<condtest>.+?)\s+(?P<message>(?:\"[^\"]*\"|'[^']*'))\s*$",
|
|
1687
|
+
x_assert,
|
|
1688
|
+
description="ASSERT",
|
|
1689
|
+
category="action",
|
|
1690
|
+
run_when_false=False,
|
|
1691
|
+
)
|
|
1692
|
+
|
|
1651
1693
|
# ------------------------------------------------------------------
|
|
1652
1694
|
# IF / ORIF / ANDIF / ELSEIF / ELSE / ENDIF
|
|
1653
1695
|
# ------------------------------------------------------------------
|
execsql/metacommands/io.py
CHANGED
|
@@ -22,6 +22,7 @@ from execsql.metacommands.io_export import ( # noqa: F401
|
|
|
22
22
|
x_export_metadata,
|
|
23
23
|
x_export_metadata_table,
|
|
24
24
|
x_export_ods_multiple,
|
|
25
|
+
x_export_xlsx_multiple,
|
|
25
26
|
x_export_query,
|
|
26
27
|
x_export_query_with_template,
|
|
27
28
|
x_export_row_buffer,
|
|
@@ -78,6 +79,7 @@ __all__ = [
|
|
|
78
79
|
"x_export_metadata",
|
|
79
80
|
"x_export_metadata_table",
|
|
80
81
|
"x_export_ods_multiple",
|
|
82
|
+
"x_export_xlsx_multiple",
|
|
81
83
|
"x_export_query",
|
|
82
84
|
"x_export_query_with_template",
|
|
83
85
|
"x_export_row_buffer",
|
|
@@ -19,6 +19,7 @@ from execsql.exporters.html import write_query_to_cgi_html, write_query_to_html
|
|
|
19
19
|
from execsql.exporters.json import write_query_to_json, write_query_to_json_ts
|
|
20
20
|
from execsql.exporters.latex import write_query_to_latex
|
|
21
21
|
from execsql.exporters.ods import write_queries_to_ods, write_query_to_ods
|
|
22
|
+
from execsql.exporters.xlsx import write_queries_to_xlsx, write_query_to_xlsx
|
|
22
23
|
from execsql.exporters.parquet import write_query_to_parquet
|
|
23
24
|
from execsql.exporters.pretty import prettyprint_query, prettyprint_rowset
|
|
24
25
|
from execsql.exporters.raw import write_query_b64, write_query_raw
|
|
@@ -26,6 +27,8 @@ from execsql.exporters.sqlite import write_query_to_sqlite
|
|
|
26
27
|
from execsql.exporters.templates import report_query
|
|
27
28
|
from execsql.exporters.values import write_query_to_values
|
|
28
29
|
from execsql.exporters.xml import write_query_to_xml
|
|
30
|
+
from execsql.exporters.markdown import write_query_to_markdown
|
|
31
|
+
from execsql.exporters.yaml import write_query_to_yaml
|
|
29
32
|
from execsql.importers.base import import_data_table
|
|
30
33
|
from execsql.script import current_script_line
|
|
31
34
|
from execsql.utils.errors import exception_desc
|
|
@@ -85,6 +88,8 @@ def x_export(**kwargs: Any) -> None:
|
|
|
85
88
|
raise ErrInfo("error", other_msg="Cannot export to the HDF5 format within a zipfile.")
|
|
86
89
|
if filefmt == "ods":
|
|
87
90
|
raise ErrInfo("error", other_msg="Cannot export to an ODS workbook within a zipfile.")
|
|
91
|
+
if filefmt == "xlsx":
|
|
92
|
+
raise ErrInfo("error", other_msg="Cannot export to an XLSX workbook within a zipfile.")
|
|
88
93
|
notype = bool(kwargs.get("notype"))
|
|
89
94
|
if zipfilename is not None:
|
|
90
95
|
check_dir(zipfilename)
|
|
@@ -120,6 +125,15 @@ def x_export(**kwargs: Any) -> None:
|
|
|
120
125
|
sheetname=queryname,
|
|
121
126
|
desc=description,
|
|
122
127
|
)
|
|
128
|
+
elif filefmt == "xlsx":
|
|
129
|
+
write_query_to_xlsx(
|
|
130
|
+
select_stmt,
|
|
131
|
+
_state.dbs.current(),
|
|
132
|
+
outfile,
|
|
133
|
+
append,
|
|
134
|
+
sheetname=queryname,
|
|
135
|
+
desc=description,
|
|
136
|
+
)
|
|
123
137
|
elif filefmt == "duckdb":
|
|
124
138
|
write_query_to_duckdb(select_stmt, _state.dbs.current(), outfile, append, tablename=queryname)
|
|
125
139
|
elif filefmt == "sqlite":
|
|
@@ -191,6 +205,24 @@ def x_export(**kwargs: Any) -> None:
|
|
|
191
205
|
)
|
|
192
206
|
elif filefmt == "hdf5":
|
|
193
207
|
write_query_to_hdf5(table, select_stmt, _state.dbs.current(), outfile, append, desc=description)
|
|
208
|
+
elif filefmt == "yaml":
|
|
209
|
+
write_query_to_yaml(
|
|
210
|
+
select_stmt,
|
|
211
|
+
_state.dbs.current(),
|
|
212
|
+
outfile,
|
|
213
|
+
append,
|
|
214
|
+
desc=description,
|
|
215
|
+
zipfile=zipfilename,
|
|
216
|
+
)
|
|
217
|
+
elif filefmt in ("markdown", "md"):
|
|
218
|
+
write_query_to_markdown(
|
|
219
|
+
select_stmt,
|
|
220
|
+
_state.dbs.current(),
|
|
221
|
+
outfile,
|
|
222
|
+
append,
|
|
223
|
+
desc=description,
|
|
224
|
+
zipfile=zipfilename,
|
|
225
|
+
)
|
|
194
226
|
else:
|
|
195
227
|
try:
|
|
196
228
|
hdrs, rows = _state.dbs.current().select_rowsource(select_stmt)
|
|
@@ -237,6 +269,8 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
237
269
|
raise ErrInfo("error", other_msg="Cannot export to the HDF5 format within a zipfile.")
|
|
238
270
|
if filefmt == "ods":
|
|
239
271
|
raise ErrInfo("error", other_msg="Cannot export to an ODS workbook within a zipfile.")
|
|
272
|
+
if filefmt == "xlsx":
|
|
273
|
+
raise ErrInfo("error", other_msg="Cannot export to an XLSX workbook within a zipfile.")
|
|
240
274
|
notype = bool(kwargs.get("notype"))
|
|
241
275
|
check_dir(outfile)
|
|
242
276
|
if tee and outfile.lower() != "stdout":
|
|
@@ -270,6 +304,16 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
270
304
|
sheetname=f"Query_{lno}",
|
|
271
305
|
desc=description,
|
|
272
306
|
)
|
|
307
|
+
elif filefmt == "xlsx":
|
|
308
|
+
script_name, lno = current_script_line()
|
|
309
|
+
write_query_to_xlsx(
|
|
310
|
+
select_stmt,
|
|
311
|
+
_state.dbs.current(),
|
|
312
|
+
outfile,
|
|
313
|
+
append,
|
|
314
|
+
sheetname=f"Query_{lno}",
|
|
315
|
+
desc=description,
|
|
316
|
+
)
|
|
273
317
|
elif filefmt == "json":
|
|
274
318
|
write_query_to_json(
|
|
275
319
|
select_stmt,
|
|
@@ -325,6 +369,24 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
325
369
|
desc=description,
|
|
326
370
|
zipfile=zipfilename,
|
|
327
371
|
)
|
|
372
|
+
elif filefmt == "yaml":
|
|
373
|
+
write_query_to_yaml(
|
|
374
|
+
select_stmt,
|
|
375
|
+
_state.dbs.current(),
|
|
376
|
+
outfile,
|
|
377
|
+
append,
|
|
378
|
+
desc=description,
|
|
379
|
+
zipfile=zipfilename,
|
|
380
|
+
)
|
|
381
|
+
elif filefmt in ("markdown", "md"):
|
|
382
|
+
write_query_to_markdown(
|
|
383
|
+
select_stmt,
|
|
384
|
+
_state.dbs.current(),
|
|
385
|
+
outfile,
|
|
386
|
+
append,
|
|
387
|
+
desc=description,
|
|
388
|
+
zipfile=zipfilename,
|
|
389
|
+
)
|
|
328
390
|
else:
|
|
329
391
|
try:
|
|
330
392
|
hdrs, rows = _state.dbs.current().select_rowsource(select_stmt)
|
|
@@ -403,6 +465,19 @@ def x_export_ods_multiple(**kwargs: Any) -> None:
|
|
|
403
465
|
write_queries_to_ods(table_list, _state.dbs.current(), outfile, append, tee, desc=description)
|
|
404
466
|
|
|
405
467
|
|
|
468
|
+
def x_export_xlsx_multiple(**kwargs: Any) -> None:
|
|
469
|
+
"""Export multiple tables to separate worksheets in a single XLSX workbook."""
|
|
470
|
+
table_list = kwargs["tables"]
|
|
471
|
+
outfile = kwargs["filename"]
|
|
472
|
+
description = kwargs["description"]
|
|
473
|
+
tee = kwargs["tee"]
|
|
474
|
+
tee = bool(tee)
|
|
475
|
+
append = kwargs["append"]
|
|
476
|
+
append = append is not None
|
|
477
|
+
check_dir(outfile)
|
|
478
|
+
write_queries_to_xlsx(table_list, _state.dbs.current(), outfile, append, tee, desc=description)
|
|
479
|
+
|
|
480
|
+
|
|
406
481
|
def x_export_metadata(**kwargs: Any) -> None:
|
|
407
482
|
outfile = kwargs["filename"]
|
|
408
483
|
append = kwargs["append"] is not None
|
execsql/script/engine.py
CHANGED
|
@@ -489,7 +489,23 @@ class CommandList:
|
|
|
489
489
|
_state.subvars.add_substitution("$CURRENT_SCRIPT_NAME", Path(cmditem.source).name)
|
|
490
490
|
_state.subvars.add_substitution("$CURRENT_SCRIPT_LINE", str(cmditem.line_no))
|
|
491
491
|
_state.subvars.add_substitution("$SCRIPT_LINE", str(cmditem.line_no))
|
|
492
|
+
_profiling = _state.profile_data is not None
|
|
493
|
+
if _profiling:
|
|
494
|
+
import time as _time
|
|
495
|
+
|
|
496
|
+
_t0 = _time.perf_counter()
|
|
492
497
|
cmditem.command.run(self.localvars.merge(self.paramvals), not _state.status.batch.in_batch())
|
|
498
|
+
if _profiling:
|
|
499
|
+
_elapsed = _time.perf_counter() - _t0
|
|
500
|
+
_state.profile_data.append(
|
|
501
|
+
(
|
|
502
|
+
cmditem.source,
|
|
503
|
+
cmditem.line_no,
|
|
504
|
+
cmditem.command_type,
|
|
505
|
+
_elapsed,
|
|
506
|
+
cmditem.command.commandline()[:100],
|
|
507
|
+
),
|
|
508
|
+
)
|
|
493
509
|
self.cmdptr += 1
|
|
494
510
|
|
|
495
511
|
def run_next(self) -> None:
|
execsql/state.py
CHANGED
|
@@ -94,6 +94,8 @@ __all__ = [
|
|
|
94
94
|
"gui_console",
|
|
95
95
|
"gui_manager_queue",
|
|
96
96
|
"gui_manager_thread",
|
|
97
|
+
# Profiling
|
|
98
|
+
"profile_data",
|
|
97
99
|
# Version
|
|
98
100
|
"primary_vno",
|
|
99
101
|
"secondary_vno",
|
|
@@ -191,6 +193,8 @@ _CONTEXT_ATTRS: frozenset[str] = frozenset(
|
|
|
191
193
|
"gui_console",
|
|
192
194
|
"gui_manager_queue",
|
|
193
195
|
"gui_manager_thread",
|
|
196
|
+
# Profiling
|
|
197
|
+
"profile_data",
|
|
194
198
|
},
|
|
195
199
|
)
|
|
196
200
|
|
|
@@ -242,6 +246,8 @@ class RuntimeContext:
|
|
|
242
246
|
"gui_console",
|
|
243
247
|
"gui_manager_queue",
|
|
244
248
|
"gui_manager_thread",
|
|
249
|
+
# Profiling
|
|
250
|
+
"profile_data",
|
|
245
251
|
)
|
|
246
252
|
|
|
247
253
|
def __init__(self) -> None:
|
|
@@ -289,6 +295,10 @@ class RuntimeContext:
|
|
|
289
295
|
self.gui_manager_queue: _mp.Queue | None = None
|
|
290
296
|
self.gui_manager_thread: _threading.Thread | None = None
|
|
291
297
|
|
|
298
|
+
# Profiling — None means profiling is disabled; a list means it is enabled.
|
|
299
|
+
# Each entry: (source, line_no, command_type, elapsed_secs, command_text_preview)
|
|
300
|
+
self.profile_data: list[tuple] | None = None
|
|
301
|
+
|
|
292
302
|
|
|
293
303
|
# ---------------------------------------------------------------------------
|
|
294
304
|
# Module proxy — transparently delegates context attr access to _ctx
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.8.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
|
|
@@ -54,6 +54,7 @@ Requires-Dist: polars; extra == 'all'
|
|
|
54
54
|
Requires-Dist: psycopg2-binary; extra == 'all'
|
|
55
55
|
Requires-Dist: pymysql; extra == 'all'
|
|
56
56
|
Requires-Dist: pyodbc; extra == 'all'
|
|
57
|
+
Requires-Dist: pyyaml; extra == 'all'
|
|
57
58
|
Requires-Dist: tables; extra == 'all'
|
|
58
59
|
Requires-Dist: xlrd; extra == 'all'
|
|
59
60
|
Provides-Extra: all-db
|
|
@@ -76,6 +77,7 @@ Requires-Dist: openpyxl; extra == 'dev'
|
|
|
76
77
|
Requires-Dist: polars; extra == 'dev'
|
|
77
78
|
Requires-Dist: pre-commit>=3.5.0; extra == 'dev'
|
|
78
79
|
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
80
|
+
Requires-Dist: pyyaml; extra == 'dev'
|
|
79
81
|
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
80
82
|
Requires-Dist: tables; extra == 'dev'
|
|
81
83
|
Requires-Dist: tox-uv>=1.13.1; extra == 'dev'
|
|
@@ -91,6 +93,7 @@ Requires-Dist: jinja2; extra == 'formats'
|
|
|
91
93
|
Requires-Dist: odfpy; extra == 'formats'
|
|
92
94
|
Requires-Dist: openpyxl; extra == 'formats'
|
|
93
95
|
Requires-Dist: polars; extra == 'formats'
|
|
96
|
+
Requires-Dist: pyyaml; extra == 'formats'
|
|
94
97
|
Requires-Dist: tables; extra == 'formats'
|
|
95
98
|
Requires-Dist: xlrd; extra == 'formats'
|
|
96
99
|
Provides-Extra: mssql
|
|
@@ -227,9 +230,10 @@ Run `execsql --help` for the full option list, or `execsql -m` to list all metac
|
|
|
227
230
|
# Features
|
|
228
231
|
|
|
229
232
|
- Import data from CSV, TSV, Excel, OpenDocument, Feather, or Parquet files into a database table.
|
|
230
|
-
- Export query results in
|
|
233
|
+
- Export query results in 20+ formats including CSV, TSV, JSON, YAML, XML, HTML, Markdown, LaTeX, XLSX, OpenDocument, Feather, Parquet, HDF5, DuckDB, SQLite, plain text, and Jinja2 templates.
|
|
231
234
|
- Copy data between databases, including across different DBMS types.
|
|
232
235
|
- Conditionally execute SQL and metacommands using `IF`/`ELSE`/`ENDIF` based on data values, DBMS type, or user input.
|
|
236
|
+
- Validate data with `ASSERT` — halt the script with a clear error message if a condition is false (ideal for CI pipelines).
|
|
233
237
|
- Loop over blocks of SQL and metacommands using `LOOP`/`ENDLOOP`.
|
|
234
238
|
- Use substitution variables (`SUB`, `$ARG_x`, built-in variables like `$date_tag`) to parameterize scripts.
|
|
235
239
|
- Include or chain scripts with `INCLUDE` and `SCRIPT`.
|
|
@@ -7,12 +7,12 @@ execsql/format.py,sha256=-6iknDddqbkapMo4NKmT5LAynDLqMW5kHgDWRg0KSws,11990
|
|
|
7
7
|
execsql/models.py,sha256=DxkGp9iWbuZDWPGmnxZp9mvEeyOwxEJNx94fxQQiLfQ,13538
|
|
8
8
|
execsql/parser.py,sha256=mbNSMiAMR1NvNvFtQAZq6nxBOupMGJZXSimLWLtZeNs,15537
|
|
9
9
|
execsql/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
execsql/state.py,sha256=
|
|
10
|
+
execsql/state.py,sha256=BodGWiLD7I3s7LFd8Mb6SHMp3I1BhVE4rYcR0UZWAoM,14799
|
|
11
11
|
execsql/types.py,sha256=HVWb4umIB9lpxCGgqk3xy1hoGYPfN39xci5mHF0Izq4,31882
|
|
12
|
-
execsql/cli/__init__.py,sha256=
|
|
12
|
+
execsql/cli/__init__.py,sha256=KewdhCBL8iRa_iPZZ7RKeRl90pGCXg3_lsMaVZph-kY,15118
|
|
13
13
|
execsql/cli/dsn.py,sha256=svaZtrUXFRL2W5G6FRRiKtR6kehOp7urrVhIx_642Z8,2820
|
|
14
14
|
execsql/cli/help.py,sha256=Sn_TgSJiQeBx-xZH0fuP5OvR_wasSTumjWF9UHfIX5k,5414
|
|
15
|
-
execsql/cli/run.py,sha256=
|
|
15
|
+
execsql/cli/run.py,sha256=pkUIcWtzDSYfoIlM418cZdLix7NI45HKRIBxgZfFtHg,26405
|
|
16
16
|
execsql/db/__init__.py,sha256=jTbuafuKOqYtXFR1wvCOoKK5Lr3l1uErfaIbIr6UywI,1063
|
|
17
17
|
execsql/db/access.py,sha256=L79gUnAnnM9EJ_f4k42jr7DI0qGcKtLOnJTlBC7uPm0,17879
|
|
18
18
|
execsql/db/base.py,sha256=hfMFj8fXY0T1aXLvWJHqb0aU4EQUDFOc-YrS29HH8U4,30405
|
|
@@ -25,14 +25,15 @@ execsql/db/oracle.py,sha256=AFVHhGlCzBuU7JgrAqeUG6e8TUUkk1Y80XVJQnGOqLM,10547
|
|
|
25
25
|
execsql/db/postgres.py,sha256=oXR7ODzQhR3yO6q-aNa9_il_rO3SpOX9yYGsfIqHwLI,20139
|
|
26
26
|
execsql/db/sqlite.py,sha256=2fD3AfckIGWN1oHcOaqQlQnbig26top1IlW-ejPHttI,10204
|
|
27
27
|
execsql/db/sqlserver.py,sha256=mNwmIIxTzqXU-cOjpNpeFi568HjQHsAk8Xnn-tR6F_E,7563
|
|
28
|
-
execsql/exporters/__init__.py,sha256
|
|
28
|
+
execsql/exporters/__init__.py,sha256=-Cnji-OgodJV8ftcDcOyTof0kQMy9J5kKVC8GVFpc3o,670
|
|
29
29
|
execsql/exporters/base.py,sha256=W9USFyk_2eztjJ51X6CJh7-chE1i3cSx-STOtbHXCNI,6373
|
|
30
|
-
execsql/exporters/delimited.py,sha256=
|
|
30
|
+
execsql/exporters/delimited.py,sha256=zMvurTRVl5W-6N8DuYtn_xILUkYLMlfflwWMfvdeaF0,30304
|
|
31
31
|
execsql/exporters/duckdb.py,sha256=Wc9I5uiV4MzmVQzCX-vgVHQUL7U3ZWdOkFVFWBv5SXM,2911
|
|
32
32
|
execsql/exporters/feather.py,sha256=w2qZAnewzeiRMnmPXECvkgD-6KtyxaiQwjokRT7Awrc,4167
|
|
33
33
|
execsql/exporters/html.py,sha256=ISQBOr7AJ5koKlebXSvWqzEvl1nXriCRGeKmk-bzkrc,9335
|
|
34
34
|
execsql/exporters/json.py,sha256=yljlRBbmvDVSTQUe0EdfdqTTRpD5sHfn7-jQ457ydvc,4139
|
|
35
35
|
execsql/exporters/latex.py,sha256=w_B83_5vKPe8uYxCWGdqvxwJeq0mw5zzKYDiAb7dbN0,4503
|
|
36
|
+
execsql/exporters/markdown.py,sha256=_ZX3dikbtAb6qZxYeWxDZAPF0-cNKTPR7or5kTbD2ZU,4436
|
|
36
37
|
execsql/exporters/ods.py,sha256=jl2qVHUeCLLv8xrkZfG3jgXbaglQ3rggCHziv7tNQOI,18876
|
|
37
38
|
execsql/exporters/parquet.py,sha256=186vUTH1oVAQ0s_qayLzEQVsKKu3ijAkhYEI6tysXkg,1095
|
|
38
39
|
execsql/exporters/pretty.py,sha256=9isA8f6xUz-3-JhMJimibnvtybVrT1cnoAjGnzsPEGI,3423
|
|
@@ -42,7 +43,9 @@ execsql/exporters/sqlite.py,sha256=XA0ALLvy-r6Pz1lpOFkWWbvpSP9Hm1tHHiuo_BvPVDk,2
|
|
|
42
43
|
execsql/exporters/templates.py,sha256=T9nk7vJrlxiPGfOWGc79xqqDxK3TCYu0wXq48U02npw,5564
|
|
43
44
|
execsql/exporters/values.py,sha256=HIyud31aux_dbCphfKHEGeZB9fkIPE5PoGXQz817XIE,2520
|
|
44
45
|
execsql/exporters/xls.py,sha256=nPROgxL8XK2oiBVoqN2L-o0j_jynRIMokwB8NpvOBt0,10623
|
|
46
|
+
execsql/exporters/xlsx.py,sha256=xXTFIKkvJnNOsFdnhSYEkJa4ulTrtq9tIRk6SSchqA0,11299
|
|
45
47
|
execsql/exporters/xml.py,sha256=lqcOM8uKDoCayU42BPSLNH1_2DIHU5D3LtQItREU90c,2564
|
|
48
|
+
execsql/exporters/yaml.py,sha256=0bwLDU3Fy00yMryBOSBSptbjV8Re6Ks-b62DObFNP4o,3062
|
|
46
49
|
execsql/exporters/zip.py,sha256=9-hExltQorONNThiMfxPDYHqHsbTeq9zM9zmtG4oFb8,4410
|
|
47
50
|
execsql/gui/__init__.py,sha256=oCb-cyhLZzVpWJ4WU5HbqEDBrV-lm0ytEwxemrOZyqs,2048
|
|
48
51
|
execsql/gui/base.py,sha256=sfNRkDrf7FhIgMRUOdyZpRLS1Xk9RqNhrV0A1RP6PXU,6068
|
|
@@ -55,15 +58,15 @@ execsql/importers/csv.py,sha256=Mu848WNzuhVO1ade-WurPyxqGOuVNRO8UwRF3-bav_I,4845
|
|
|
55
58
|
execsql/importers/feather.py,sha256=g2B69d2uv9vmnXcmjFyTVsMP40LYEzFYkhk3gD26mGw,1900
|
|
56
59
|
execsql/importers/ods.py,sha256=MJsdsjropzCvxAA3DDZfAL_AnmZ4yij7DnrjGyDJqHQ,2843
|
|
57
60
|
execsql/importers/xls.py,sha256=e0Zfe47ZiCpA1Ae3XDJ1ko3sCiH3-8U6XLKi6NvD0jQ,3683
|
|
58
|
-
execsql/metacommands/__init__.py,sha256=
|
|
61
|
+
execsql/metacommands/__init__.py,sha256=ejuY2GFHxNh5f_Yp_GOV0EBe2vuUcly0-zBrKiR3qes,11112
|
|
59
62
|
execsql/metacommands/conditions.py,sha256=u-XdeIWj9QMht9hRGhvH0XlB9V09AliAPKDBHRXc02s,24540
|
|
60
63
|
execsql/metacommands/connect.py,sha256=Nsm0D91i3RX-R2rzQQ-Br-gULaI6Uvdn9fqb7DOAVfE,14804
|
|
61
|
-
execsql/metacommands/control.py,sha256=
|
|
64
|
+
execsql/metacommands/control.py,sha256=CBCg0ZKSR-BGejBW5cXwk6aJ9VrYBzCg9C40ofi8qi8,8776
|
|
62
65
|
execsql/metacommands/data.py,sha256=tRQBGTAuW-eJ2tBNWaoZI9OjTyNNyHJISo7gOdL-sm8,11370
|
|
63
66
|
execsql/metacommands/debug.py,sha256=nmfQ2ijUbTQO3drnyV9EzFueGSTfMl-CddP_NlQyI14,8178
|
|
64
|
-
execsql/metacommands/dispatch.py,sha256=
|
|
65
|
-
execsql/metacommands/io.py,sha256=
|
|
66
|
-
execsql/metacommands/io_export.py,sha256=
|
|
67
|
+
execsql/metacommands/dispatch.py,sha256=I6HoBKMofRalL1Cmdsnj1jQFZSFXCgntTofFaIZWgWQ,83670
|
|
68
|
+
execsql/metacommands/io.py,sha256=Duh60caM4go9JczbGYNMKKYpcMimwPzF6EQ_tshKxdE,2971
|
|
69
|
+
execsql/metacommands/io_export.py,sha256=7lkCSnPhXy9FVau9_hT1u68NOVdG2DsWmvUh9hM1QWI,18359
|
|
67
70
|
execsql/metacommands/io_fileops.py,sha256=RKqbWPTYiwiqCZYG-lpih0w1JVOY4RBFdWr3BJb_pnY,9669
|
|
68
71
|
execsql/metacommands/io_import.py,sha256=wyxJJdlW07P5ZIhweejhXyyGANAvEhY5uMjKZ200Jyc,12983
|
|
69
72
|
execsql/metacommands/io_write.py,sha256=NpL2aYGfBpbqmPpYsqniYltYfd_SCA1EQz3_4qSdNbo,8279
|
|
@@ -72,7 +75,7 @@ execsql/metacommands/script_ext.py,sha256=TUgAldB2LSJAwZrCvDDi804hQ1d9BDQD2GDqHN
|
|
|
72
75
|
execsql/metacommands/system.py,sha256=sUR5kLL7idTVg8WXIMdd-Kv7nkERIiaeL0beWsz8NyY,7293
|
|
73
76
|
execsql/script/__init__.py,sha256=pIo0EJ7-vg67rSMbOvbri_BOUgLoGoSEUfJgxUN7ZS0,3380
|
|
74
77
|
execsql/script/control.py,sha256=s-1eZdGARM6H1FwZ6VDdO_f50j7bvvRtTHesfUm9tbc,6144
|
|
75
|
-
execsql/script/engine.py,sha256=
|
|
78
|
+
execsql/script/engine.py,sha256=d3iUGF_r4OQAlqKpd8pIuWGAjDlYvzYiKqi-2Ew1-Yo,40213
|
|
76
79
|
execsql/script/variables.py,sha256=MOT9XEHucpuuuHQZM5bklxGMBQcwHzwTBxd0q3aO0XY,11641
|
|
77
80
|
execsql/utils/__init__.py,sha256=0uR6JwVJQRX3vceByNBduCAf5dd5assKjeqJUWvpZoA,278
|
|
78
81
|
execsql/utils/auth.py,sha256=onXzNkNZQZxGC5w7eey06sjvAIAX_Lf9g7nUJtcsel0,7009
|
|
@@ -86,24 +89,24 @@ execsql/utils/numeric.py,sha256=xh02ANSRk3nUpQ-rtm66ILoMqoi7HtzCoRMIOT9U8QI,1570
|
|
|
86
89
|
execsql/utils/regex.py,sha256=diEzTZqU_HHwVMadPAvN1Vgzhl7I03eVaEFGCXyGGL8,3770
|
|
87
90
|
execsql/utils/strings.py,sha256=5Dvzrk-9SIw2lpxXZQkiJbNyo1sy7iXXAtSULlZ0KG8,8488
|
|
88
91
|
execsql/utils/timer.py,sha256=eDYf5VzCNFk7oo90InJucUm3XcBdhYMogjZMqeg9xzc,1899
|
|
89
|
-
execsql2-2.
|
|
90
|
-
execsql2-2.
|
|
91
|
-
execsql2-2.
|
|
92
|
-
execsql2-2.
|
|
93
|
-
execsql2-2.
|
|
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.
|
|
92
|
+
execsql2-2.8.0.data/data/execsql2_extras/README.md,sha256=sxwVyU0ZahCfANv56LahkyuM505kFjrMhe-1SvWE69E,4845
|
|
93
|
+
execsql2-2.8.0.data/data/execsql2_extras/config_settings.sqlite,sha256=aY5cxR7Q7J6zJ4bC9lu5mHUrhy211Cq3MNKPQVCt02E,20480
|
|
94
|
+
execsql2-2.8.0.data/data/execsql2_extras/example_config_prompt.sql,sha256=SY3Jxn1qcVm4kPW9xmmTfknHfvURXmeEYTbRjYrjGSw,7487
|
|
95
|
+
execsql2-2.8.0.data/data/execsql2_extras/execsql.conf,sha256=_45iJ-KWZnB8uMW_gEg067MM5pmGJ-dVl7VbAZMunAE,9530
|
|
96
|
+
execsql2-2.8.0.data/data/execsql2_extras/make_config_db.sql,sha256=WwyC6dK-Eh5CAVppiBCDHqiI1_wEI9U95Ytpr4lsZkg,8726
|
|
97
|
+
execsql2-2.8.0.data/data/execsql2_extras/md_compare.sql,sha256=B8Wd7LZ0vnMY2qvA139JIEBkPObgRH2i5xj6PejTQt8,24092
|
|
98
|
+
execsql2-2.8.0.data/data/execsql2_extras/md_glossary.sql,sha256=DJRHcU5NbFpxTTX-IwH3yRlsboj1q6BBGrUAHKn4Cuo,10796
|
|
99
|
+
execsql2-2.8.0.data/data/execsql2_extras/md_upsert.sql,sha256=v_7GbWh_N1mBTmw3gvTrkagOVp2q0KmXvM8hE-DlFxY,112524
|
|
100
|
+
execsql2-2.8.0.data/data/execsql2_extras/pg_compare.sql,sha256=9dWa8hnfy5dVJI-z2iGpd9JzQmI4j2ziMlEdpnr66ro,24352
|
|
101
|
+
execsql2-2.8.0.data/data/execsql2_extras/pg_glossary.sql,sha256=pKjIIDsROAgJq2H-1qNEcRMAWManivcZ_AEVHzUUlic,9908
|
|
102
|
+
execsql2-2.8.0.data/data/execsql2_extras/pg_upsert.sql,sha256=k7AFiGTLBy3nf-qO5QIaZrEYTAKvdxxU3JDLx9jqkzs,108315
|
|
103
|
+
execsql2-2.8.0.data/data/execsql2_extras/script_template.sql,sha256=1Estacb_vm1FgK41k_G9nuduP1yiA-fQ1Kn4Z4mv5Ao,11153
|
|
104
|
+
execsql2-2.8.0.data/data/execsql2_extras/ss_compare.sql,sha256=TsVxWm3cEpR5-EiMYXNhtaY0arSNeKZhsJdHdLA7xeI,24833
|
|
105
|
+
execsql2-2.8.0.data/data/execsql2_extras/ss_glossary.sql,sha256=cLM7nN8JOIu9ZVP9oY9qdSK3hrnWJiDcX6nZmQQbQWI,13065
|
|
106
|
+
execsql2-2.8.0.data/data/execsql2_extras/ss_upsert.sql,sha256=BCqmBykXBF-BpCgOFeG1qhf2XfScKsxPD17wd1hYfHw,120647
|
|
107
|
+
execsql2-2.8.0.dist-info/METADATA,sha256=fGxvlbidjAgVeGg51ZWXNPcblzQrR3UWbgfF60yGpuA,16849
|
|
108
|
+
execsql2-2.8.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
109
|
+
execsql2-2.8.0.dist-info/entry_points.txt,sha256=sUOxkM-dN1eBGGpSpDLsAaE0yNXYQKWZAfxPOlMkQyk,90
|
|
110
|
+
execsql2-2.8.0.dist-info/licenses/LICENSE.txt,sha256=LBdhuxejF8_bLCHZ2kWfmDXpDGUu914Gbd6_3JjCRe0,676
|
|
111
|
+
execsql2-2.8.0.dist-info/licenses/NOTICE,sha256=sqVrM73Ys9zfvWC_P797lHfTnoPW_ETeBSrUTFaob0A,339
|
|
112
|
+
execsql2-2.8.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|