execsql2 2.0.1__py3-none-any.whl → 2.1.2__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.py +322 -108
- execsql/config.py +134 -114
- execsql/db/access.py +89 -65
- execsql/db/base.py +97 -68
- execsql/db/dsn.py +45 -29
- execsql/db/duckdb.py +4 -5
- execsql/db/factory.py +27 -27
- execsql/db/firebird.py +30 -18
- execsql/db/mysql.py +38 -14
- execsql/db/oracle.py +58 -33
- execsql/db/postgres.py +68 -28
- execsql/db/sqlite.py +36 -27
- execsql/db/sqlserver.py +45 -30
- execsql/exceptions.py +68 -64
- execsql/exporters/__init__.py +1 -1
- execsql/exporters/base.py +42 -17
- execsql/exporters/delimited.py +60 -59
- execsql/exporters/duckdb.py +8 -12
- execsql/exporters/feather.py +32 -24
- execsql/exporters/html.py +33 -30
- execsql/exporters/json.py +18 -17
- execsql/exporters/latex.py +11 -13
- execsql/exporters/ods.py +50 -46
- execsql/exporters/parquet.py +32 -0
- execsql/exporters/pretty.py +16 -15
- execsql/exporters/raw.py +9 -11
- execsql/exporters/sqlite.py +38 -38
- execsql/exporters/templates.py +15 -72
- execsql/exporters/values.py +13 -12
- execsql/exporters/xls.py +26 -26
- execsql/exporters/xml.py +12 -12
- execsql/exporters/zip.py +0 -3
- execsql/gui/__init__.py +2 -2
- execsql/gui/console.py +0 -1
- execsql/gui/desktop.py +6 -7
- execsql/gui/tui.py +8 -14
- execsql/importers/base.py +6 -9
- execsql/importers/csv.py +10 -17
- execsql/importers/feather.py +16 -22
- execsql/importers/ods.py +3 -4
- execsql/importers/xls.py +5 -6
- execsql/metacommands/__init__.py +8 -8
- execsql/metacommands/conditions.py +41 -33
- execsql/metacommands/connect.py +113 -99
- execsql/metacommands/control.py +38 -26
- execsql/metacommands/data.py +35 -33
- execsql/metacommands/debug.py +13 -9
- execsql/metacommands/io.py +288 -229
- execsql/metacommands/prompt.py +179 -157
- execsql/metacommands/script_ext.py +11 -9
- execsql/metacommands/system.py +44 -25
- execsql/models.py +9 -16
- execsql/parser.py +10 -10
- execsql/script.py +183 -157
- execsql/state.py +170 -208
- execsql/types.py +46 -81
- execsql/utils/auth.py +114 -14
- execsql/utils/crypto.py +31 -4
- execsql/utils/datetime.py +7 -7
- execsql/utils/errors.py +34 -29
- execsql/utils/fileio.py +90 -55
- execsql/utils/gui.py +22 -23
- execsql/utils/mail.py +15 -17
- execsql/utils/numeric.py +2 -3
- execsql/utils/regex.py +9 -12
- execsql/utils/strings.py +10 -12
- execsql/utils/timer.py +0 -2
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/execsql.conf +1 -1
- execsql2-2.1.2.dist-info/METADATA +300 -0
- execsql2-2.1.2.dist-info/RECORD +96 -0
- execsql2-2.0.1.dist-info/METADATA +0 -406
- execsql2-2.0.1.dist-info/RECORD +0 -95
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/READ_ME.rst +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/config_settings.sqlite +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/make_config_db.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/md_compare.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/md_glossary.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/md_upsert.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/pg_compare.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/pg_glossary.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/pg_upsert.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/script_template.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/ss_compare.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/ss_glossary.sql +0 -0
- {execsql2-2.0.1.data → execsql2-2.1.2.data}/data/execsql2_extras/ss_upsert.sql +0 -0
- {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/WHEEL +0 -0
- {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/entry_points.txt +0 -0
- {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/licenses/LICENSE.txt +0 -0
- {execsql2-2.0.1.dist-info → execsql2-2.1.2.dist-info}/licenses/NOTICE +0 -0
execsql/metacommands/io.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
from execsql.exceptions import ErrInfo
|
|
2
3
|
|
|
3
4
|
"""
|
|
4
5
|
Input/output metacommand handlers for execsql.
|
|
@@ -17,10 +18,60 @@ metacommands:
|
|
|
17
18
|
|
|
18
19
|
import os
|
|
19
20
|
import sys
|
|
21
|
+
from pathlib import Path
|
|
20
22
|
from shutil import copyfileobj
|
|
21
23
|
from typing import Any
|
|
22
24
|
|
|
23
25
|
import execsql.state as _state
|
|
26
|
+
from execsql.exporters.base import ExportRecord
|
|
27
|
+
from execsql.exporters.delimited import CsvFile, write_delimited_file
|
|
28
|
+
from execsql.exporters.duckdb import write_query_to_duckdb
|
|
29
|
+
from execsql.exporters.feather import write_query_to_feather, write_query_to_hdf5
|
|
30
|
+
from execsql.exporters.parquet import write_query_to_parquet
|
|
31
|
+
from execsql.exporters.html import write_query_to_cgi_html, write_query_to_html
|
|
32
|
+
from execsql.exporters.json import write_query_to_json, write_query_to_json_ts
|
|
33
|
+
from execsql.exporters.latex import write_query_to_latex
|
|
34
|
+
from execsql.exporters.ods import OdsFile, write_queries_to_ods, write_query_to_ods
|
|
35
|
+
from execsql.exporters.pretty import prettyprint_query, prettyprint_rowset
|
|
36
|
+
from execsql.exporters.raw import write_query_b64, write_query_raw
|
|
37
|
+
from execsql.exporters.sqlite import write_query_to_sqlite
|
|
38
|
+
from execsql.exporters.templates import report_query
|
|
39
|
+
from execsql.exporters.values import write_query_to_values
|
|
40
|
+
from execsql.exporters.xls import XlsFile, XlsxFile
|
|
41
|
+
from execsql.exporters.xml import write_query_to_xml
|
|
42
|
+
from execsql.importers.base import import_data_table
|
|
43
|
+
from execsql.importers.csv import importfile, importtable
|
|
44
|
+
from execsql.importers.feather import import_feather, import_parquet
|
|
45
|
+
from execsql.importers.ods import importods, ods_data
|
|
46
|
+
from execsql.importers.xls import importxls, xls_data
|
|
47
|
+
from execsql.models import DataTable
|
|
48
|
+
from execsql.script import current_script_line, read_sqlfile, substitute_vars
|
|
49
|
+
from execsql.types import dbt_firebird
|
|
50
|
+
from execsql.utils.errors import exception_desc
|
|
51
|
+
from execsql.utils.fileio import check_dir, filewriter_close, filewriter_open_as_new, filewriter_write
|
|
52
|
+
from execsql.utils.gui import ConsoleUIError
|
|
53
|
+
from execsql.utils.strings import clean_words, fold_words, unquoted
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _apply_output_dir(path: str) -> str:
|
|
57
|
+
"""Prepend the configured --output-dir to *path* if it is a relative path.
|
|
58
|
+
|
|
59
|
+
If ``conf.export_output_dir`` is set and *path* is not absolute (and not
|
|
60
|
+
``stdout``), the base directory is joined to *path* so that all EXPORT
|
|
61
|
+
output lands in the same directory without requiring scripts to hard-code
|
|
62
|
+
absolute paths.
|
|
63
|
+
"""
|
|
64
|
+
output_dir = getattr(_state.conf, "export_output_dir", None)
|
|
65
|
+
if not output_dir:
|
|
66
|
+
return path
|
|
67
|
+
if path.lower() == "stdout":
|
|
68
|
+
return path
|
|
69
|
+
if Path(path).is_absolute():
|
|
70
|
+
return path
|
|
71
|
+
# Windows drive-letter paths are also absolute
|
|
72
|
+
if len(path) > 1 and path[1] == ":":
|
|
73
|
+
return path
|
|
74
|
+
return str(Path(output_dir) / path)
|
|
24
75
|
|
|
25
76
|
|
|
26
77
|
def x_export(**kwargs: Any) -> None:
|
|
@@ -28,40 +79,42 @@ def x_export(**kwargs: Any) -> None:
|
|
|
28
79
|
table = kwargs["table"]
|
|
29
80
|
queryname = _state.dbs.current().schema_qualified_table_name(schema, table)
|
|
30
81
|
select_stmt = f"select * from {queryname};"
|
|
31
|
-
outfile = kwargs["filename"]
|
|
82
|
+
outfile = _apply_output_dir(kwargs["filename"])
|
|
32
83
|
description = kwargs["description"]
|
|
33
84
|
tee = kwargs["tee"]
|
|
34
|
-
tee =
|
|
85
|
+
tee = bool(tee)
|
|
35
86
|
append = kwargs["append"]
|
|
36
|
-
append =
|
|
87
|
+
append = bool(append)
|
|
37
88
|
filefmt = kwargs["format"].lower()
|
|
38
|
-
zipfilename = kwargs["zipfilename"]
|
|
89
|
+
zipfilename = _apply_output_dir(kwargs["zipfilename"]) if kwargs["zipfilename"] else None
|
|
39
90
|
if zipfilename is not None:
|
|
40
91
|
if outfile.lower() == "stdout":
|
|
41
|
-
raise
|
|
92
|
+
raise ErrInfo("error", other_msg="Cannot write stdout to a zipfile.")
|
|
42
93
|
elif len(outfile) > 1 and outfile[1] == ":":
|
|
43
|
-
raise
|
|
94
|
+
raise ErrInfo("error", other_msg="Cannot use a drive letter for a file path within a zipfile.")
|
|
44
95
|
if filefmt == "duckdb":
|
|
45
|
-
raise
|
|
96
|
+
raise ErrInfo("error", other_msg="Cannot export to the DuckDB format within a zipfile.")
|
|
46
97
|
if filefmt == "sqlite":
|
|
47
|
-
raise
|
|
98
|
+
raise ErrInfo("error", other_msg="Cannot export to the SQLite format within a zipfile.")
|
|
48
99
|
if filefmt == "latex":
|
|
49
|
-
raise
|
|
100
|
+
raise ErrInfo("error", other_msg="Cannot export to the LaTeX format within a zipfile.")
|
|
50
101
|
if filefmt == "feather":
|
|
51
|
-
raise
|
|
102
|
+
raise ErrInfo("error", other_msg="Cannot export to the feather format within a zipfile.")
|
|
103
|
+
if filefmt == "parquet":
|
|
104
|
+
raise ErrInfo("error", other_msg="Cannot export to the parquet format within a zipfile.")
|
|
52
105
|
if filefmt == "hdf5":
|
|
53
|
-
raise
|
|
106
|
+
raise ErrInfo("error", other_msg="Cannot export to the HDF5 format within a zipfile.")
|
|
54
107
|
if filefmt == "ods":
|
|
55
|
-
raise
|
|
56
|
-
notype =
|
|
108
|
+
raise ErrInfo("error", other_msg="Cannot export to an ODS workbook within a zipfile.")
|
|
109
|
+
notype = bool(kwargs.get("notype"))
|
|
57
110
|
if zipfilename is not None:
|
|
58
|
-
|
|
111
|
+
check_dir(zipfilename)
|
|
59
112
|
else:
|
|
60
|
-
|
|
113
|
+
check_dir(outfile)
|
|
61
114
|
if tee and outfile.lower() != "stdout":
|
|
62
|
-
|
|
115
|
+
prettyprint_query(select_stmt, _state.dbs.current(), "stdout", False, desc=description)
|
|
63
116
|
if filefmt in ("txt", "text"):
|
|
64
|
-
|
|
117
|
+
prettyprint_query(
|
|
65
118
|
select_stmt,
|
|
66
119
|
_state.dbs.current(),
|
|
67
120
|
outfile,
|
|
@@ -70,7 +123,7 @@ def x_export(**kwargs: Any) -> None:
|
|
|
70
123
|
zipfile=zipfilename,
|
|
71
124
|
)
|
|
72
125
|
elif filefmt in ("txt-and", "text-and"):
|
|
73
|
-
|
|
126
|
+
prettyprint_query(
|
|
74
127
|
select_stmt,
|
|
75
128
|
_state.dbs.current(),
|
|
76
129
|
outfile,
|
|
@@ -80,7 +133,7 @@ def x_export(**kwargs: Any) -> None:
|
|
|
80
133
|
zipfile=zipfilename,
|
|
81
134
|
)
|
|
82
135
|
elif filefmt == "ods":
|
|
83
|
-
|
|
136
|
+
write_query_to_ods(
|
|
84
137
|
select_stmt,
|
|
85
138
|
_state.dbs.current(),
|
|
86
139
|
outfile,
|
|
@@ -89,11 +142,11 @@ def x_export(**kwargs: Any) -> None:
|
|
|
89
142
|
desc=description,
|
|
90
143
|
)
|
|
91
144
|
elif filefmt == "duckdb":
|
|
92
|
-
|
|
145
|
+
write_query_to_duckdb(select_stmt, _state.dbs.current(), outfile, append, tablename=queryname)
|
|
93
146
|
elif filefmt == "sqlite":
|
|
94
|
-
|
|
147
|
+
write_query_to_sqlite(select_stmt, _state.dbs.current(), outfile, append, tablename=queryname)
|
|
95
148
|
elif filefmt == "xml":
|
|
96
|
-
|
|
149
|
+
write_query_to_xml(
|
|
97
150
|
select_stmt,
|
|
98
151
|
table,
|
|
99
152
|
_state.dbs.current(),
|
|
@@ -103,7 +156,7 @@ def x_export(**kwargs: Any) -> None:
|
|
|
103
156
|
zipfile=zipfilename,
|
|
104
157
|
)
|
|
105
158
|
elif filefmt == "json":
|
|
106
|
-
|
|
159
|
+
write_query_to_json(
|
|
107
160
|
select_stmt,
|
|
108
161
|
_state.dbs.current(),
|
|
109
162
|
outfile,
|
|
@@ -112,7 +165,7 @@ def x_export(**kwargs: Any) -> None:
|
|
|
112
165
|
zipfile=zipfilename,
|
|
113
166
|
)
|
|
114
167
|
elif filefmt in ("json_ts", "json_tableschema"):
|
|
115
|
-
|
|
168
|
+
write_query_to_json_ts(
|
|
116
169
|
select_stmt,
|
|
117
170
|
_state.dbs.current(),
|
|
118
171
|
outfile,
|
|
@@ -122,7 +175,7 @@ def x_export(**kwargs: Any) -> None:
|
|
|
122
175
|
zipfile=zipfilename,
|
|
123
176
|
)
|
|
124
177
|
elif filefmt == "values":
|
|
125
|
-
|
|
178
|
+
write_query_to_values(
|
|
126
179
|
select_stmt,
|
|
127
180
|
_state.dbs.current(),
|
|
128
181
|
outfile,
|
|
@@ -131,7 +184,7 @@ def x_export(**kwargs: Any) -> None:
|
|
|
131
184
|
zipfile=zipfilename,
|
|
132
185
|
)
|
|
133
186
|
elif filefmt == "html":
|
|
134
|
-
|
|
187
|
+
write_query_to_html(
|
|
135
188
|
select_stmt,
|
|
136
189
|
_state.dbs.current(),
|
|
137
190
|
outfile,
|
|
@@ -140,7 +193,7 @@ def x_export(**kwargs: Any) -> None:
|
|
|
140
193
|
zipfile=zipfilename,
|
|
141
194
|
)
|
|
142
195
|
elif filefmt == "cgi-html":
|
|
143
|
-
|
|
196
|
+
write_query_to_cgi_html(
|
|
144
197
|
select_stmt,
|
|
145
198
|
_state.dbs.current(),
|
|
146
199
|
outfile,
|
|
@@ -149,7 +202,7 @@ def x_export(**kwargs: Any) -> None:
|
|
|
149
202
|
zipfile=zipfilename,
|
|
150
203
|
)
|
|
151
204
|
elif filefmt == "latex":
|
|
152
|
-
|
|
205
|
+
write_query_to_latex(
|
|
153
206
|
select_stmt,
|
|
154
207
|
_state.dbs.current(),
|
|
155
208
|
outfile,
|
|
@@ -158,23 +211,25 @@ def x_export(**kwargs: Any) -> None:
|
|
|
158
211
|
zipfile=zipfilename,
|
|
159
212
|
)
|
|
160
213
|
elif filefmt == "hdf5":
|
|
161
|
-
|
|
214
|
+
write_query_to_hdf5(table, select_stmt, _state.dbs.current(), outfile, append, desc=description)
|
|
162
215
|
else:
|
|
163
216
|
try:
|
|
164
217
|
hdrs, rows = _state.dbs.current().select_rowsource(select_stmt)
|
|
165
|
-
except
|
|
218
|
+
except ErrInfo:
|
|
166
219
|
raise
|
|
167
220
|
except Exception:
|
|
168
|
-
raise
|
|
221
|
+
raise ErrInfo("db", select_stmt, exception_msg=exception_desc())
|
|
169
222
|
if filefmt == "raw":
|
|
170
|
-
|
|
223
|
+
write_query_raw(outfile, rows, _state.dbs.current().encoding, append, zipfile=zipfilename)
|
|
171
224
|
elif filefmt == "b64":
|
|
172
|
-
|
|
225
|
+
write_query_b64(outfile, rows, append)
|
|
173
226
|
elif filefmt == "feather":
|
|
174
|
-
|
|
227
|
+
write_query_to_feather(outfile, hdrs, rows)
|
|
228
|
+
elif filefmt == "parquet":
|
|
229
|
+
write_query_to_parquet(outfile, hdrs, rows)
|
|
175
230
|
else:
|
|
176
|
-
|
|
177
|
-
_state.export_metadata.add(
|
|
231
|
+
write_delimited_file(outfile, filefmt, hdrs, rows, _state.conf.output_encoding, append, zipfilename)
|
|
232
|
+
_state.export_metadata.add(ExportRecord(queryname, outfile, zipfilename, description))
|
|
178
233
|
return None
|
|
179
234
|
|
|
180
235
|
|
|
@@ -183,30 +238,32 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
183
238
|
outfile = kwargs["filename"]
|
|
184
239
|
description = kwargs["description"]
|
|
185
240
|
tee = kwargs["tee"]
|
|
186
|
-
tee =
|
|
241
|
+
tee = bool(tee)
|
|
187
242
|
append = kwargs["append"]
|
|
188
|
-
append =
|
|
243
|
+
append = bool(append)
|
|
189
244
|
filefmt = kwargs["format"].lower()
|
|
190
245
|
zipfilename = kwargs["zipfilename"]
|
|
191
246
|
if zipfilename is not None:
|
|
192
247
|
if outfile == "stdout":
|
|
193
|
-
raise
|
|
248
|
+
raise ErrInfo("error", other_msg="Cannot write stdout to a zipfile.")
|
|
194
249
|
elif len(outfile) > 1 and outfile[1] == ":":
|
|
195
|
-
raise
|
|
250
|
+
raise ErrInfo("error", other_msg="Cannot use a drive letter for a file path within a zipfile.")
|
|
196
251
|
if filefmt == "latex":
|
|
197
|
-
raise
|
|
252
|
+
raise ErrInfo("error", other_msg="Cannot export to the LaTeX format within a zipfile.")
|
|
198
253
|
if filefmt == "feather":
|
|
199
|
-
raise
|
|
254
|
+
raise ErrInfo("error", other_msg="Cannot export to the feather format within a zipfile.")
|
|
255
|
+
if filefmt == "parquet":
|
|
256
|
+
raise ErrInfo("error", other_msg="Cannot export to the parquet format within a zipfile.")
|
|
200
257
|
if filefmt == "hdf5":
|
|
201
|
-
raise
|
|
258
|
+
raise ErrInfo("error", other_msg="Cannot export to the HDF5 format within a zipfile.")
|
|
202
259
|
if filefmt == "ods":
|
|
203
|
-
raise
|
|
204
|
-
notype =
|
|
205
|
-
|
|
260
|
+
raise ErrInfo("error", other_msg="Cannot export to an ODS workbook within a zipfile.")
|
|
261
|
+
notype = bool(kwargs.get("notype"))
|
|
262
|
+
check_dir(outfile)
|
|
206
263
|
if tee and outfile.lower() != "stdout":
|
|
207
|
-
|
|
264
|
+
prettyprint_query(select_stmt, _state.dbs.current(), "stdout", False, desc=description)
|
|
208
265
|
if filefmt in ("txt", "text"):
|
|
209
|
-
|
|
266
|
+
prettyprint_query(
|
|
210
267
|
select_stmt,
|
|
211
268
|
_state.dbs.current(),
|
|
212
269
|
outfile,
|
|
@@ -215,7 +272,7 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
215
272
|
zipfile=zipfilename,
|
|
216
273
|
)
|
|
217
274
|
elif filefmt in ("txt-and", "text-and"):
|
|
218
|
-
|
|
275
|
+
prettyprint_query(
|
|
219
276
|
select_stmt,
|
|
220
277
|
_state.dbs.current(),
|
|
221
278
|
outfile,
|
|
@@ -225,8 +282,8 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
225
282
|
zipfile=zipfilename,
|
|
226
283
|
)
|
|
227
284
|
elif filefmt == "ods":
|
|
228
|
-
script_name, lno =
|
|
229
|
-
|
|
285
|
+
script_name, lno = current_script_line()
|
|
286
|
+
write_query_to_ods(
|
|
230
287
|
select_stmt,
|
|
231
288
|
_state.dbs.current(),
|
|
232
289
|
outfile,
|
|
@@ -235,7 +292,7 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
235
292
|
desc=description,
|
|
236
293
|
)
|
|
237
294
|
elif filefmt == "json":
|
|
238
|
-
|
|
295
|
+
write_query_to_json(
|
|
239
296
|
select_stmt,
|
|
240
297
|
_state.dbs.current(),
|
|
241
298
|
outfile,
|
|
@@ -244,7 +301,7 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
244
301
|
zipfile=zipfilename,
|
|
245
302
|
)
|
|
246
303
|
elif filefmt in ("json_ts", "json_tableschema"):
|
|
247
|
-
|
|
304
|
+
write_query_to_json_ts(
|
|
248
305
|
select_stmt,
|
|
249
306
|
_state.dbs.current(),
|
|
250
307
|
outfile,
|
|
@@ -254,7 +311,7 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
254
311
|
zipfile=zipfilename,
|
|
255
312
|
)
|
|
256
313
|
elif filefmt == "values":
|
|
257
|
-
|
|
314
|
+
write_query_to_values(
|
|
258
315
|
select_stmt,
|
|
259
316
|
_state.dbs.current(),
|
|
260
317
|
outfile,
|
|
@@ -263,7 +320,7 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
263
320
|
zipfile=zipfilename,
|
|
264
321
|
)
|
|
265
322
|
elif filefmt == "html":
|
|
266
|
-
|
|
323
|
+
write_query_to_html(
|
|
267
324
|
select_stmt,
|
|
268
325
|
_state.dbs.current(),
|
|
269
326
|
outfile,
|
|
@@ -272,7 +329,7 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
272
329
|
zipfile=zipfilename,
|
|
273
330
|
)
|
|
274
331
|
elif filefmt == "cgi-html":
|
|
275
|
-
|
|
332
|
+
write_query_to_cgi_html(
|
|
276
333
|
select_stmt,
|
|
277
334
|
_state.dbs.current(),
|
|
278
335
|
outfile,
|
|
@@ -281,7 +338,7 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
281
338
|
zipfile=zipfilename,
|
|
282
339
|
)
|
|
283
340
|
elif filefmt == "latex":
|
|
284
|
-
|
|
341
|
+
write_query_to_latex(
|
|
285
342
|
select_stmt,
|
|
286
343
|
_state.dbs.current(),
|
|
287
344
|
outfile,
|
|
@@ -292,18 +349,20 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
292
349
|
else:
|
|
293
350
|
try:
|
|
294
351
|
hdrs, rows = _state.dbs.current().select_rowsource(select_stmt)
|
|
295
|
-
except
|
|
352
|
+
except ErrInfo:
|
|
296
353
|
raise
|
|
297
354
|
except Exception:
|
|
298
|
-
raise
|
|
355
|
+
raise ErrInfo("db", select_stmt, exception_msg=exception_desc())
|
|
299
356
|
if filefmt == "raw":
|
|
300
|
-
|
|
357
|
+
write_query_raw(outfile, rows, _state.dbs.current().encoding, append, zipfile=zipfilename)
|
|
301
358
|
elif filefmt == "b64":
|
|
302
|
-
|
|
359
|
+
write_query_b64(outfile, rows, append, zipfile=zipfilename)
|
|
303
360
|
elif filefmt == "feather":
|
|
304
|
-
|
|
361
|
+
write_query_to_feather(outfile, hdrs, rows)
|
|
362
|
+
elif filefmt == "parquet":
|
|
363
|
+
write_query_to_parquet(outfile, hdrs, rows)
|
|
305
364
|
else:
|
|
306
|
-
|
|
365
|
+
write_delimited_file(
|
|
307
366
|
outfile,
|
|
308
367
|
filefmt,
|
|
309
368
|
hdrs,
|
|
@@ -312,7 +371,7 @@ def x_export_query(**kwargs: Any) -> None:
|
|
|
312
371
|
append,
|
|
313
372
|
zipfile=zipfilename,
|
|
314
373
|
)
|
|
315
|
-
_state.export_metadata.add(
|
|
374
|
+
_state.export_metadata.add(ExportRecord(select_stmt, outfile, zipfilename, description))
|
|
316
375
|
return None
|
|
317
376
|
|
|
318
377
|
|
|
@@ -321,15 +380,15 @@ def x_export_query_with_template(**kwargs: Any) -> None:
|
|
|
321
380
|
outfile = kwargs["filename"]
|
|
322
381
|
template_file = kwargs["template"]
|
|
323
382
|
tee = kwargs["tee"]
|
|
324
|
-
tee =
|
|
383
|
+
tee = bool(tee)
|
|
325
384
|
append = kwargs["append"]
|
|
326
|
-
append =
|
|
385
|
+
append = bool(append)
|
|
327
386
|
zipfilename = kwargs["zipfilename"]
|
|
328
|
-
|
|
387
|
+
check_dir(outfile)
|
|
329
388
|
if tee and outfile.lower() != "stdout":
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
_state.export_metadata.add(
|
|
389
|
+
prettyprint_query(select_stmt, _state.dbs.current(), "stdout", False)
|
|
390
|
+
report_query(select_stmt, _state.dbs.current(), outfile, template_file, append, zipfile=zipfilename)
|
|
391
|
+
_state.export_metadata.add(ExportRecord(select_stmt, outfile, zipfilename))
|
|
333
392
|
return None
|
|
334
393
|
|
|
335
394
|
|
|
@@ -341,15 +400,15 @@ def x_export_with_template(**kwargs: Any) -> None:
|
|
|
341
400
|
outfile = kwargs["filename"]
|
|
342
401
|
template_file = kwargs["template"]
|
|
343
402
|
tee = kwargs["tee"]
|
|
344
|
-
tee =
|
|
403
|
+
tee = bool(tee)
|
|
345
404
|
append = kwargs["append"]
|
|
346
|
-
append =
|
|
405
|
+
append = bool(append)
|
|
347
406
|
zipfilename = kwargs["zipfilename"]
|
|
348
|
-
|
|
407
|
+
check_dir(outfile)
|
|
349
408
|
if tee and outfile.lower() != "stdout":
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
_state.export_metadata.add(
|
|
409
|
+
prettyprint_query(select_stmt, _state.dbs.current(), "stdout", False)
|
|
410
|
+
report_query(select_stmt, _state.dbs.current(), outfile, template_file, append, zipfile=zipfilename)
|
|
411
|
+
_state.export_metadata.add(ExportRecord(queryname, outfile, zipfilename))
|
|
353
412
|
return None
|
|
354
413
|
|
|
355
414
|
|
|
@@ -358,11 +417,11 @@ def x_export_ods_multiple(**kwargs: Any) -> None:
|
|
|
358
417
|
outfile = kwargs["filename"]
|
|
359
418
|
description = kwargs["description"]
|
|
360
419
|
tee = kwargs["tee"]
|
|
361
|
-
tee =
|
|
420
|
+
tee = bool(tee)
|
|
362
421
|
append = kwargs["append"]
|
|
363
|
-
append =
|
|
364
|
-
|
|
365
|
-
|
|
422
|
+
append = append is not None
|
|
423
|
+
check_dir(outfile)
|
|
424
|
+
write_queries_to_ods(table_list, _state.dbs.current(), outfile, append, tee, desc=description)
|
|
366
425
|
|
|
367
426
|
|
|
368
427
|
def x_export_metadata(**kwargs: Any) -> None:
|
|
@@ -376,11 +435,11 @@ def x_export_metadata(**kwargs: Any) -> None:
|
|
|
376
435
|
else:
|
|
377
436
|
hdrs, rows = _state.export_metadata.get()
|
|
378
437
|
if outfile.lower() != "stdout":
|
|
379
|
-
|
|
438
|
+
check_dir(outfile)
|
|
380
439
|
if filefmt in ("txt", "text"):
|
|
381
|
-
|
|
440
|
+
prettyprint_rowset(hdrs, rows, outfile, append, and_val="", zipfile=zipfilename)
|
|
382
441
|
else:
|
|
383
|
-
|
|
442
|
+
write_delimited_file(outfile, filefmt, hdrs, rows, _state.conf.output_encoding, append, zipfilename)
|
|
384
443
|
|
|
385
444
|
|
|
386
445
|
def x_export_metadata_table(**kwargs: Any) -> None:
|
|
@@ -396,7 +455,7 @@ def x_export_metadata_table(**kwargs: Any) -> None:
|
|
|
396
455
|
hdrs, rows = _state.export_metadata.get_all()
|
|
397
456
|
else:
|
|
398
457
|
hdrs, rows = _state.export_metadata.get()
|
|
399
|
-
|
|
458
|
+
import_data_table(_state.dbs.current(), schemaname, tablename, is_new, hdrs, rows)
|
|
400
459
|
|
|
401
460
|
|
|
402
461
|
def x_import(**kwargs: Any) -> None:
|
|
@@ -409,9 +468,9 @@ def x_import(**kwargs: Any) -> None:
|
|
|
409
468
|
tablename = kwargs["table"]
|
|
410
469
|
filename = kwargs["filename"]
|
|
411
470
|
if len(filename) > 1 and filename[0] == "~" and filename[1] == os.sep:
|
|
412
|
-
filename =
|
|
413
|
-
if not
|
|
414
|
-
raise
|
|
471
|
+
filename = str(Path.home() / filename[2:])
|
|
472
|
+
if not Path(filename).exists():
|
|
473
|
+
raise ErrInfo(
|
|
415
474
|
type="cmd",
|
|
416
475
|
command_text=kwargs["metacommandline"],
|
|
417
476
|
other_msg=f"Input file {filename} does not exist",
|
|
@@ -436,7 +495,7 @@ def x_import(**kwargs: Any) -> None:
|
|
|
436
495
|
sz, dt = file_size_date(filename)
|
|
437
496
|
_state.exec_log.log_status_info(f"IMPORTing {filename} ({sz}, {dt})")
|
|
438
497
|
try:
|
|
439
|
-
|
|
498
|
+
importtable(
|
|
440
499
|
_state.dbs.current(),
|
|
441
500
|
schemaname,
|
|
442
501
|
tablename,
|
|
@@ -448,12 +507,12 @@ def x_import(**kwargs: Any) -> None:
|
|
|
448
507
|
encoding=enc,
|
|
449
508
|
junk_header_lines=junk_hdrs,
|
|
450
509
|
)
|
|
451
|
-
except
|
|
510
|
+
except ErrInfo:
|
|
452
511
|
raise
|
|
453
512
|
except Exception:
|
|
454
|
-
raise
|
|
513
|
+
raise ErrInfo(
|
|
455
514
|
"exception",
|
|
456
|
-
exception_msg=
|
|
515
|
+
exception_msg=exception_desc(),
|
|
457
516
|
other_msg=f"Can't import data from tabular text file {filename}",
|
|
458
517
|
)
|
|
459
518
|
return None
|
|
@@ -464,8 +523,8 @@ def x_import_file(**kwargs: Any) -> None:
|
|
|
464
523
|
tablename = kwargs["table"]
|
|
465
524
|
columnname = kwargs["columnname"]
|
|
466
525
|
filename = kwargs["filename"]
|
|
467
|
-
if not
|
|
468
|
-
raise
|
|
526
|
+
if not Path(filename).exists():
|
|
527
|
+
raise ErrInfo(
|
|
469
528
|
type="cmd",
|
|
470
529
|
command_text=kwargs["metacommandline"],
|
|
471
530
|
other_msg=f"Input file {filename} does not exist",
|
|
@@ -475,13 +534,13 @@ def x_import_file(**kwargs: Any) -> None:
|
|
|
475
534
|
sz, dt = file_size_date(filename)
|
|
476
535
|
_state.exec_log.log_status_info(f"IMPORTing_FILE {filename} ({sz}, {dt})")
|
|
477
536
|
try:
|
|
478
|
-
|
|
479
|
-
except
|
|
537
|
+
importfile(_state.dbs.current(), schemaname, tablename, columnname, filename)
|
|
538
|
+
except ErrInfo:
|
|
480
539
|
raise
|
|
481
540
|
except Exception:
|
|
482
|
-
raise
|
|
541
|
+
raise ErrInfo(
|
|
483
542
|
"exception",
|
|
484
|
-
exception_msg=
|
|
543
|
+
exception_msg=exception_desc(),
|
|
485
544
|
other_msg=f"Can't import file {filename}",
|
|
486
545
|
)
|
|
487
546
|
return None
|
|
@@ -502,20 +561,20 @@ def x_import_ods(**kwargs: Any) -> None:
|
|
|
502
561
|
hdr_rows = 0
|
|
503
562
|
else:
|
|
504
563
|
hdr_rows = int(hdr_rows)
|
|
505
|
-
if not
|
|
506
|
-
raise
|
|
564
|
+
if not Path(filename).exists():
|
|
565
|
+
raise ErrInfo(
|
|
507
566
|
type="cmd",
|
|
508
567
|
command_text=kwargs["metacommandline"],
|
|
509
568
|
other_msg="Input file does not exist",
|
|
510
569
|
)
|
|
511
570
|
try:
|
|
512
|
-
|
|
513
|
-
except
|
|
571
|
+
importods(_state.dbs.current(), schemaname, tablename, is_new, filename, sheetname, hdr_rows)
|
|
572
|
+
except ErrInfo:
|
|
514
573
|
raise
|
|
515
574
|
except Exception:
|
|
516
|
-
raise
|
|
575
|
+
raise ErrInfo(
|
|
517
576
|
"exception",
|
|
518
|
-
exception_msg=
|
|
577
|
+
exception_msg=exception_desc(),
|
|
519
578
|
other_msg=f"Can't import data from ODS file {filename}",
|
|
520
579
|
)
|
|
521
580
|
return None
|
|
@@ -537,35 +596,35 @@ def x_import_ods_pattern(**kwargs: Any) -> None:
|
|
|
537
596
|
hdr_rows = 0
|
|
538
597
|
else:
|
|
539
598
|
hdr_rows = int(hdr_rows)
|
|
540
|
-
if not
|
|
541
|
-
raise
|
|
599
|
+
if not Path(filename).exists():
|
|
600
|
+
raise ErrInfo(
|
|
542
601
|
type="cmd",
|
|
543
602
|
command_text=kwargs["metacommandline"],
|
|
544
603
|
other_msg="Input file does not exist",
|
|
545
604
|
)
|
|
546
|
-
wbk =
|
|
605
|
+
wbk = OdsFile()
|
|
547
606
|
try:
|
|
548
607
|
wbk.open(filename)
|
|
549
608
|
except Exception:
|
|
550
|
-
raise
|
|
609
|
+
raise ErrInfo(type="cmd", other_msg=f"{filename} is not a valid OpenDocument spreadsheet.")
|
|
551
610
|
sheets = wbk.sheetnames()
|
|
552
611
|
impsheets = [s for s in sheets if rx.search(s)]
|
|
553
612
|
tables = list(impsheets)
|
|
554
613
|
if _state.conf.clean_col_hdrs:
|
|
555
|
-
tables =
|
|
614
|
+
tables = clean_words(tables)
|
|
556
615
|
if _state.conf.fold_col_hdrs != "no":
|
|
557
|
-
tables =
|
|
616
|
+
tables = fold_words(tables, _state.conf.fold_col_hdrs)
|
|
558
617
|
for ix in range(len(impsheets)):
|
|
559
618
|
sheetname = impsheets[ix]
|
|
560
619
|
tablename = tables[ix]
|
|
561
620
|
try:
|
|
562
|
-
|
|
563
|
-
except
|
|
621
|
+
importods(_state.dbs.current(), schemaname, tablename, is_new, filename, sheetname, hdr_rows)
|
|
622
|
+
except ErrInfo:
|
|
564
623
|
raise
|
|
565
624
|
except Exception:
|
|
566
|
-
raise
|
|
625
|
+
raise ErrInfo(
|
|
567
626
|
"exception",
|
|
568
|
-
exception_msg=
|
|
627
|
+
exception_msg=exception_desc(),
|
|
569
628
|
other_msg=f"Can't import data from ODS file {filename}",
|
|
570
629
|
)
|
|
571
630
|
_state.subvars.add_substitution("$SHEETS_IMPORTED", ",".join(impsheets))
|
|
@@ -593,20 +652,20 @@ def x_import_xls(**kwargs: Any) -> None:
|
|
|
593
652
|
junk_hdrs = 0
|
|
594
653
|
else:
|
|
595
654
|
junk_hdrs = int(junk_hdrs)
|
|
596
|
-
if not
|
|
597
|
-
raise
|
|
655
|
+
if not Path(filename).exists():
|
|
656
|
+
raise ErrInfo(
|
|
598
657
|
type="cmd",
|
|
599
658
|
command_text=kwargs["metacommandline"],
|
|
600
659
|
other_msg="Input file does not exist",
|
|
601
660
|
)
|
|
602
661
|
try:
|
|
603
|
-
|
|
604
|
-
except
|
|
662
|
+
importxls(_state.dbs.current(), schemaname, tablename, is_new, filename, sheetname, junk_hdrs, encoding)
|
|
663
|
+
except ErrInfo:
|
|
605
664
|
raise
|
|
606
665
|
except Exception:
|
|
607
|
-
raise
|
|
666
|
+
raise ErrInfo(
|
|
608
667
|
"exception",
|
|
609
|
-
exception_msg=
|
|
668
|
+
exception_msg=exception_desc(),
|
|
610
669
|
other_msg=f"Can't import data from Excel file {filename}",
|
|
611
670
|
)
|
|
612
671
|
return None
|
|
@@ -629,37 +688,37 @@ def x_import_xls_pattern(**kwargs: Any) -> None:
|
|
|
629
688
|
hdr_rows = 0
|
|
630
689
|
else:
|
|
631
690
|
hdr_rows = int(hdr_rows)
|
|
632
|
-
if not
|
|
633
|
-
raise
|
|
691
|
+
if not Path(filename).exists():
|
|
692
|
+
raise ErrInfo(
|
|
634
693
|
type="cmd",
|
|
635
694
|
command_text=kwargs["metacommandline"],
|
|
636
695
|
other_msg="Input file does not exist",
|
|
637
696
|
)
|
|
638
697
|
if len(filename) < 4:
|
|
639
|
-
raise
|
|
698
|
+
raise ErrInfo(type="cmd", other_msg=f"{filename} is not a recognizable Excel spreadsheet name.")
|
|
640
699
|
ext3 = filename[-3:].lower()
|
|
641
700
|
if ext3 == "xls":
|
|
642
|
-
wbk =
|
|
701
|
+
wbk = XlsFile()
|
|
643
702
|
elif ext3 == "lsx":
|
|
644
|
-
wbk =
|
|
703
|
+
wbk = XlsxFile()
|
|
645
704
|
else:
|
|
646
|
-
raise
|
|
705
|
+
raise ErrInfo(type="cmd", other_msg=f"{filename} is not a recognizable Excel spreadsheet name.")
|
|
647
706
|
try:
|
|
648
707
|
wbk.open(filename, encoding, read_only=True)
|
|
649
708
|
except Exception:
|
|
650
|
-
raise
|
|
709
|
+
raise ErrInfo(type="cmd", other_msg=f"{filename} is not a valid Excel spreadsheet.")
|
|
651
710
|
sheets = wbk.sheetnames()
|
|
652
711
|
impsheets = [s for s in sheets if rx.search(s)]
|
|
653
712
|
tables = list(impsheets)
|
|
654
713
|
if _state.conf.clean_col_hdrs:
|
|
655
|
-
tables =
|
|
714
|
+
tables = clean_words(tables)
|
|
656
715
|
if _state.conf.fold_col_hdrs != "no":
|
|
657
|
-
tables =
|
|
716
|
+
tables = fold_words(tables, _state.conf.fold_col_hdrs)
|
|
658
717
|
for ix in range(len(impsheets)):
|
|
659
718
|
sheetname = impsheets[ix]
|
|
660
719
|
tablename = tables[ix]
|
|
661
720
|
try:
|
|
662
|
-
|
|
721
|
+
importxls(
|
|
663
722
|
_state.dbs.current(),
|
|
664
723
|
schemaname,
|
|
665
724
|
tablename,
|
|
@@ -669,12 +728,12 @@ def x_import_xls_pattern(**kwargs: Any) -> None:
|
|
|
669
728
|
hdr_rows,
|
|
670
729
|
encoding,
|
|
671
730
|
)
|
|
672
|
-
except
|
|
731
|
+
except ErrInfo:
|
|
673
732
|
raise
|
|
674
733
|
except Exception:
|
|
675
|
-
raise
|
|
734
|
+
raise ErrInfo(
|
|
676
735
|
"exception",
|
|
677
|
-
exception_msg=
|
|
736
|
+
exception_msg=exception_desc(),
|
|
678
737
|
other_msg=f"Can't import data from ODS file {filename}",
|
|
679
738
|
)
|
|
680
739
|
_state.subvars.add_substitution("$SHEETS_IMPORTED", ",".join(impsheets))
|
|
@@ -696,9 +755,9 @@ def x_import_parquet(**kwargs: Any) -> None:
|
|
|
696
755
|
tablename = kwargs["table"]
|
|
697
756
|
filename = kwargs["filename"]
|
|
698
757
|
if len(filename) > 1 and filename[0] == "~" and filename[1] == os.sep:
|
|
699
|
-
filename =
|
|
700
|
-
if not
|
|
701
|
-
raise
|
|
758
|
+
filename = str(Path.home() / filename[2:])
|
|
759
|
+
if not Path(filename).exists():
|
|
760
|
+
raise ErrInfo(
|
|
702
761
|
type="cmd",
|
|
703
762
|
command_text=kwargs["metacommandline"],
|
|
704
763
|
other_msg=f"Input file {filename} does not exist",
|
|
@@ -708,13 +767,13 @@ def x_import_parquet(**kwargs: Any) -> None:
|
|
|
708
767
|
sz, dt = file_size_date(filename)
|
|
709
768
|
_state.exec_log.log_status_info(f"IMPORTing from Parquet file {filename} ({sz}, {dt})")
|
|
710
769
|
try:
|
|
711
|
-
|
|
712
|
-
except
|
|
770
|
+
import_parquet(_state.dbs.current(), schemaname, tablename, filename, is_new)
|
|
771
|
+
except ErrInfo:
|
|
713
772
|
raise
|
|
714
773
|
except Exception:
|
|
715
|
-
raise
|
|
774
|
+
raise ErrInfo(
|
|
716
775
|
"exception",
|
|
717
|
-
exception_msg=
|
|
776
|
+
exception_msg=exception_desc(),
|
|
718
777
|
other_msg=f"Can't import data from Parquet data file {filename}",
|
|
719
778
|
)
|
|
720
779
|
return None
|
|
@@ -730,9 +789,9 @@ def x_import_feather(**kwargs: Any) -> None:
|
|
|
730
789
|
tablename = kwargs["table"]
|
|
731
790
|
filename = kwargs["filename"]
|
|
732
791
|
if len(filename) > 1 and filename[0] == "~" and filename[1] == os.sep:
|
|
733
|
-
filename =
|
|
734
|
-
if not
|
|
735
|
-
raise
|
|
792
|
+
filename = str(Path.home() / filename[2:])
|
|
793
|
+
if not Path(filename).exists():
|
|
794
|
+
raise ErrInfo(
|
|
736
795
|
type="cmd",
|
|
737
796
|
command_text=kwargs["metacommandline"],
|
|
738
797
|
other_msg=f"Input file {filename} does not exist",
|
|
@@ -742,13 +801,13 @@ def x_import_feather(**kwargs: Any) -> None:
|
|
|
742
801
|
sz, dt = file_size_date(filename)
|
|
743
802
|
_state.exec_log.log_status_info(f"IMPORTing from Feather file {filename} ({sz}, {dt})")
|
|
744
803
|
try:
|
|
745
|
-
|
|
746
|
-
except
|
|
804
|
+
import_feather(_state.dbs.current(), schemaname, tablename, filename, is_new)
|
|
805
|
+
except ErrInfo:
|
|
747
806
|
raise
|
|
748
807
|
except Exception:
|
|
749
|
-
raise
|
|
808
|
+
raise ErrInfo(
|
|
750
809
|
"exception",
|
|
751
|
-
exception_msg=
|
|
810
|
+
exception_msg=exception_desc(),
|
|
752
811
|
other_msg=f"Can't import data from Feather data file {filename}",
|
|
753
812
|
)
|
|
754
813
|
return None
|
|
@@ -767,25 +826,25 @@ def x_export_row_buffer(**kwargs: Any) -> None:
|
|
|
767
826
|
def x_write(**kwargs: Any) -> None:
|
|
768
827
|
msg = f"{kwargs['text']}\n"
|
|
769
828
|
tee = kwargs["tee"]
|
|
770
|
-
tee =
|
|
829
|
+
tee = bool(tee)
|
|
771
830
|
outf = kwargs["filename"]
|
|
772
831
|
if _state.conf.write_prefix is not None:
|
|
773
|
-
msg =
|
|
832
|
+
msg = substitute_vars(_state.conf.write_prefix) + " " + msg
|
|
774
833
|
if _state.conf.write_suffix is not None:
|
|
775
|
-
msg = msg[:-1] + " " +
|
|
834
|
+
msg = msg[:-1] + " " + substitute_vars(_state.conf.write_suffix) + "\n"
|
|
776
835
|
if outf:
|
|
777
|
-
|
|
778
|
-
|
|
836
|
+
check_dir(outf)
|
|
837
|
+
filewriter_write(outf, msg)
|
|
779
838
|
if (not outf) or tee:
|
|
780
839
|
try:
|
|
781
840
|
_state.output.write(msg)
|
|
782
841
|
except TypeError:
|
|
783
|
-
raise
|
|
842
|
+
raise ErrInfo(
|
|
784
843
|
type="other",
|
|
785
844
|
command_text=kwargs["metacommandline"],
|
|
786
845
|
other_msg="TypeError in 'write' metacommand.",
|
|
787
846
|
)
|
|
788
|
-
except
|
|
847
|
+
except ConsoleUIError as e:
|
|
789
848
|
_state.output.reset()
|
|
790
849
|
_state.exec_log.log_status_info(f"Console UI write failed (message {{{e.value}}}); output reset to stdout.")
|
|
791
850
|
_state.output.write(msg.encode(_state.conf.output_encoding))
|
|
@@ -796,8 +855,8 @@ def x_write(**kwargs: Any) -> None:
|
|
|
796
855
|
|
|
797
856
|
def x_write_create_table(**kwargs: Any) -> None:
|
|
798
857
|
filename = kwargs["filename"]
|
|
799
|
-
if not
|
|
800
|
-
raise
|
|
858
|
+
if not Path(filename).exists():
|
|
859
|
+
raise ErrInfo(
|
|
801
860
|
type="cmd",
|
|
802
861
|
command_text=kwargs["metacommandline"],
|
|
803
862
|
other_msg="Input file does not exist",
|
|
@@ -815,8 +874,8 @@ def x_write_create_table(**kwargs: Any) -> None:
|
|
|
815
874
|
junk_hdrs = 0
|
|
816
875
|
else:
|
|
817
876
|
junk_hdrs = int(junk_hdrs)
|
|
818
|
-
enc =
|
|
819
|
-
inf =
|
|
877
|
+
enc = encoding if encoding else _state.conf.import_encoding
|
|
878
|
+
inf = CsvFile(filename, enc, junk_header_lines=junk_hdrs)
|
|
820
879
|
if quotechar and delimchar:
|
|
821
880
|
inf.lineformat(delimchar, quotechar, None)
|
|
822
881
|
inf.evaluate_column_types()
|
|
@@ -829,10 +888,10 @@ def x_write_create_table(**kwargs: Any) -> None:
|
|
|
829
888
|
if outfile is None or outfile == "stdout":
|
|
830
889
|
_state.output.write(txt)
|
|
831
890
|
else:
|
|
832
|
-
|
|
891
|
+
filewriter_write(outfile, txt)
|
|
833
892
|
|
|
834
893
|
if outfile:
|
|
835
|
-
|
|
894
|
+
check_dir(outfile)
|
|
836
895
|
if comment:
|
|
837
896
|
write(f"-- {comment}\n")
|
|
838
897
|
write(f"{sql}\n")
|
|
@@ -850,20 +909,20 @@ def x_write_create_table_ods(**kwargs: Any) -> None:
|
|
|
850
909
|
hdr_rows = int(hdr_rows)
|
|
851
910
|
comment = kwargs["comment"]
|
|
852
911
|
outfile = kwargs["outfile"]
|
|
853
|
-
if not
|
|
854
|
-
raise
|
|
912
|
+
if not Path(filename).exists():
|
|
913
|
+
raise ErrInfo(
|
|
855
914
|
type="cmd",
|
|
856
915
|
command_text=kwargs["metacommandline"],
|
|
857
916
|
other_msg="Input file does not exist",
|
|
858
917
|
)
|
|
859
|
-
hdrs, data =
|
|
860
|
-
tablespec =
|
|
918
|
+
hdrs, data = ods_data(filename, sheetname, hdr_rows)
|
|
919
|
+
tablespec = DataTable(hdrs, data)
|
|
861
920
|
sql = tablespec.create_table(_state.dbs.current().type, schemaname, tablename, pretty=True)
|
|
862
921
|
if outfile:
|
|
863
922
|
if comment:
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
923
|
+
filewriter_write(outfile, f"-- {comment}\n")
|
|
924
|
+
filewriter_write(outfile, sql)
|
|
925
|
+
filewriter_close(outfile)
|
|
867
926
|
else:
|
|
868
927
|
if comment:
|
|
869
928
|
_state.output.write(f"-- {comment}\n")
|
|
@@ -877,27 +936,27 @@ def x_write_create_table_xls(**kwargs: Any) -> None:
|
|
|
877
936
|
sheetname = kwargs["sheet"]
|
|
878
937
|
junk_hdrs = kwargs["skip"]
|
|
879
938
|
encoding = kwargs["encoding"]
|
|
880
|
-
enc =
|
|
939
|
+
enc = encoding if encoding else _state.conf.import_encoding
|
|
881
940
|
if not junk_hdrs:
|
|
882
941
|
junk_hdrs = 0
|
|
883
942
|
else:
|
|
884
943
|
junk_hdrs = int(junk_hdrs)
|
|
885
944
|
comment = kwargs["comment"]
|
|
886
945
|
outfile = kwargs["outfile"]
|
|
887
|
-
if not
|
|
888
|
-
raise
|
|
946
|
+
if not Path(filename).exists():
|
|
947
|
+
raise ErrInfo(
|
|
889
948
|
type="cmd",
|
|
890
949
|
command_text=kwargs["metacommandline"],
|
|
891
950
|
other_msg="Input file does not exist",
|
|
892
951
|
)
|
|
893
|
-
hdrs, data =
|
|
894
|
-
tablespec =
|
|
952
|
+
hdrs, data = xls_data(filename, sheetname, junk_hdrs, enc)
|
|
953
|
+
tablespec = DataTable(hdrs, data)
|
|
895
954
|
sql = tablespec.create_table(_state.dbs.current().type, schemaname, tablename, pretty=True)
|
|
896
955
|
if outfile:
|
|
897
956
|
if comment:
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
957
|
+
filewriter_write(outfile, f"-- {comment}\n")
|
|
958
|
+
filewriter_write(outfile, sql)
|
|
959
|
+
filewriter_close(outfile)
|
|
901
960
|
else:
|
|
902
961
|
if comment:
|
|
903
962
|
_state.output.write(f"-- {comment}\n")
|
|
@@ -911,7 +970,7 @@ def x_write_create_table_alias(**kwargs: Any) -> None:
|
|
|
911
970
|
comment = kwargs["comment"]
|
|
912
971
|
outfile = kwargs["filename"]
|
|
913
972
|
if alias not in _state.dbs.aliases():
|
|
914
|
-
raise
|
|
973
|
+
raise ErrInfo(
|
|
915
974
|
type="cmd",
|
|
916
975
|
command_text=kwargs["metacommandline"],
|
|
917
976
|
other_msg=f"Unrecognized database alias: {alias}.",
|
|
@@ -920,27 +979,27 @@ def x_write_create_table_alias(**kwargs: Any) -> None:
|
|
|
920
979
|
tbl = db.schema_qualified_table_name(schema, table)
|
|
921
980
|
try:
|
|
922
981
|
if not db.table_exists(table, schema):
|
|
923
|
-
raise
|
|
982
|
+
raise ErrInfo(
|
|
924
983
|
type="cmd",
|
|
925
984
|
command_text=kwargs["metacommandline"],
|
|
926
985
|
other_msg=f"Table {tbl} does not exist",
|
|
927
986
|
)
|
|
928
987
|
except Exception:
|
|
929
|
-
pass
|
|
988
|
+
pass # Best-effort check; some adapters lack information_schema.
|
|
930
989
|
select_stmt = f"select * from {tbl};"
|
|
931
990
|
try:
|
|
932
991
|
hdrs, rows = db.select_rowsource(select_stmt)
|
|
933
|
-
except
|
|
992
|
+
except ErrInfo:
|
|
934
993
|
raise
|
|
935
994
|
except Exception:
|
|
936
|
-
raise
|
|
937
|
-
tablespec =
|
|
995
|
+
raise ErrInfo("db", select_stmt, exception_msg=exception_desc())
|
|
996
|
+
tablespec = DataTable(hdrs, rows)
|
|
938
997
|
sql = tablespec.create_table(_state.dbs.current().type, kwargs["schema1"], kwargs["table1"], pretty=True)
|
|
939
998
|
if outfile:
|
|
940
999
|
if comment:
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1000
|
+
filewriter_write(outfile, f"-- {comment}\n")
|
|
1001
|
+
filewriter_write(outfile, sql)
|
|
1002
|
+
filewriter_close(outfile)
|
|
944
1003
|
else:
|
|
945
1004
|
if comment:
|
|
946
1005
|
_state.output.write(f"-- {comment}\n")
|
|
@@ -974,12 +1033,12 @@ def x_writescript(**kwargs: Any) -> None:
|
|
|
974
1033
|
if output_dest is None or output_dest == "stdout":
|
|
975
1034
|
_state.output.write(txt)
|
|
976
1035
|
else:
|
|
977
|
-
|
|
1036
|
+
filewriter_write(output_dest, txt)
|
|
978
1037
|
|
|
979
1038
|
if output_dest is not None and output_dest != "stdout":
|
|
980
|
-
|
|
1039
|
+
check_dir(output_dest)
|
|
981
1040
|
if not append:
|
|
982
|
-
|
|
1041
|
+
filewriter_open_as_new(output_dest)
|
|
983
1042
|
script = _state.savedscripts[script_id]
|
|
984
1043
|
if script.paramnames is not None and len(script.paramnames) > 0:
|
|
985
1044
|
write(f"BEGIN SCRIPT {script_id} ({', '.join(script.paramnames)})\n")
|
|
@@ -994,15 +1053,15 @@ def x_writescript(**kwargs: Any) -> None:
|
|
|
994
1053
|
def x_include(**kwargs: Any) -> None:
|
|
995
1054
|
filename = kwargs["filename"]
|
|
996
1055
|
if len(filename) > 1 and filename[0] == "~" and filename[1] == os.sep:
|
|
997
|
-
filename =
|
|
1056
|
+
filename = str(Path.home() / filename[2:])
|
|
998
1057
|
exists = kwargs["exists"]
|
|
999
1058
|
if exists is not None:
|
|
1000
|
-
if
|
|
1001
|
-
|
|
1059
|
+
if Path(filename).is_file():
|
|
1060
|
+
read_sqlfile(filename)
|
|
1002
1061
|
else:
|
|
1003
|
-
if not
|
|
1004
|
-
raise
|
|
1005
|
-
|
|
1062
|
+
if not Path(filename).is_file():
|
|
1063
|
+
raise ErrInfo(type="error", other_msg=f"File {filename} does not exist.")
|
|
1064
|
+
read_sqlfile(filename)
|
|
1006
1065
|
return None
|
|
1007
1066
|
|
|
1008
1067
|
|
|
@@ -1016,13 +1075,13 @@ def x_copy(**kwargs: Any) -> None:
|
|
|
1016
1075
|
schema2 = kwargs["schema2"]
|
|
1017
1076
|
table2 = kwargs["table2"]
|
|
1018
1077
|
if alias1 not in _state.dbs.aliases():
|
|
1019
|
-
raise
|
|
1078
|
+
raise ErrInfo(
|
|
1020
1079
|
type="cmd",
|
|
1021
1080
|
command_text=kwargs["metacommandline"],
|
|
1022
1081
|
other_msg=f"Unrecognized database alias: {alias1}.",
|
|
1023
1082
|
)
|
|
1024
1083
|
if alias2 not in _state.dbs.aliases():
|
|
1025
|
-
raise
|
|
1084
|
+
raise ErrInfo(
|
|
1026
1085
|
type="cmd",
|
|
1027
1086
|
command_text=kwargs["metacommandline"],
|
|
1028
1087
|
other_msg=f"Unrecognized database alias: {alias2}.",
|
|
@@ -1033,29 +1092,29 @@ def x_copy(**kwargs: Any) -> None:
|
|
|
1033
1092
|
tbl2 = db2.schema_qualified_table_name(schema2, table2)
|
|
1034
1093
|
try:
|
|
1035
1094
|
if not db1.table_exists(table1, schema1):
|
|
1036
|
-
raise
|
|
1095
|
+
raise ErrInfo(
|
|
1037
1096
|
type="cmd",
|
|
1038
1097
|
command_text=kwargs["metacommandline"],
|
|
1039
1098
|
other_msg=f"Table {tbl1} does not exist",
|
|
1040
1099
|
)
|
|
1041
1100
|
except Exception:
|
|
1042
|
-
pass
|
|
1101
|
+
pass # Best-effort check; some adapters lack information_schema.
|
|
1043
1102
|
if new_tbl2 and new_tbl2 == "new":
|
|
1044
1103
|
try:
|
|
1045
1104
|
if db2.table_exists(table2, schema2):
|
|
1046
|
-
raise
|
|
1105
|
+
raise ErrInfo(
|
|
1047
1106
|
type="cmd",
|
|
1048
1107
|
command_text=kwargs["metacommandline"],
|
|
1049
1108
|
other_msg=f"Table {tbl2} already exists",
|
|
1050
1109
|
)
|
|
1051
1110
|
except Exception:
|
|
1052
|
-
pass
|
|
1111
|
+
pass # Best-effort check; some adapters lack information_schema.
|
|
1053
1112
|
select_stmt = f"select * from {tbl1};"
|
|
1054
1113
|
|
|
1055
|
-
def get_ts() ->
|
|
1114
|
+
def get_ts() -> DataTable:
|
|
1056
1115
|
if get_ts.tablespec is None:
|
|
1057
1116
|
hdrs, rows = db1.select_rowsource(select_stmt)
|
|
1058
|
-
get_ts.tablespec =
|
|
1117
|
+
get_ts.tablespec = DataTable(hdrs, rows)
|
|
1059
1118
|
return get_ts.tablespec
|
|
1060
1119
|
|
|
1061
1120
|
get_ts.tablespec = None
|
|
@@ -1069,21 +1128,21 @@ def x_copy(**kwargs: Any) -> None:
|
|
|
1069
1128
|
except Exception:
|
|
1070
1129
|
_state.exec_log.log_status_info(f"Could not drop existing table ({tbl2}) for COPY metacommand")
|
|
1071
1130
|
db2.execute(create_tbl)
|
|
1072
|
-
if db2.type ==
|
|
1131
|
+
if db2.type == dbt_firebird:
|
|
1073
1132
|
db2.execute("COMMIT;")
|
|
1074
1133
|
try:
|
|
1075
1134
|
hdrs, rows = db1.select_rowsource(select_stmt)
|
|
1076
|
-
except
|
|
1135
|
+
except ErrInfo:
|
|
1077
1136
|
raise
|
|
1078
1137
|
except Exception:
|
|
1079
|
-
raise
|
|
1138
|
+
raise ErrInfo("db", select_stmt, exception_msg=exception_desc())
|
|
1080
1139
|
try:
|
|
1081
1140
|
db2.populate_table(schema2, table2, rows, hdrs, get_ts)
|
|
1082
1141
|
db2.commit()
|
|
1083
|
-
except
|
|
1142
|
+
except ErrInfo:
|
|
1084
1143
|
raise
|
|
1085
1144
|
except Exception:
|
|
1086
|
-
raise
|
|
1145
|
+
raise ErrInfo("db", select_stmt, exception_msg=exception_desc())
|
|
1087
1146
|
|
|
1088
1147
|
|
|
1089
1148
|
def x_copy_query(**kwargs: Any) -> None:
|
|
@@ -1095,13 +1154,13 @@ def x_copy_query(**kwargs: Any) -> None:
|
|
|
1095
1154
|
schema2 = kwargs["schema"]
|
|
1096
1155
|
table2 = kwargs["table"]
|
|
1097
1156
|
if alias1 not in _state.dbs.aliases():
|
|
1098
|
-
raise
|
|
1157
|
+
raise ErrInfo(
|
|
1099
1158
|
type="cmd",
|
|
1100
1159
|
command_text=kwargs["metacommandline"],
|
|
1101
1160
|
other_msg=f"Unrecognized database alias: {alias1}.",
|
|
1102
1161
|
)
|
|
1103
1162
|
if alias2 not in _state.dbs.aliases():
|
|
1104
|
-
raise
|
|
1163
|
+
raise ErrInfo(
|
|
1105
1164
|
type="cmd",
|
|
1106
1165
|
command_text=kwargs["metacommandline"],
|
|
1107
1166
|
other_msg=f"Unrecognized database alias: {alias2}.",
|
|
@@ -1112,18 +1171,18 @@ def x_copy_query(**kwargs: Any) -> None:
|
|
|
1112
1171
|
if new_tbl2 and new_tbl2 == "new":
|
|
1113
1172
|
try:
|
|
1114
1173
|
if db2.table_exists(table2, schema2):
|
|
1115
|
-
raise
|
|
1174
|
+
raise ErrInfo(
|
|
1116
1175
|
type="cmd",
|
|
1117
1176
|
command_text=kwargs["metacommandline"],
|
|
1118
1177
|
other_msg=f"Table {tbl2} already exists",
|
|
1119
1178
|
)
|
|
1120
1179
|
except Exception:
|
|
1121
|
-
pass
|
|
1180
|
+
pass # Best-effort check; some adapters lack information_schema.
|
|
1122
1181
|
|
|
1123
|
-
def get_ts() ->
|
|
1182
|
+
def get_ts() -> DataTable:
|
|
1124
1183
|
if not get_ts.tablespec:
|
|
1125
1184
|
hdrs, rows = db1.select_rowsource(select_stmt)
|
|
1126
|
-
get_ts.tablespec =
|
|
1185
|
+
get_ts.tablespec = DataTable(hdrs, rows)
|
|
1127
1186
|
return get_ts.tablespec
|
|
1128
1187
|
|
|
1129
1188
|
get_ts.tablespec = None
|
|
@@ -1131,11 +1190,11 @@ def x_copy_query(**kwargs: Any) -> None:
|
|
|
1131
1190
|
if new_tbl2:
|
|
1132
1191
|
try:
|
|
1133
1192
|
hdrs, rows = db1.select_rowsource(select_stmt)
|
|
1134
|
-
except
|
|
1193
|
+
except ErrInfo:
|
|
1135
1194
|
raise
|
|
1136
1195
|
except Exception:
|
|
1137
|
-
raise
|
|
1138
|
-
get_ts.tablespec =
|
|
1196
|
+
raise ErrInfo("db", select_stmt, exception_msg=exception_desc())
|
|
1197
|
+
get_ts.tablespec = DataTable(hdrs, rows)
|
|
1139
1198
|
tbl_desc = get_ts.tablespec
|
|
1140
1199
|
create_tbl = tbl_desc.create_table(db2.type, schema2, table2)
|
|
1141
1200
|
if new_tbl2 == "replacement":
|
|
@@ -1144,21 +1203,21 @@ def x_copy_query(**kwargs: Any) -> None:
|
|
|
1144
1203
|
except Exception:
|
|
1145
1204
|
_state.exec_log.log_status_info(f"Could not drop existing table ({tbl2}) for COPY metacommand")
|
|
1146
1205
|
db2.execute(create_tbl)
|
|
1147
|
-
if db2.type ==
|
|
1206
|
+
if db2.type == dbt_firebird:
|
|
1148
1207
|
db2.execute("COMMIT;")
|
|
1149
1208
|
try:
|
|
1150
1209
|
hdrs, rows = db1.select_rowsource(select_stmt)
|
|
1151
|
-
except
|
|
1210
|
+
except ErrInfo:
|
|
1152
1211
|
raise
|
|
1153
1212
|
except Exception:
|
|
1154
|
-
raise
|
|
1213
|
+
raise ErrInfo("db", select_stmt, exception_msg=exception_desc())
|
|
1155
1214
|
try:
|
|
1156
1215
|
db2.populate_table(schema2, table2, rows, hdrs, get_ts)
|
|
1157
1216
|
db2.commit()
|
|
1158
|
-
except
|
|
1217
|
+
except ErrInfo:
|
|
1159
1218
|
raise
|
|
1160
1219
|
except Exception:
|
|
1161
|
-
raise
|
|
1220
|
+
raise ErrInfo("db", select_stmt, exception_msg=exception_desc())
|
|
1162
1221
|
|
|
1163
1222
|
|
|
1164
1223
|
def x_zip(**kwargs: Any) -> None:
|
|
@@ -1172,7 +1231,7 @@ def x_zip(**kwargs: Any) -> None:
|
|
|
1172
1231
|
zf = _zipfile.ZipFile(zipfile_name, mode=zmode, compression=_zipfile.ZIP_BZIP2, compresslevel=9)
|
|
1173
1232
|
fnlist = _glob.glob(files)
|
|
1174
1233
|
for f in fnlist:
|
|
1175
|
-
if
|
|
1234
|
+
if Path(f).is_file():
|
|
1176
1235
|
zf.write(f)
|
|
1177
1236
|
zf.close()
|
|
1178
1237
|
|
|
@@ -1188,8 +1247,8 @@ def x_rm_file(**kwargs: Any) -> None:
|
|
|
1188
1247
|
fn = kwargs["filename"].strip(' "')
|
|
1189
1248
|
fnlist = _glob.glob(fn)
|
|
1190
1249
|
for f in fnlist:
|
|
1191
|
-
if
|
|
1192
|
-
|
|
1250
|
+
if Path(f).is_file():
|
|
1251
|
+
filewriter_close(f)
|
|
1193
1252
|
os.unlink(f)
|
|
1194
1253
|
|
|
1195
1254
|
|
|
@@ -1199,15 +1258,15 @@ def x_make_export_dirs(**kwargs: Any) -> None:
|
|
|
1199
1258
|
|
|
1200
1259
|
|
|
1201
1260
|
def x_cd(**kwargs: Any) -> None:
|
|
1202
|
-
new_dir =
|
|
1203
|
-
if not
|
|
1204
|
-
raise
|
|
1261
|
+
new_dir = unquoted(kwargs["dir"])
|
|
1262
|
+
if not Path(new_dir).is_dir():
|
|
1263
|
+
raise ErrInfo(
|
|
1205
1264
|
type="cmd",
|
|
1206
1265
|
command_text=kwargs["metacommandline"],
|
|
1207
1266
|
other_msg="Directory does not exist",
|
|
1208
1267
|
)
|
|
1209
1268
|
os.chdir(new_dir)
|
|
1210
|
-
script, lno =
|
|
1269
|
+
script, lno = current_script_line()
|
|
1211
1270
|
_state.exec_log.log_status_info(f"Current directory changed to {new_dir} at line {lno} of {script}")
|
|
1212
1271
|
return None
|
|
1213
1272
|
|
|
@@ -1223,13 +1282,13 @@ def x_hdf5_text_len(**kwargs: Any) -> None:
|
|
|
1223
1282
|
def x_serve(**kwargs: Any) -> None:
|
|
1224
1283
|
infname = kwargs["filename"]
|
|
1225
1284
|
fmt = kwargs["format"].lower()
|
|
1226
|
-
if not
|
|
1227
|
-
raise
|
|
1285
|
+
if not Path(infname).is_file():
|
|
1286
|
+
raise ErrInfo(
|
|
1228
1287
|
type="cmd",
|
|
1229
1288
|
command_text=kwargs["metacommandline"],
|
|
1230
1289
|
other_msg=f"Input file {infname} does not exist",
|
|
1231
1290
|
)
|
|
1232
|
-
fname =
|
|
1291
|
+
fname = Path(infname).name
|
|
1233
1292
|
if fmt == "binary":
|
|
1234
1293
|
contenttype = "application/octet-stream"
|
|
1235
1294
|
elif fmt == "csv":
|