execsql2 2.4.4__py3-none-any.whl → 2.5.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 +14 -0
- execsql/cli/dsn.py +2 -0
- execsql/cli/help.py +2 -0
- execsql/cli/run.py +4 -2
- execsql/constants.py +11 -0
- execsql/db/access.py +20 -0
- execsql/db/base.py +4 -0
- execsql/db/dsn.py +11 -8
- execsql/db/duckdb.py +12 -8
- execsql/db/firebird.py +17 -8
- execsql/db/mysql.py +13 -8
- execsql/db/oracle.py +22 -8
- execsql/db/postgres.py +21 -9
- execsql/db/sqlite.py +18 -8
- execsql/db/sqlserver.py +14 -8
- execsql/exporters/__init__.py +6 -1
- execsql/exporters/base.py +2 -0
- execsql/exporters/delimited.py +10 -0
- execsql/exporters/protocol.py +128 -0
- execsql/exporters/xls.py +8 -0
- execsql/format.py +3 -1
- execsql/gui/__init__.py +2 -0
- execsql/gui/base.py +2 -0
- execsql/gui/console.py +2 -0
- execsql/gui/desktop.py +1 -0
- execsql/gui/tui.py +2 -0
- execsql/importers/base.py +1 -0
- execsql/importers/csv.py +2 -0
- execsql/importers/feather.py +2 -0
- execsql/importers/ods.py +1 -0
- execsql/importers/xls.py +1 -0
- execsql/metacommands/__init__.py +206 -0
- execsql/metacommands/dispatch.py +93 -2
- execsql/metacommands/io.py +41 -0
- execsql/models.py +17 -0
- execsql/parser.py +41 -0
- execsql/script/control.py +2 -0
- execsql/script/engine.py +19 -0
- execsql/script/variables.py +9 -5
- execsql/state.py +52 -0
- execsql/types.py +46 -0
- {execsql2-2.4.4.dist-info → execsql2-2.5.0.dist-info}/METADATA +31 -4
- {execsql2-2.4.4.dist-info → execsql2-2.5.0.dist-info}/RECORD +62 -61
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/README.md +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/config_settings.sqlite +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/execsql.conf +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/make_config_db.sql +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/md_compare.sql +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/md_glossary.sql +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/md_upsert.sql +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/pg_compare.sql +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/pg_glossary.sql +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/pg_upsert.sql +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/script_template.sql +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/ss_compare.sql +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/ss_glossary.sql +0 -0
- {execsql2-2.4.4.data → execsql2-2.5.0.data}/data/execsql2_extras/ss_upsert.sql +0 -0
- {execsql2-2.4.4.dist-info → execsql2-2.5.0.dist-info}/WHEEL +0 -0
- {execsql2-2.4.4.dist-info → execsql2-2.5.0.dist-info}/entry_points.txt +0 -0
- {execsql2-2.4.4.dist-info → execsql2-2.5.0.dist-info}/licenses/LICENSE.txt +0 -0
- {execsql2-2.4.4.dist-info → execsql2-2.5.0.dist-info}/licenses/NOTICE +0 -0
execsql/metacommands/__init__.py
CHANGED
|
@@ -212,6 +212,212 @@ from execsql.utils.regex import (
|
|
|
212
212
|
)
|
|
213
213
|
from execsql.script import MetaCommandList # noqa: F401
|
|
214
214
|
|
|
215
|
+
__all__ = [
|
|
216
|
+
# execsql.state
|
|
217
|
+
"_state",
|
|
218
|
+
# connect handlers
|
|
219
|
+
"x_connect_pg",
|
|
220
|
+
"x_connect_user_pg",
|
|
221
|
+
"x_connect_ssvr",
|
|
222
|
+
"x_connect_user_ssvr",
|
|
223
|
+
"x_connect_mysql",
|
|
224
|
+
"x_connect_user_mysql",
|
|
225
|
+
"x_connect_access",
|
|
226
|
+
"x_connect_fb",
|
|
227
|
+
"x_connect_user_fb",
|
|
228
|
+
"x_connect_ora",
|
|
229
|
+
"x_connect_user_ora",
|
|
230
|
+
"x_connect_duckdb",
|
|
231
|
+
"x_connect_sqlite",
|
|
232
|
+
"x_connect_dsn",
|
|
233
|
+
"x_use",
|
|
234
|
+
"x_disconnect",
|
|
235
|
+
"x_autocommit_on",
|
|
236
|
+
"x_autocommit_off",
|
|
237
|
+
"x_pg_vacuum",
|
|
238
|
+
"x_daoflushdelay",
|
|
239
|
+
# control handlers
|
|
240
|
+
"x_if",
|
|
241
|
+
"x_if_orif",
|
|
242
|
+
"x_if_andif",
|
|
243
|
+
"x_if_elseif",
|
|
244
|
+
"x_if_else",
|
|
245
|
+
"x_if_block",
|
|
246
|
+
"x_if_end",
|
|
247
|
+
"x_loop",
|
|
248
|
+
"x_halt",
|
|
249
|
+
"x_halt_msg",
|
|
250
|
+
"x_error_halt",
|
|
251
|
+
"x_metacommand_error_halt",
|
|
252
|
+
"x_begin_batch",
|
|
253
|
+
"x_end_batch",
|
|
254
|
+
"x_rollback",
|
|
255
|
+
"x_break",
|
|
256
|
+
"x_wait_until",
|
|
257
|
+
# data handlers
|
|
258
|
+
"x_sub",
|
|
259
|
+
"x_sub_add",
|
|
260
|
+
"x_sub_append",
|
|
261
|
+
"x_sub_empty",
|
|
262
|
+
"x_rm_sub",
|
|
263
|
+
"x_sub_local",
|
|
264
|
+
"x_sub_tempfile",
|
|
265
|
+
"x_sub_ini",
|
|
266
|
+
"x_sub_querystring",
|
|
267
|
+
"x_sub_encrypt",
|
|
268
|
+
"x_sub_decrypt",
|
|
269
|
+
"x_subdata",
|
|
270
|
+
"x_selectsub",
|
|
271
|
+
"x_prompt_selectsub",
|
|
272
|
+
"x_empty_strings",
|
|
273
|
+
"x_trim_strings",
|
|
274
|
+
"x_replace_newlines",
|
|
275
|
+
"x_empty_rows",
|
|
276
|
+
"x_only_strings",
|
|
277
|
+
"x_boolean_int",
|
|
278
|
+
"x_boolean_words",
|
|
279
|
+
"x_fold_col_hdrs",
|
|
280
|
+
"x_trim_col_hdrs",
|
|
281
|
+
"x_clean_col_hdrs",
|
|
282
|
+
"x_del_empty_cols",
|
|
283
|
+
"x_create_col_hdrs",
|
|
284
|
+
"x_dedup_col_hdrs",
|
|
285
|
+
"x_import_common_cols_only",
|
|
286
|
+
"x_quote_all_text",
|
|
287
|
+
"x_reset_counter",
|
|
288
|
+
"x_reset_counters",
|
|
289
|
+
"x_set_counter",
|
|
290
|
+
"x_max_int",
|
|
291
|
+
# debug handlers
|
|
292
|
+
"x_debug_write_metacommands",
|
|
293
|
+
"x_debug_commandliststack",
|
|
294
|
+
"x_debug_iflevels",
|
|
295
|
+
"x_debug_write_odbc_drivers",
|
|
296
|
+
"x_debug_log_subvars",
|
|
297
|
+
"x_debug_log_config",
|
|
298
|
+
"x_debug_write_subvars",
|
|
299
|
+
"x_debug_write_config",
|
|
300
|
+
# io handlers
|
|
301
|
+
"x_export",
|
|
302
|
+
"x_export_query",
|
|
303
|
+
"x_export_query_with_template",
|
|
304
|
+
"x_export_with_template",
|
|
305
|
+
"x_export_ods_multiple",
|
|
306
|
+
"x_export_metadata",
|
|
307
|
+
"x_export_metadata_table",
|
|
308
|
+
"x_import",
|
|
309
|
+
"x_import_file",
|
|
310
|
+
"x_import_ods",
|
|
311
|
+
"x_import_ods_pattern",
|
|
312
|
+
"x_import_xls",
|
|
313
|
+
"x_import_xls_pattern",
|
|
314
|
+
"x_import_parquet",
|
|
315
|
+
"x_import_feather",
|
|
316
|
+
"x_import_row_buffer",
|
|
317
|
+
"x_show_progress",
|
|
318
|
+
"x_export_row_buffer",
|
|
319
|
+
"x_write",
|
|
320
|
+
"x_write_create_table",
|
|
321
|
+
"x_write_create_table_ods",
|
|
322
|
+
"x_write_create_table_xls",
|
|
323
|
+
"x_write_create_table_alias",
|
|
324
|
+
"x_write_prefix",
|
|
325
|
+
"x_write_suffix",
|
|
326
|
+
"x_writescript",
|
|
327
|
+
"x_include",
|
|
328
|
+
"x_copy",
|
|
329
|
+
"x_copy_query",
|
|
330
|
+
"x_zip",
|
|
331
|
+
"x_zip_buffer_mb",
|
|
332
|
+
"x_rm_file",
|
|
333
|
+
"x_make_export_dirs",
|
|
334
|
+
"x_cd",
|
|
335
|
+
"x_scan_lines",
|
|
336
|
+
"x_hdf5_text_len",
|
|
337
|
+
"x_serve",
|
|
338
|
+
# prompt handlers
|
|
339
|
+
"x_prompt",
|
|
340
|
+
"x_prompt_enter",
|
|
341
|
+
"x_prompt_entryform",
|
|
342
|
+
"x_prompt_pause",
|
|
343
|
+
"x_prompt_compare",
|
|
344
|
+
"x_prompt_ask_compare",
|
|
345
|
+
"x_prompt_ask",
|
|
346
|
+
"x_prompt_map",
|
|
347
|
+
"x_prompt_action",
|
|
348
|
+
"x_prompt_savefile",
|
|
349
|
+
"x_prompt_openfile",
|
|
350
|
+
"x_prompt_directory",
|
|
351
|
+
"x_prompt_select_rows",
|
|
352
|
+
"x_prompt_credentials",
|
|
353
|
+
"x_prompt_connect",
|
|
354
|
+
"x_ask",
|
|
355
|
+
"x_pause",
|
|
356
|
+
"x_msg",
|
|
357
|
+
"x_reset_dialog_canceled",
|
|
358
|
+
# script_ext handlers
|
|
359
|
+
"x_extendscript",
|
|
360
|
+
"x_extendscript_metacommand",
|
|
361
|
+
"x_extendscript_sql",
|
|
362
|
+
"x_executescript",
|
|
363
|
+
# system handlers
|
|
364
|
+
"x_system_cmd",
|
|
365
|
+
"x_email",
|
|
366
|
+
"x_timer",
|
|
367
|
+
"x_log",
|
|
368
|
+
"x_logwritemessages",
|
|
369
|
+
"x_log_datavars",
|
|
370
|
+
"x_log_sql",
|
|
371
|
+
"x_console",
|
|
372
|
+
"x_consoleprogress",
|
|
373
|
+
"x_consolewait",
|
|
374
|
+
"x_consolewait_onerror",
|
|
375
|
+
"x_consolewait_whendone",
|
|
376
|
+
"x_console_hideshow",
|
|
377
|
+
"x_consolewidth",
|
|
378
|
+
"x_consoleheight",
|
|
379
|
+
"x_consolestatus",
|
|
380
|
+
"x_consolesave",
|
|
381
|
+
"x_cancel_halt",
|
|
382
|
+
"x_cancel_halt_write_clear",
|
|
383
|
+
"x_cancel_halt_write",
|
|
384
|
+
"x_cancel_halt_email_clear",
|
|
385
|
+
"x_cancel_halt_email",
|
|
386
|
+
"x_cancel_halt_exec",
|
|
387
|
+
"x_cancel_halt_exec_clear",
|
|
388
|
+
"x_error_halt_write_clear",
|
|
389
|
+
"x_error_halt_write",
|
|
390
|
+
"x_error_halt_email_clear",
|
|
391
|
+
"x_error_halt_email",
|
|
392
|
+
"x_error_halt_exec",
|
|
393
|
+
"x_error_halt_exec_clear",
|
|
394
|
+
"x_write_warnings",
|
|
395
|
+
"x_gui_level",
|
|
396
|
+
"x_execute",
|
|
397
|
+
# regex helpers
|
|
398
|
+
"ins_rxs",
|
|
399
|
+
"ins_quoted_rx",
|
|
400
|
+
"ins_schema_rxs",
|
|
401
|
+
"ins_table_rxs",
|
|
402
|
+
"ins_table_list_rxs",
|
|
403
|
+
"ins_fn_rxs",
|
|
404
|
+
# MetaCommandList
|
|
405
|
+
"MetaCommandList",
|
|
406
|
+
# format constants
|
|
407
|
+
"DELIMITED_FORMATS",
|
|
408
|
+
"TEXT_FORMATS",
|
|
409
|
+
"JSON_VARIANT_FORMATS",
|
|
410
|
+
"QUERY_EXPORT_FORMATS",
|
|
411
|
+
"TABLE_EXPORT_FORMATS",
|
|
412
|
+
"SERVE_FORMATS",
|
|
413
|
+
"METADATA_FORMATS",
|
|
414
|
+
"ALL_EXPORT_FORMATS",
|
|
415
|
+
"DATABASE_TYPES",
|
|
416
|
+
# dispatch
|
|
417
|
+
"build_dispatch_table",
|
|
418
|
+
"DISPATCH_TABLE",
|
|
419
|
+
]
|
|
420
|
+
|
|
215
421
|
# ---------------------------------------------------------------------------
|
|
216
422
|
# Export format constants — single source of truth.
|
|
217
423
|
# Used in dispatch table regex patterns and by io_export.py for validation.
|
execsql/metacommands/dispatch.py
CHANGED
|
@@ -169,6 +169,7 @@ from execsql.metacommands.system import (
|
|
|
169
169
|
x_cancel_halt,
|
|
170
170
|
x_cancel_halt_email,
|
|
171
171
|
x_cancel_halt_email_clear,
|
|
172
|
+
x_cancel_halt_exec,
|
|
172
173
|
x_cancel_halt_exec_clear,
|
|
173
174
|
x_cancel_halt_write,
|
|
174
175
|
x_cancel_halt_write_clear,
|
|
@@ -185,6 +186,7 @@ from execsql.metacommands.system import (
|
|
|
185
186
|
x_email,
|
|
186
187
|
x_error_halt_email,
|
|
187
188
|
x_error_halt_email_clear,
|
|
189
|
+
x_error_halt_exec,
|
|
188
190
|
x_error_halt_exec_clear,
|
|
189
191
|
x_error_halt_write,
|
|
190
192
|
x_error_halt_write_clear,
|
|
@@ -219,6 +221,8 @@ from execsql.metacommands import (
|
|
|
219
221
|
TABLE_EXPORT_FORMATS,
|
|
220
222
|
)
|
|
221
223
|
|
|
224
|
+
__all__ = ["build_dispatch_table"]
|
|
225
|
+
|
|
222
226
|
|
|
223
227
|
def build_dispatch_table() -> MetaCommandList:
|
|
224
228
|
"""Construct and return the complete metacommand dispatch table."""
|
|
@@ -1030,6 +1034,10 @@ def build_dispatch_table() -> MetaCommandList:
|
|
|
1030
1034
|
x_error_halt_email,
|
|
1031
1035
|
)
|
|
1032
1036
|
mcl.add(r"^\s*ON\s+ERROR_HALT\s+EXEC\s+CLEAR\s*$", x_error_halt_exec_clear)
|
|
1037
|
+
mcl.add(
|
|
1038
|
+
r'^\s*ON\s+ERROR_HALT\s+EXEC(?:UTE)?\s+SCRIPT(?:\s+(?P<exists>IF\s+EXISTS))?\s+(?P<script_id>\w+)(?:(?:\s+WITH)?(?:\s+ARG(?:UMENT)?S?)?\s*\(\s*(?P<argexp>#?\w+\s*=\s*(?:(?:[^"\'\[][^,\)]*)|(?:"[^"]*")|(?:\'[^\']*\')|(?:\[[^\]]*\]))(?:\s*,\s*#?\w+\s*=\s*(?:(?:[^"\'\[][^,\)]*)|(?:"[^"]*")|(?:\'[^\']*\')|(?:\[[^\]]*\])))*)\s*\))?(?:\s+(?P<looptype>WHILE|UNTIL)\s*\(\s*(?P<loopcond>.+)\s*\))?\s*$',
|
|
1039
|
+
x_error_halt_exec,
|
|
1040
|
+
)
|
|
1033
1041
|
mcl.add(
|
|
1034
1042
|
r"^\s*ON\s+CANCEL_HALT\s+WRITE\s+CLEAR\s*$",
|
|
1035
1043
|
x_cancel_halt_write_clear,
|
|
@@ -1077,6 +1085,10 @@ def build_dispatch_table() -> MetaCommandList:
|
|
|
1077
1085
|
x_cancel_halt_email,
|
|
1078
1086
|
)
|
|
1079
1087
|
mcl.add(r"^\s*ON\s+CANCEL_HALT\s+EXEC\s+CLEAR\s*$", x_cancel_halt_exec_clear)
|
|
1088
|
+
mcl.add(
|
|
1089
|
+
r'^\s*ON\s+CANCEL_HALT\s+EXEC(?:UTE)?\s+SCRIPT(?:\s+(?P<exists>IF\s+EXISTS))?\s+(?P<script_id>\w+)(?:(?:\s+WITH)?(?:\s+ARG(?:UMENT)?S?)?\s*\(\s*(?P<argexp>#?\w+\s*=\s*(?:(?:[^"\'\[][^,\)]*)|(?:"[^"]*")|(?:\'[^\']*\')|(?:\[[^\]]*\]))(?:\s*,\s*#?\w+\s*=\s*(?:(?:[^"\'\[][^,\)]*)|(?:"[^"]*")|(?:\'[^\']*\')|(?:\[[^\]]*\])))*)\s*\))?(?:\s+(?P<looptype>WHILE|UNTIL)\s*\(\s*(?P<loopcond>.+)\s*\))?\s*$',
|
|
1090
|
+
x_cancel_halt_exec,
|
|
1091
|
+
)
|
|
1080
1092
|
|
|
1081
1093
|
# ------------------------------------------------------------------
|
|
1082
1094
|
# SUB_TEMPFILE
|
|
@@ -1680,16 +1692,54 @@ def build_dispatch_table() -> MetaCommandList:
|
|
|
1680
1692
|
)
|
|
1681
1693
|
mcl.add(
|
|
1682
1694
|
(
|
|
1695
|
+
# SERVER unquoted, DB unquoted, PASSWORD unquoted
|
|
1683
1696
|
r"^CONNECT\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\/\\\-\.]*)\s*,\s*"
|
|
1684
1697
|
r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_~`!@#$%^&\*\+=\/\?\.-]*)"
|
|
1685
1698
|
r"\s*,\s*NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
|
|
1686
1699
|
r"(?:\s*,\s+PASSWORD\s*=\s*(?P<password>[^\s\)]+))?"
|
|
1687
1700
|
r"(?:\s*,\s*ENCODING\s*=\s*(?P<encoding>[A-Z][A-Z0-9_-]+))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
|
|
1701
|
+
# SERVER quoted, DB quoted, PASSWORD unquoted
|
|
1688
1702
|
r'^CONNECT\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\/\\\s\-\.]*)"\s*,\s*'
|
|
1689
1703
|
r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\-\s]*)"(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_~`!@#$%^&\*\+=\/\?\.-]*)'
|
|
1690
1704
|
r"\s*,\s*NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
|
|
1691
1705
|
r"(?:\s*,\s+PASSWORD\s*=\s*(?P<password>[^\s\)]+))?"
|
|
1692
1706
|
r"(?:\s*,\s*ENCODING\s*=\s*(?P<encoding>[A-Z][A-Z0-9_-]+))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
|
|
1707
|
+
# SERVER quoted, DB unquoted, PASSWORD unquoted
|
|
1708
|
+
r'^CONNECT\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\/\\\s\-\.]*)"\s*,\s*'
|
|
1709
|
+
r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_~`!@#$%^&\*\+=\/\?\.-]*)"
|
|
1710
|
+
r"\s*,\s*NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
|
|
1711
|
+
r"(?:\s*,\s+PASSWORD\s*=\s*(?P<password>[^\s\)]+))?"
|
|
1712
|
+
r"(?:\s*,\s*ENCODING\s*=\s*(?P<encoding>[A-Z][A-Z0-9_-]+))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
|
|
1713
|
+
# SERVER unquoted, DB quoted, PASSWORD unquoted
|
|
1714
|
+
r"^CONNECT\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\/\\\-\.]*)\s*,\s*"
|
|
1715
|
+
r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\- ]*)"(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_~`!@#$%^&\*\+=\/\?\.-]*)'
|
|
1716
|
+
r"\s*,\s*NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
|
|
1717
|
+
r"(?:\s*,\s+PASSWORD\s*=\s*(?P<password>[^\s\)]+))?"
|
|
1718
|
+
r"(?:\s*,\s*ENCODING\s*=\s*(?P<encoding>[A-Z][A-Z0-9_-]+))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
|
|
1719
|
+
# SERVER unquoted, DB unquoted, PASSWORD quoted
|
|
1720
|
+
r"^CONNECT\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\/\\\-\.]*)\s*,\s*"
|
|
1721
|
+
r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_~`!@#$%^&\*\+=\/\?\.-]*)"
|
|
1722
|
+
r"\s*,\s*NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
|
|
1723
|
+
r'(?:\s*,\s+PASSWORD\s*=\s*(?P<password>"[^\s\)]+"))?'
|
|
1724
|
+
r"(?:\s*,\s*ENCODING\s*=\s*(?P<encoding>[A-Z][A-Z0-9_-]+))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
|
|
1725
|
+
# SERVER quoted, DB quoted, PASSWORD quoted
|
|
1726
|
+
r'^CONNECT\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\/\\\s\-\.]*)"\s*,\s*'
|
|
1727
|
+
r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\-\s]*)"(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_~`!@#$%^&\*\+=\/\?\.-]*)'
|
|
1728
|
+
r"\s*,\s*NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
|
|
1729
|
+
r'(?:\s*,\s+PASSWORD\s*=\s*(?P<password>"[^\s\)]+"))?'
|
|
1730
|
+
r"(?:\s*,\s*ENCODING\s*=\s*(?P<encoding>[A-Z][A-Z0-9_-]+))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
|
|
1731
|
+
# SERVER quoted, DB unquoted, PASSWORD quoted
|
|
1732
|
+
r'^CONNECT\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\/\\\s\-\.]*)"\s*,\s*'
|
|
1733
|
+
r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_~`!@#$%^&\*\+=\/\?\.-]*)"
|
|
1734
|
+
r"\s*,\s*NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
|
|
1735
|
+
r'(?:\s*,\s+PASSWORD\s*=\s*(?P<password>"[^\s\)]+"))?'
|
|
1736
|
+
r"(?:\s*,\s*ENCODING\s*=\s*(?P<encoding>[A-Z][A-Z0-9_-]+))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
|
|
1737
|
+
# SERVER unquoted, DB quoted, PASSWORD quoted
|
|
1738
|
+
r"^CONNECT\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\/\\\-\.]*)\s*,\s*"
|
|
1739
|
+
r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\- ]*)"(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_~`!@#$%^&\*\+=\/\?\.-]*)'
|
|
1740
|
+
r"\s*,\s*NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
|
|
1741
|
+
r'(?:\s*,\s+PASSWORD\s*=\s*(?P<password>"[^\s\)]+"))?'
|
|
1742
|
+
r"(?:\s*,\s*ENCODING\s*=\s*(?P<encoding>[A-Z][A-Z0-9_-]+))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
|
|
1693
1743
|
),
|
|
1694
1744
|
x_connect_ssvr,
|
|
1695
1745
|
)
|
|
@@ -1722,6 +1772,12 @@ def build_dispatch_table() -> MetaCommandList:
|
|
|
1722
1772
|
# ------------------------------------------------------------------
|
|
1723
1773
|
# APPEND/EXTEND SCRIPT
|
|
1724
1774
|
# ------------------------------------------------------------------
|
|
1775
|
+
mcl.add(
|
|
1776
|
+
r"\s*EXTEND\s+SCRIPT\s+(?P<script2>\w+)\s+WITH\s+SCRIPT\s+(?P<script1>\w+)\s*$",
|
|
1777
|
+
x_extendscript,
|
|
1778
|
+
description="EXTEND SCRIPT",
|
|
1779
|
+
category="action",
|
|
1780
|
+
)
|
|
1725
1781
|
mcl.add(
|
|
1726
1782
|
r"\s*APPEND\s+SCRIPT\s+(?P<script1>\w+)\s+TO\s+(?P<script2>\w+)\s*$",
|
|
1727
1783
|
x_extendscript,
|
|
@@ -1897,13 +1953,48 @@ def build_dispatch_table() -> MetaCommandList:
|
|
|
1897
1953
|
# ------------------------------------------------------------------
|
|
1898
1954
|
mcl.add(
|
|
1899
1955
|
ins_table_rxs(
|
|
1900
|
-
r
|
|
1901
|
-
r
|
|
1956
|
+
r"^\s*PROMPT\s+ASK\s+'(?P<question>[^']+)'\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+",
|
|
1957
|
+
r")?(?:\s+HELP\s+(?P<help>[^\s]+))?\s*$",
|
|
1902
1958
|
),
|
|
1903
1959
|
x_prompt_ask,
|
|
1904
1960
|
description="PROMPT ASK",
|
|
1905
1961
|
category="prompt",
|
|
1906
1962
|
)
|
|
1963
|
+
mcl.add(
|
|
1964
|
+
ins_table_rxs(
|
|
1965
|
+
r"^\s*PROMPT\s+ASK\s+'(?P<question>[^']+)'\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+",
|
|
1966
|
+
r')?(?:\s+HELP\s+"(?P<help>[^"]+)")?\s*$',
|
|
1967
|
+
),
|
|
1968
|
+
x_prompt_ask,
|
|
1969
|
+
)
|
|
1970
|
+
mcl.add(
|
|
1971
|
+
ins_table_rxs(
|
|
1972
|
+
r"^\s*PROMPT\s+ASK\s+\[(?P<question>[^\]]+)\]\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+",
|
|
1973
|
+
r")?(?:\s+HELP\s+(?P<help>[^\s]+))?\s*$",
|
|
1974
|
+
),
|
|
1975
|
+
x_prompt_ask,
|
|
1976
|
+
)
|
|
1977
|
+
mcl.add(
|
|
1978
|
+
ins_table_rxs(
|
|
1979
|
+
r"^\s*PROMPT\s+ASK\s+\[(?P<question>[^\]]+)\]\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+",
|
|
1980
|
+
r')?(?:\s+HELP\s+"(?P<help>[^"]+)")?\s*$',
|
|
1981
|
+
),
|
|
1982
|
+
x_prompt_ask,
|
|
1983
|
+
)
|
|
1984
|
+
mcl.add(
|
|
1985
|
+
ins_table_rxs(
|
|
1986
|
+
r'^\s*PROMPT\s+ASK\s+"(?P<question>[^"]+)"\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+',
|
|
1987
|
+
r")?(?:\s+HELP\s+(?P<help>[^\s]+))?\s*$",
|
|
1988
|
+
),
|
|
1989
|
+
x_prompt_ask,
|
|
1990
|
+
)
|
|
1991
|
+
mcl.add(
|
|
1992
|
+
ins_table_rxs(
|
|
1993
|
+
r'^\s*PROMPT\s+ASK\s+"(?P<question>[^"]+)"\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+',
|
|
1994
|
+
r')?(?:\s+HELP\s+"(?P<help>[^"]+)")?\s*$',
|
|
1995
|
+
),
|
|
1996
|
+
x_prompt_ask,
|
|
1997
|
+
)
|
|
1907
1998
|
|
|
1908
1999
|
# ------------------------------------------------------------------
|
|
1909
2000
|
# PROMPT DISPLAY (table viewer)
|
execsql/metacommands/io.py
CHANGED
|
@@ -68,3 +68,44 @@ from execsql.metacommands.io_fileops import ( # noqa: F401
|
|
|
68
68
|
x_zip,
|
|
69
69
|
x_zip_buffer_mb,
|
|
70
70
|
)
|
|
71
|
+
|
|
72
|
+
__all__ = [
|
|
73
|
+
"_apply_output_dir",
|
|
74
|
+
"x_cd",
|
|
75
|
+
"x_copy",
|
|
76
|
+
"x_copy_query",
|
|
77
|
+
"x_export",
|
|
78
|
+
"x_export_metadata",
|
|
79
|
+
"x_export_metadata_table",
|
|
80
|
+
"x_export_ods_multiple",
|
|
81
|
+
"x_export_query",
|
|
82
|
+
"x_export_query_with_template",
|
|
83
|
+
"x_export_row_buffer",
|
|
84
|
+
"x_export_with_template",
|
|
85
|
+
"x_hdf5_text_len",
|
|
86
|
+
"x_import",
|
|
87
|
+
"x_import_feather",
|
|
88
|
+
"x_import_file",
|
|
89
|
+
"x_import_ods",
|
|
90
|
+
"x_import_ods_pattern",
|
|
91
|
+
"x_import_parquet",
|
|
92
|
+
"x_import_row_buffer",
|
|
93
|
+
"x_import_xls",
|
|
94
|
+
"x_import_xls_pattern",
|
|
95
|
+
"x_include",
|
|
96
|
+
"x_make_export_dirs",
|
|
97
|
+
"x_rm_file",
|
|
98
|
+
"x_scan_lines",
|
|
99
|
+
"x_serve",
|
|
100
|
+
"x_show_progress",
|
|
101
|
+
"x_write",
|
|
102
|
+
"x_write_create_table",
|
|
103
|
+
"x_write_create_table_alias",
|
|
104
|
+
"x_write_create_table_ods",
|
|
105
|
+
"x_write_create_table_xls",
|
|
106
|
+
"x_write_prefix",
|
|
107
|
+
"x_write_suffix",
|
|
108
|
+
"x_writescript",
|
|
109
|
+
"x_zip",
|
|
110
|
+
"x_zip_buffer_mb",
|
|
111
|
+
]
|
execsql/models.py
CHANGED
|
@@ -49,13 +49,18 @@ __all__ = [
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
class Column:
|
|
52
|
+
"""Compile data-type match statistics for a single column of imported data."""
|
|
53
|
+
|
|
52
54
|
# Column objects are used to compile information about the data types that a set of data
|
|
53
55
|
# values may match. A Column object is intended to be used to identify the data type of a column
|
|
54
56
|
# when scanning a data stream (such as a CSV file) to create a new data table.
|
|
55
57
|
|
|
56
58
|
class Accum:
|
|
59
|
+
"""Accumulate match counts and length statistics for a single data type."""
|
|
60
|
+
|
|
57
61
|
# Accumulates the count of matches for each data type, plus the maximum length if appropriate.
|
|
58
62
|
def __init__(self, data_type_obj: DataType) -> None:
|
|
63
|
+
"""Initialise the accumulator for the given data type."""
|
|
59
64
|
self.dt = data_type_obj
|
|
60
65
|
self.failed = False
|
|
61
66
|
self.count = 0
|
|
@@ -72,6 +77,7 @@ class Column:
|
|
|
72
77
|
)
|
|
73
78
|
|
|
74
79
|
def check(self, datavalue: Any) -> None:
|
|
80
|
+
"""Test whether a non-null value matches this data type and update statistics."""
|
|
75
81
|
# datavalue must be non-null
|
|
76
82
|
if not self.failed:
|
|
77
83
|
is_match = self.dt.matches(datavalue)
|
|
@@ -105,6 +111,7 @@ class Column:
|
|
|
105
111
|
self.failed = True
|
|
106
112
|
|
|
107
113
|
def __init__(self, colname: str) -> None:
|
|
114
|
+
"""Create a column characteriser for the named column."""
|
|
108
115
|
from execsql.exceptions import ErrInfo
|
|
109
116
|
import execsql.state as _state
|
|
110
117
|
|
|
@@ -150,6 +157,7 @@ class Column:
|
|
|
150
157
|
return f"Column({self.name!r})"
|
|
151
158
|
|
|
152
159
|
def eval_types(self, column_value: Any) -> None:
|
|
160
|
+
"""Evaluate which data types the value matches and update counters."""
|
|
153
161
|
# Evaluate which data type(s) the value matches, and increment the appropriate counter(s).
|
|
154
162
|
import execsql.state as _state
|
|
155
163
|
|
|
@@ -170,6 +178,7 @@ class Column:
|
|
|
170
178
|
dt.check(column_value)
|
|
171
179
|
|
|
172
180
|
def column_type(self) -> tuple:
|
|
181
|
+
"""Return the inferred type of this column as a 6-tuple."""
|
|
173
182
|
# Return the type of this column as a tuple of:
|
|
174
183
|
# column name, data type class, max length or None, bool for null values,
|
|
175
184
|
# precision or None, scale or None.
|
|
@@ -212,7 +221,10 @@ class Column:
|
|
|
212
221
|
|
|
213
222
|
|
|
214
223
|
class DataTable:
|
|
224
|
+
"""Scan a row source and infer column types for CREATE TABLE generation."""
|
|
225
|
+
|
|
215
226
|
def __init__(self, column_names: list[str], rowsource: Any) -> None:
|
|
227
|
+
"""Scan all rows from the source and infer a column type for each column."""
|
|
216
228
|
import execsql.state as _state
|
|
217
229
|
|
|
218
230
|
self.inputrows = 0 # Total number of rows in the row source.
|
|
@@ -264,6 +276,7 @@ class DataTable:
|
|
|
264
276
|
return f"DataTable({[col.name for col in self.cols]!r}, rowsource)"
|
|
265
277
|
|
|
266
278
|
def column_declarations(self, database_type: DbType) -> list[str]:
|
|
279
|
+
"""Return a list of SQL column-declaration strings for the given DBMS."""
|
|
267
280
|
# Returns a list of column specifications.
|
|
268
281
|
spec = []
|
|
269
282
|
for col in self.cols:
|
|
@@ -277,6 +290,7 @@ class DataTable:
|
|
|
277
290
|
tablename: str,
|
|
278
291
|
pretty: bool = False,
|
|
279
292
|
) -> str:
|
|
293
|
+
"""Generate a CREATE TABLE statement for the given DBMS and table name."""
|
|
280
294
|
tb = (
|
|
281
295
|
f"{database_type.quoted(schemaname)}.{database_type.quoted(tablename)}"
|
|
282
296
|
if schemaname
|
|
@@ -292,7 +306,10 @@ class DataTable:
|
|
|
292
306
|
|
|
293
307
|
|
|
294
308
|
class JsonDatatype:
|
|
309
|
+
"""Namespace mapping Python DataType subclasses to JSON Schema type strings."""
|
|
310
|
+
|
|
295
311
|
def __init__(self) -> None:
|
|
312
|
+
"""Create an empty JsonDatatype namespace instance."""
|
|
296
313
|
pass
|
|
297
314
|
|
|
298
315
|
|