execsql2 2.1.2__py3-none-any.whl → 2.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. execsql/cli/__init__.py +436 -0
  2. execsql/cli/dsn.py +86 -0
  3. execsql/cli/help.py +140 -0
  4. execsql/{cli.py → cli/run.py} +14 -589
  5. execsql/config.py +65 -1
  6. execsql/db/access.py +27 -15
  7. execsql/db/base.py +328 -215
  8. execsql/db/dsn.py +10 -5
  9. execsql/db/duckdb.py +6 -2
  10. execsql/db/factory.py +21 -0
  11. execsql/db/firebird.py +27 -19
  12. execsql/db/mysql.py +12 -7
  13. execsql/db/oracle.py +15 -11
  14. execsql/db/postgres.py +31 -16
  15. execsql/db/sqlite.py +15 -11
  16. execsql/db/sqlserver.py +16 -5
  17. execsql/exceptions.py +25 -7
  18. execsql/exporters/base.py +12 -1
  19. execsql/exporters/delimited.py +80 -35
  20. execsql/exporters/duckdb.py +6 -2
  21. execsql/exporters/feather.py +10 -6
  22. execsql/exporters/html.py +89 -69
  23. execsql/exporters/json.py +52 -45
  24. execsql/exporters/latex.py +37 -27
  25. execsql/exporters/ods.py +32 -11
  26. execsql/exporters/parquet.py +5 -2
  27. execsql/exporters/pretty.py +16 -9
  28. execsql/exporters/raw.py +22 -16
  29. execsql/exporters/sqlite.py +6 -2
  30. execsql/exporters/templates.py +39 -21
  31. execsql/exporters/values.py +26 -20
  32. execsql/exporters/xls.py +30 -11
  33. execsql/exporters/xml.py +31 -13
  34. execsql/exporters/zip.py +15 -0
  35. execsql/importers/base.py +6 -4
  36. execsql/importers/csv.py +8 -6
  37. execsql/importers/feather.py +6 -4
  38. execsql/importers/ods.py +6 -4
  39. execsql/importers/xls.py +6 -4
  40. execsql/metacommands/__init__.py +208 -1548
  41. execsql/metacommands/conditions.py +101 -27
  42. execsql/metacommands/control.py +8 -4
  43. execsql/metacommands/data.py +6 -6
  44. execsql/metacommands/debug.py +6 -2
  45. execsql/metacommands/dispatch.py +2011 -0
  46. execsql/metacommands/io.py +67 -1310
  47. execsql/metacommands/io_export.py +442 -0
  48. execsql/metacommands/io_fileops.py +287 -0
  49. execsql/metacommands/io_import.py +398 -0
  50. execsql/metacommands/io_write.py +248 -0
  51. execsql/metacommands/prompt.py +22 -66
  52. execsql/metacommands/system.py +7 -2
  53. execsql/models.py +7 -0
  54. execsql/parser.py +10 -0
  55. execsql/py.typed +0 -0
  56. execsql/script/__init__.py +95 -0
  57. execsql/script/control.py +162 -0
  58. execsql/{script.py → script/engine.py} +184 -402
  59. execsql/script/variables.py +281 -0
  60. execsql/types.py +49 -20
  61. execsql/utils/auth.py +2 -0
  62. execsql/utils/crypto.py +4 -6
  63. execsql/utils/datetime.py +1 -0
  64. execsql/utils/errors.py +11 -0
  65. execsql/utils/fileio.py +33 -8
  66. execsql/utils/gui.py +46 -0
  67. execsql/utils/mail.py +7 -17
  68. execsql/utils/numeric.py +2 -0
  69. execsql/utils/regex.py +9 -0
  70. execsql/utils/strings.py +16 -0
  71. execsql/utils/timer.py +2 -0
  72. execsql2-2.4.0.data/data/execsql2_extras/README.md +65 -0
  73. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/execsql.conf +1 -1
  74. {execsql2-2.1.2.dist-info → execsql2-2.4.0.dist-info}/METADATA +13 -6
  75. execsql2-2.4.0.dist-info/RECORD +108 -0
  76. execsql2-2.1.2.data/data/execsql2_extras/READ_ME.rst +0 -127
  77. execsql2-2.1.2.dist-info/RECORD +0 -96
  78. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/config_settings.sqlite +0 -0
  79. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
  80. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/make_config_db.sql +0 -0
  81. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/md_compare.sql +0 -0
  82. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/md_glossary.sql +0 -0
  83. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/md_upsert.sql +0 -0
  84. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/pg_compare.sql +0 -0
  85. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/pg_glossary.sql +0 -0
  86. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/pg_upsert.sql +0 -0
  87. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/script_template.sql +0 -0
  88. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/ss_compare.sql +0 -0
  89. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/ss_glossary.sql +0 -0
  90. {execsql2-2.1.2.data → execsql2-2.4.0.data}/data/execsql2_extras/ss_upsert.sql +0 -0
  91. {execsql2-2.1.2.dist-info → execsql2-2.4.0.dist-info}/WHEEL +0 -0
  92. {execsql2-2.1.2.dist-info → execsql2-2.4.0.dist-info}/entry_points.txt +0 -0
  93. {execsql2-2.1.2.dist-info → execsql2-2.4.0.dist-info}/licenses/LICENSE.txt +0 -0
  94. {execsql2-2.1.2.dist-info → execsql2-2.4.0.dist-info}/licenses/NOTICE +0 -0
@@ -10,1587 +10,247 @@ Handler functions live in the sibling modules:
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
- import re
14
-
15
13
  import execsql.state as _state # noqa: F401
16
14
 
17
15
  # Handler imports — grouped by module for readability.
18
16
  from execsql.metacommands.connect import (
19
- x_connect_pg,
20
- x_connect_user_pg,
21
- x_connect_ssvr,
22
- x_connect_user_ssvr,
23
- x_connect_mysql,
24
- x_connect_user_mysql,
25
- x_connect_access,
26
- x_connect_fb,
27
- x_connect_user_fb,
28
- x_connect_ora,
29
- x_connect_user_ora,
30
- x_connect_duckdb,
31
- x_connect_sqlite,
17
+ x_connect_pg, # noqa: F401
18
+ x_connect_user_pg, # noqa: F401
19
+ x_connect_ssvr, # noqa: F401
20
+ x_connect_user_ssvr, # noqa: F401
21
+ x_connect_mysql, # noqa: F401
22
+ x_connect_user_mysql, # noqa: F401
23
+ x_connect_access, # noqa: F401
24
+ x_connect_fb, # noqa: F401
25
+ x_connect_user_fb, # noqa: F401
26
+ x_connect_ora, # noqa: F401
27
+ x_connect_user_ora, # noqa: F401
28
+ x_connect_duckdb, # noqa: F401
29
+ x_connect_sqlite, # noqa: F401
32
30
  x_connect_dsn, # noqa: F401
33
- x_use,
34
- x_disconnect,
35
- x_autocommit_on,
36
- x_autocommit_off,
37
- x_pg_vacuum,
38
- x_daoflushdelay,
31
+ x_use, # noqa: F401
32
+ x_disconnect, # noqa: F401
33
+ x_autocommit_on, # noqa: F401
34
+ x_autocommit_off, # noqa: F401
35
+ x_pg_vacuum, # noqa: F401
36
+ x_daoflushdelay, # noqa: F401
39
37
  )
40
38
  from execsql.metacommands.control import (
41
- x_if,
42
- x_if_orif,
43
- x_if_andif,
44
- x_if_elseif,
45
- x_if_else,
46
- x_if_block,
47
- x_if_end,
48
- x_loop,
49
- x_halt,
50
- x_halt_msg,
51
- x_error_halt,
52
- x_metacommand_error_halt,
53
- x_begin_batch,
54
- x_end_batch,
55
- x_rollback,
56
- x_break,
57
- x_wait_until,
39
+ x_if, # noqa: F401
40
+ x_if_orif, # noqa: F401
41
+ x_if_andif, # noqa: F401
42
+ x_if_elseif, # noqa: F401
43
+ x_if_else, # noqa: F401
44
+ x_if_block, # noqa: F401
45
+ x_if_end, # noqa: F401
46
+ x_loop, # noqa: F401
47
+ x_halt, # noqa: F401
48
+ x_halt_msg, # noqa: F401
49
+ x_error_halt, # noqa: F401
50
+ x_metacommand_error_halt, # noqa: F401
51
+ x_begin_batch, # noqa: F401
52
+ x_end_batch, # noqa: F401
53
+ x_rollback, # noqa: F401
54
+ x_break, # noqa: F401
55
+ x_wait_until, # noqa: F401
58
56
  )
59
57
  from execsql.metacommands.data import (
60
- x_sub,
61
- x_sub_add,
62
- x_sub_append,
63
- x_sub_empty,
64
- x_rm_sub,
65
- x_sub_local,
66
- x_sub_tempfile,
67
- x_sub_ini,
68
- x_sub_querystring,
69
- x_sub_encrypt,
70
- x_sub_decrypt,
71
- x_subdata,
72
- x_selectsub,
73
- x_prompt_selectsub,
74
- x_empty_strings,
75
- x_trim_strings,
76
- x_replace_newlines,
77
- x_empty_rows,
78
- x_only_strings,
79
- x_boolean_int,
80
- x_boolean_words,
81
- x_fold_col_hdrs,
82
- x_trim_col_hdrs,
83
- x_clean_col_hdrs,
84
- x_del_empty_cols,
85
- x_create_col_hdrs,
86
- x_dedup_col_hdrs,
87
- x_import_common_cols_only,
88
- x_quote_all_text,
89
- x_reset_counter,
90
- x_reset_counters,
91
- x_set_counter,
92
- x_max_int,
58
+ x_sub, # noqa: F401
59
+ x_sub_add, # noqa: F401
60
+ x_sub_append, # noqa: F401
61
+ x_sub_empty, # noqa: F401
62
+ x_rm_sub, # noqa: F401
63
+ x_sub_local, # noqa: F401
64
+ x_sub_tempfile, # noqa: F401
65
+ x_sub_ini, # noqa: F401
66
+ x_sub_querystring, # noqa: F401
67
+ x_sub_encrypt, # noqa: F401
68
+ x_sub_decrypt, # noqa: F401
69
+ x_subdata, # noqa: F401
70
+ x_selectsub, # noqa: F401
71
+ x_prompt_selectsub, # noqa: F401
72
+ x_empty_strings, # noqa: F401
73
+ x_trim_strings, # noqa: F401
74
+ x_replace_newlines, # noqa: F401
75
+ x_empty_rows, # noqa: F401
76
+ x_only_strings, # noqa: F401
77
+ x_boolean_int, # noqa: F401
78
+ x_boolean_words, # noqa: F401
79
+ x_fold_col_hdrs, # noqa: F401
80
+ x_trim_col_hdrs, # noqa: F401
81
+ x_clean_col_hdrs, # noqa: F401
82
+ x_del_empty_cols, # noqa: F401
83
+ x_create_col_hdrs, # noqa: F401
84
+ x_dedup_col_hdrs, # noqa: F401
85
+ x_import_common_cols_only, # noqa: F401
86
+ x_quote_all_text, # noqa: F401
87
+ x_reset_counter, # noqa: F401
88
+ x_reset_counters, # noqa: F401
89
+ x_set_counter, # noqa: F401
90
+ x_max_int, # noqa: F401
93
91
  )
94
92
  from execsql.metacommands.debug import (
95
- x_debug_write_metacommands,
96
- x_debug_commandliststack,
97
- x_debug_iflevels,
98
- x_debug_write_odbc_drivers,
99
- x_debug_log_subvars,
100
- x_debug_log_config,
101
- x_debug_write_subvars,
102
- x_debug_write_config,
93
+ x_debug_write_metacommands, # noqa: F401
94
+ x_debug_commandliststack, # noqa: F401
95
+ x_debug_iflevels, # noqa: F401
96
+ x_debug_write_odbc_drivers, # noqa: F401
97
+ x_debug_log_subvars, # noqa: F401
98
+ x_debug_log_config, # noqa: F401
99
+ x_debug_write_subvars, # noqa: F401
100
+ x_debug_write_config, # noqa: F401
103
101
  )
104
102
  from execsql.metacommands.io import (
105
- x_export,
106
- x_export_query,
107
- x_export_query_with_template,
108
- x_export_with_template,
109
- x_export_ods_multiple,
110
- x_export_metadata,
111
- x_export_metadata_table,
112
- x_import,
113
- x_import_file,
114
- x_import_ods,
115
- x_import_ods_pattern,
116
- x_import_xls,
117
- x_import_xls_pattern,
118
- x_import_parquet,
119
- x_import_feather,
120
- x_import_row_buffer,
121
- x_export_row_buffer,
122
- x_write,
123
- x_write_create_table,
124
- x_write_create_table_ods,
125
- x_write_create_table_xls,
126
- x_write_create_table_alias,
127
- x_write_prefix,
128
- x_write_suffix,
129
- x_writescript,
130
- x_include,
131
- x_copy,
132
- x_copy_query,
133
- x_zip,
134
- x_zip_buffer_mb,
135
- x_rm_file,
136
- x_make_export_dirs,
137
- x_cd,
138
- x_scan_lines,
139
- x_hdf5_text_len,
140
- x_serve,
103
+ x_export, # noqa: F401
104
+ x_export_query, # noqa: F401
105
+ x_export_query_with_template, # noqa: F401
106
+ x_export_with_template, # noqa: F401
107
+ x_export_ods_multiple, # noqa: F401
108
+ x_export_metadata, # noqa: F401
109
+ x_export_metadata_table, # noqa: F401
110
+ x_import, # noqa: F401
111
+ x_import_file, # noqa: F401
112
+ x_import_ods, # noqa: F401
113
+ x_import_ods_pattern, # noqa: F401
114
+ x_import_xls, # noqa: F401
115
+ x_import_xls_pattern, # noqa: F401
116
+ x_import_parquet, # noqa: F401
117
+ x_import_feather, # noqa: F401
118
+ x_import_row_buffer, # noqa: F401
119
+ x_show_progress, # noqa: F401
120
+ x_export_row_buffer, # noqa: F401
121
+ x_write, # noqa: F401
122
+ x_write_create_table, # noqa: F401
123
+ x_write_create_table_ods, # noqa: F401
124
+ x_write_create_table_xls, # noqa: F401
125
+ x_write_create_table_alias, # noqa: F401
126
+ x_write_prefix, # noqa: F401
127
+ x_write_suffix, # noqa: F401
128
+ x_writescript, # noqa: F401
129
+ x_include, # noqa: F401
130
+ x_copy, # noqa: F401
131
+ x_copy_query, # noqa: F401
132
+ x_zip, # noqa: F401
133
+ x_zip_buffer_mb, # noqa: F401
134
+ x_rm_file, # noqa: F401
135
+ x_make_export_dirs, # noqa: F401
136
+ x_cd, # noqa: F401
137
+ x_scan_lines, # noqa: F401
138
+ x_hdf5_text_len, # noqa: F401
139
+ x_serve, # noqa: F401
141
140
  )
142
141
  from execsql.metacommands.prompt import (
143
- x_prompt,
144
- x_prompt_enter,
145
- x_prompt_entryform,
146
- x_prompt_pause,
147
- x_prompt_compare,
148
- x_prompt_ask_compare,
149
- x_prompt_ask,
150
- x_prompt_map,
151
- x_prompt_action,
152
- x_prompt_savefile,
153
- x_prompt_openfile,
154
- x_prompt_directory,
155
- x_prompt_select_rows,
156
- x_prompt_credentials,
157
- x_prompt_connect,
158
- x_ask,
159
- x_pause,
160
- x_msg,
161
- x_reset_dialog_canceled,
142
+ x_prompt, # noqa: F401
143
+ x_prompt_enter, # noqa: F401
144
+ x_prompt_entryform, # noqa: F401
145
+ x_prompt_pause, # noqa: F401
146
+ x_prompt_compare, # noqa: F401
147
+ x_prompt_ask_compare, # noqa: F401
148
+ x_prompt_ask, # noqa: F401
149
+ x_prompt_map, # noqa: F401
150
+ x_prompt_action, # noqa: F401
151
+ x_prompt_savefile, # noqa: F401
152
+ x_prompt_openfile, # noqa: F401
153
+ x_prompt_directory, # noqa: F401
154
+ x_prompt_select_rows, # noqa: F401
155
+ x_prompt_credentials, # noqa: F401
156
+ x_prompt_connect, # noqa: F401
157
+ x_ask, # noqa: F401
158
+ x_pause, # noqa: F401
159
+ x_msg, # noqa: F401
160
+ x_reset_dialog_canceled, # noqa: F401
162
161
  )
163
162
  from execsql.metacommands.script_ext import (
164
- x_extendscript,
165
- x_extendscript_metacommand,
166
- x_extendscript_sql,
167
- x_executescript,
163
+ x_extendscript, # noqa: F401
164
+ x_extendscript_metacommand, # noqa: F401
165
+ x_extendscript_sql, # noqa: F401
166
+ x_executescript, # noqa: F401
168
167
  )
169
168
  from execsql.metacommands.system import (
170
- x_system_cmd,
171
- x_email,
172
- x_timer,
173
- x_log,
174
- x_logwritemessages,
175
- x_log_datavars,
176
- x_console,
177
- x_consoleprogress,
178
- x_consolewait,
179
- x_consolewait_onerror,
180
- x_consolewait_whendone,
181
- x_console_hideshow,
182
- x_consolewidth,
183
- x_consoleheight,
184
- x_consolestatus,
185
- x_consolesave,
186
- x_cancel_halt,
187
- x_cancel_halt_write_clear,
188
- x_cancel_halt_write,
189
- x_cancel_halt_email_clear,
190
- x_cancel_halt_email,
169
+ x_system_cmd, # noqa: F401
170
+ x_email, # noqa: F401
171
+ x_timer, # noqa: F401
172
+ x_log, # noqa: F401
173
+ x_logwritemessages, # noqa: F401
174
+ x_log_datavars, # noqa: F401
175
+ x_log_sql, # noqa: F401
176
+ x_console, # noqa: F401
177
+ x_consoleprogress, # noqa: F401
178
+ x_consolewait, # noqa: F401
179
+ x_consolewait_onerror, # noqa: F401
180
+ x_consolewait_whendone, # noqa: F401
181
+ x_console_hideshow, # noqa: F401
182
+ x_consolewidth, # noqa: F401
183
+ x_consoleheight, # noqa: F401
184
+ x_consolestatus, # noqa: F401
185
+ x_consolesave, # noqa: F401
186
+ x_cancel_halt, # noqa: F401
187
+ x_cancel_halt_write_clear, # noqa: F401
188
+ x_cancel_halt_write, # noqa: F401
189
+ x_cancel_halt_email_clear, # noqa: F401
190
+ x_cancel_halt_email, # noqa: F401
191
191
  x_cancel_halt_exec, # noqa: F401
192
- x_cancel_halt_exec_clear,
193
- x_error_halt_write_clear,
194
- x_error_halt_write,
195
- x_error_halt_email_clear,
196
- x_error_halt_email,
192
+ x_cancel_halt_exec_clear, # noqa: F401
193
+ x_error_halt_write_clear, # noqa: F401
194
+ x_error_halt_write, # noqa: F401
195
+ x_error_halt_email_clear, # noqa: F401
196
+ x_error_halt_email, # noqa: F401
197
197
  x_error_halt_exec, # noqa: F401
198
- x_error_halt_exec_clear,
199
- x_write_warnings,
200
- x_gui_level,
201
- x_execute,
198
+ x_error_halt_exec_clear, # noqa: F401
199
+ x_write_warnings, # noqa: F401
200
+ x_gui_level, # noqa: F401
201
+ x_execute, # noqa: F401
202
202
  )
203
203
 
204
204
  # Regex helper functions (from utils/regex.py)
205
205
  from execsql.utils.regex import (
206
- ins_rxs,
206
+ ins_rxs, # noqa: F401
207
207
  ins_quoted_rx, # noqa: F401
208
- ins_schema_rxs,
209
- ins_table_rxs,
210
- ins_table_list_rxs,
211
- ins_fn_rxs,
208
+ ins_schema_rxs, # noqa: F401
209
+ ins_table_rxs, # noqa: F401
210
+ ins_table_list_rxs, # noqa: F401
211
+ ins_fn_rxs, # noqa: F401
212
212
  )
213
- from execsql.script import MetaCommandList
214
-
215
-
216
- def build_dispatch_table() -> MetaCommandList:
217
- """Construct and return the complete metacommand dispatch table."""
218
- mcl = MetaCommandList()
219
-
220
- # ------------------------------------------------------------------
221
- # DEBUG metacommands
222
- # ------------------------------------------------------------------
223
- mcl.add(
224
- ins_fn_rxs(r"^\s*DEBUG\s+WRITE\s+METACOMMANDLIST\s+TO\s+", r"\s*$"),
225
- x_debug_write_metacommands,
226
- )
227
- mcl.add(r"^\s*DEBUG\s+WRITE\s+COMMANDLISTSTACK\s*$", x_debug_commandliststack)
228
- mcl.add(r"^\s*DEBUG\s+WRITE\s+IFLEVELS\s*$", x_debug_iflevels)
229
- mcl.add(
230
- ins_fn_rxs(
231
- r"^\s*DEBUG\s+WRITE\s+ODBC_DRIVERS(?:\s+(?P<append>APPEND\s+)?TO\s+",
232
- r")?\s*$",
233
- ),
234
- x_debug_write_odbc_drivers,
235
- )
236
- mcl.add(
237
- r"^\s*DEBUG\s+LOG(?:\s+(?P<local>LOCAL))?(?:\s+(?P<user>USER))?\s+SUBVARS\s*$",
238
- x_debug_log_subvars,
239
- )
240
- mcl.add(r"^\s*DEBUG\s+LOG\s+CONFIG\s*$", x_debug_log_config)
241
- mcl.add(
242
- ins_fn_rxs(
243
- r"^\s*DEBUG\s+WRITE(?:\s+(?P<local>LOCAL))?(?:\s+(?P<user>USER))?\s+SUBVARS"
244
- r"(?:\s+(?P<append>APPEND\s+)?TO\s+",
245
- r")?\s*$",
246
- ),
247
- x_debug_write_subvars,
248
- )
249
- mcl.add(
250
- ins_fn_rxs(
251
- r"^\s*DEBUG\s+WRITE\s+CONFIG(?:\s+(?P<append>APPEND\s+)?TO\s+",
252
- r")?\s*$",
253
- ),
254
- x_debug_write_config,
255
- )
256
-
257
- # ------------------------------------------------------------------
258
- # SERVE
259
- # ------------------------------------------------------------------
260
- mcl.add(
261
- ins_fn_rxs(
262
- r"^\s*SERVE\s+",
263
- r"\s+AS\s+(?P<format>BINARY|CSV|TXT|TEXT|ODS|JSON|HTML|PDF|ZIP)\s*$",
264
- ),
265
- x_serve,
266
- )
267
-
268
- # ------------------------------------------------------------------
269
- # Misc short commands
270
- # ------------------------------------------------------------------
271
- mcl.add(r"^\s*RESET\s+DIALOG_CANCELED\s*$", x_reset_dialog_canceled)
272
- mcl.add(r"^\s*SUB_QUERYSTRING\s+(?P<qstr>.+)\s*$", x_sub_querystring)
273
- mcl.add(r"^\s*BREAK\s*$", x_break)
274
-
275
- # ------------------------------------------------------------------
276
- # EXPORT QUERY (various formats)
277
- # ------------------------------------------------------------------
278
- mcl.add(
279
- ins_fn_rxs(
280
- r"^\s*EXPORT\s+QUERY\s+<<\s*(?P<query>.*;)\s*>>\s+(?P<tee>TEE\s+)?(?P<append>APPEND\s+)?TO\s+",
281
- ins_fn_rxs(
282
- r"(?:\s+IN\s+ZIPFILE\s+",
283
- r")?\s+AS\s*(?P<format>CSV|TAB|TSV|TABQ|TSVQ|UNITSEP|US|TXT|TXT-AND|PLAIN|ODS|JSON|"
284
- r'HTML|CGI-HTML|VALUES|LATEX|RAW|B64|FEATHER)(?:\s+DESCRIP(?:TION)?\s+"(?P<description>[^"]*)")?\s*$',
285
- symbolicname="zipfilename",
286
- ),
287
- ),
288
- x_export_query,
289
- "Write data from a query to a file.",
290
- )
291
- mcl.add(
292
- ins_fn_rxs(
293
- r"^\s*EXPORT\s+QUERY\s+<<\s*(?P<query>.*;)\s*>>\s+(?P<tee>TEE\s+)?(?P<append>APPEND\s+)?TO\s+",
294
- r"\s+AS\s*(?P<format>JSON_TS|JSON_TABLESCHEMA)(?:\s+(?P<notype>NOTYPE))?"
295
- r'(?:\s+DESCRIP(?:TION)?\s+"(?P<description>[^"]*)")?\s*$',
296
- ),
297
- x_export_query,
298
- "Write data from a query to a file.",
299
- )
300
- mcl.add(
301
- ins_fn_rxs(
302
- r"^\s*EXPORT\s+QUERY\s+<<\s*(?P<query>.*;)\s*>>\s+(?P<tee>TEE\s+)?(?P<append>APPEND\s+)?TO\s+",
303
- ins_fn_rxs(
304
- r"(?:\s+IN\s+ZIPFILE\s+",
305
- ins_fn_rxs(r")?\s+WITH\s+TEMPLATE\s+", r"\s*$", "template"),
306
- symbolicname="zipfilename",
307
- ),
308
- ),
309
- x_export_query_with_template,
310
- )
311
-
312
- # ------------------------------------------------------------------
313
- # EXPORT (table/view)
314
- # ------------------------------------------------------------------
315
- mcl.add(
316
- ins_table_rxs(
317
- r"^\s*EXPORT\s+",
318
- ins_fn_rxs(
319
- r"\s+(?P<tee>TEE\s+)?(?P<append>APPEND\s+)?TO\s+",
320
- ins_fn_rxs(
321
- r"(?:\s+IN\s+ZIPFILE\s+",
322
- ins_fn_rxs(r")?\s+WITH\s+TEMPLATE\s+", r"\s*$", "template"),
323
- symbolicname="zipfilename",
324
- ),
325
- ),
326
- ),
327
- x_export_with_template,
328
- )
329
- mcl.add(
330
- ins_table_rxs(
331
- r"^\s*EXPORT\s+",
332
- ins_fn_rxs(
333
- ins_fn_rxs(
334
- r"\s+(?P<tee>TEE\s+)?(?P<append>APPEND\s+)?TO\s+",
335
- r"(?:\s+IN\s+ZIPFILE\s+",
336
- ),
337
- r")?\s+AS\s+(?P<format>CSV|TAB|TSV|TABQ|TSVQ|UNITSEP|US|TXT|TXT-AND|PLAIN|JSON|XML|"
338
- r"VALUES|HTML|CGI-HTML|SQLITE|DUCKDB|LATEX|RAW|B64|FEATHER|HDF5)"
339
- r'(?:\s+DESCRIP(?:TION)?\s+"(?P<description>[^"]*)")?\s*$',
340
- symbolicname="zipfilename",
341
- ),
342
- ),
343
- x_export,
344
- "Write data from a table or view to a file.",
345
- )
346
- mcl.add(
347
- ins_table_rxs(
348
- r"^\s*EXPORT\s+",
349
- ins_fn_rxs(
350
- ins_fn_rxs(
351
- r"\s+(?P<tee>TEE\s+)?(?P<append>APPEND\s+)?TO\s+",
352
- r"(?:\s+IN\s+ZIPFILE\s+",
353
- ),
354
- r")?\s+AS\s+(?P<format>JSON_TS|JSON_TABLESCHEMA)(?:\s+(?P<notype>NOTYPE))?"
355
- r'(?:\s+DESCRIP(?:TION)?\s+"(?P<description>[^"]*)")?\s*$',
356
- symbolicname="zipfilename",
357
- ),
358
- ),
359
- x_export,
360
- "Write data from a table or view to a file.",
361
- )
362
- mcl.add(
363
- ins_table_list_rxs(
364
- r"^\s*EXPORT\s+",
365
- ins_fn_rxs(
366
- r"\s+(?P<tee>TEE\s+)?(?P<append>APPEND\s+)?TO\s+",
367
- r'\s+AS\s+ODS(?:\s+DESCRIP(?:TION)?\s+"(?P<description>[^"]*)")?\s*$',
368
- ),
369
- ),
370
- x_export_ods_multiple,
371
- "Write data from tables or views to an ODS file.",
372
- )
373
-
374
- # ------------------------------------------------------------------
375
- # IMPORT_FILE
376
- # ------------------------------------------------------------------
377
- mcl.add(
378
- ins_table_rxs(
379
- r"^\s*IMPORT_FILE\s+TO\s+TABLE\s+",
380
- ins_fn_rxs(
381
- r'\s+COLUMN\s+"(?P<columnname>[A-Za-z0-9_\-\: ]+)"\s+FROM\s+',
382
- r"\s*$",
383
- ),
384
- ),
385
- x_import_file,
386
- )
387
- mcl.add(
388
- ins_table_rxs(
389
- r"^\s*IMPORT_FILE\s+TO\s+TABLE\s+",
390
- ins_fn_rxs(
391
- r"\s+COLUMN\s+(?P<columnname>[A-Za-z0-9_\-\:]+)\s+FROM\s+",
392
- r"\s*$",
393
- ),
394
- ),
395
- x_import_file,
396
- )
397
-
398
- # ------------------------------------------------------------------
399
- # IMPORT ODS (pattern)
400
- # ------------------------------------------------------------------
401
- mcl.add(
402
- ins_schema_rxs(
403
- r"\s*IMPORT\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?TABLES\s+IN\s+(?:SCHEMA\s+)?",
404
- ins_fn_rxs(
405
- r"\s+FROM\s+",
406
- r"\s+SHEETS\s+MATCHING\s+(?P<patn>\S+)(?:\s+SKIP\s+(?P<skip>\d+))?\s*?",
407
- ),
408
- ),
409
- x_import_ods_pattern,
410
- )
411
-
412
- # ------------------------------------------------------------------
413
- # CD
414
- # ------------------------------------------------------------------
415
- mcl.add(r"^\s*CD\s+(?P<dir>.+)\s*$", x_cd)
416
-
417
- # ------------------------------------------------------------------
418
- # IMPORT ODS (single sheet)
419
- # ------------------------------------------------------------------
420
- mcl.add(
421
- ins_table_rxs(
422
- r"^\s*IMPORT\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?",
423
- ins_fn_rxs(
424
- r"\s+FROM\s+",
425
- r'\s+SHEET\s+"(?P<sheetname>[A-Za-z0-9_\.\/\-\\ ]+)"'
426
- r"(?:\s+SKIP\s+(?P<skip>\d+))?\s*$",
427
- ),
428
- )
429
- + ins_table_rxs(
430
- r"^\s*IMPORT\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?",
431
- ins_fn_rxs(
432
- r"\s+FROM\s+",
433
- r"\s+SHEET\s+(?P<sheetname>[A-Za-z0-9_\.\/\-\\]+)"
434
- r"(?:\s+SKIP\s+(?P<skip>\d+))?\s*$",
435
- ),
436
- ),
437
- x_import_ods,
438
- )
439
-
440
- # ------------------------------------------------------------------
441
- # IMPORT XLS (pattern)
442
- # ------------------------------------------------------------------
443
- mcl.add(
444
- ins_schema_rxs(
445
- r"\s*IMPORT\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?TABLES\s+IN\s+(?:SCHEMA\s+)?",
446
- ins_fn_rxs(
447
- r"\s+FROM\s+EXCEL\s+",
448
- r"\s+SHEETS\s+MATCHING\s+(?P<patn>\S+)(?:\s+SKIP\s+(?P<skip>\d+))?"
449
- r"(?:\s+ENCODING\s+(?P<encoding>\w+))?\s*?",
450
- ),
451
- ),
452
- x_import_xls_pattern,
453
- )
454
-
455
- # ------------------------------------------------------------------
456
- # IMPORT XLS (single sheet)
457
- # ------------------------------------------------------------------
458
- mcl.add(
459
- ins_table_rxs(
460
- r"^\s*IMPORT\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?",
461
- ins_fn_rxs(
462
- r"\s+FROM\s+EXCEL\s+",
463
- r'\s+SHEET\s+"(?P<sheetname>[A-Za-z0-9_\.\/\-\\ ]+)"'
464
- r"(?:\s+SKIP\s+(?P<skip>\d+))?(?:\s+ENCODING\s+(?P<encoding>\w+))?\s*$",
465
- ),
466
- )
467
- + ins_table_rxs(
468
- r"^\s*IMPORT\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?",
469
- ins_fn_rxs(
470
- r"\s+FROM\s+EXCEL\s+",
471
- r"\s+SHEET\s+(?P<sheetname>[A-Za-z0-9_\.\/\-\\]+)"
472
- r"(?:\s+SKIP\s+(?P<skip>\d+))?(?:\s+ENCODING\s+(?P<encoding>\w+))?\s*$",
473
- ),
474
- ),
475
- x_import_xls,
476
- )
477
-
478
- # ------------------------------------------------------------------
479
- # IMPORT PARQUET / FEATHER
480
- # ------------------------------------------------------------------
481
- mcl.add(
482
- ins_table_rxs(
483
- r"^\s*IMPORT\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?",
484
- ins_fn_rxs(r"\s+FROM\s+PARQUET\s+", r"\s*$"),
485
- ),
486
- x_import_parquet,
487
- )
488
- mcl.add(
489
- ins_table_rxs(
490
- r"^\s*IMPORT\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?",
491
- ins_fn_rxs(r"\s+FROM\s+FEATHER\s+", r"\s*$"),
492
- ),
493
- x_import_feather,
494
- )
495
-
496
- # ------------------------------------------------------------------
497
- # PROMPT ACTION
498
- # ------------------------------------------------------------------
499
- mcl.add(
500
- ins_table_rxs(
501
- r"^\s*PROMPT\s+ACTION\s+",
502
- ins_table_rxs(
503
- r'\s+MESSAGE\s+"(?P<message>(.|\n)*)"(?:\s+DISPLAY\s+',
504
- r")?(?:\s+COMPACT\s+(?P<compact>\d+))?(?:\s+(?P<continue>CONTINUE))?"
505
- r"(?:\s+HELP\s+(?P<help>[^\s]+))?\s*$",
506
- suffix="disp",
507
- ),
508
- ),
509
- x_prompt_action,
510
- )
511
- mcl.add(
512
- ins_table_rxs(
513
- r"^\s*PROMPT\s+ACTION\s+",
514
- ins_table_rxs(
515
- r'\s+MESSAGE\s+"(?P<message>(.|\n)*)"(?:\s+DISPLAY\s+',
516
- r")?(?:\s+COMPACT\s+(?P<compact>\d+))?(?:\s+(?P<continue>CONTINUE))?"
517
- r'(?:\s+HELP\s+"(?P<help>[^"]+)")?\s*$',
518
- suffix="disp",
519
- ),
520
- ),
521
- x_prompt_action,
522
- )
523
-
524
- # ------------------------------------------------------------------
525
- # PROMPT SAVEFILE / OPENFILE / DIRECTORY
526
- # ------------------------------------------------------------------
527
- mcl.add(
528
- ins_fn_rxs(
529
- r"^\s*PROMPT\s+SAVEFILE\s+SUB\s+(?P<match>~?\w+)(?:\s+(?P<fn_match>~?\w+))?"
530
- r"(?:\s+(?P<path_match>~?\w+))?(?:\s+(?P<ext_match>~?\w+))?"
531
- r"(?:\s+(?P<fnbase_match>~?\w+))?(?:\s+FROM\s+",
532
- r")?\s*$",
533
- symbolicname="startdir",
534
- ),
535
- x_prompt_savefile,
536
- )
537
- mcl.add(
538
- ins_fn_rxs(
539
- r"^\s*PROMPT\s+OPENFILE\s+SUB\s+(?P<match>~?\w+)(?:\s+(?P<fn_match>~?\w+))?"
540
- r"(?:\s+(?P<path_match>~?\w+))?(?:\s+(?P<ext_match>~?\w+))?"
541
- r"(?:\s+(?P<fnbase_match>~?\w+))?(?:\s+FROM\s+",
542
- r")?\s*$",
543
- symbolicname="startdir",
544
- ),
545
- x_prompt_openfile,
546
- )
547
- mcl.add(
548
- ins_fn_rxs(
549
- r"^\s*PROMPT\s+DIRECTORY\s+SUB\s+(?P<match>~?\w+)(?:\s+(?P<fullpath>FULLPATH))?"
550
- r"(?:\s+FROM\s+",
551
- r")?\s*$",
552
- symbolicname="startdir",
553
- ),
554
- x_prompt_directory,
555
- )
556
-
557
- # ------------------------------------------------------------------
558
- # PROMPT SELECT_ROWS
559
- # ------------------------------------------------------------------
560
- mcl.add(
561
- ins_table_rxs(
562
- r"^\s*PROMPT\s+SELECT_ROWS\s+FROM\s+",
563
- ins_table_rxs(
564
- r"(?:\s+IN\s+(?P<alias1>\w+))?\s+INTO\s+",
565
- r'(?:\s+IN\s+(?P<alias2>\w+))?(?:\s+HELP\s+(?P<help>[^\s]+))?\s+MESSAGE\s+"(?P<msg>(.|\n)*)"\s*$',
566
- suffix="2",
567
- ),
568
- suffix="1",
569
- ),
570
- x_prompt_select_rows,
571
- )
572
- mcl.add(
573
- ins_table_rxs(
574
- r"^\s*PROMPT\s+SELECT_ROWS\s+FROM\s+",
575
- ins_table_rxs(
576
- r"(?:\s+IN\s+(?P<alias1>\w+))?\s+INTO\s+",
577
- r'(?:\s+IN\s+(?P<alias2>\w+))?(?:\s+HELP\s+"(?P<help>[^"]+)")?\s+MESSAGE\s+"(?P<msg>(.|\n)*)"\s*$',
578
- suffix="2",
579
- ),
580
- suffix="1",
581
- ),
582
- x_prompt_select_rows,
583
- )
584
-
585
- # ------------------------------------------------------------------
586
- # SUB_LOCAL / SUB_ENCRYPT / SUB_DECRYPT
587
- # ------------------------------------------------------------------
588
- mcl.add(
589
- r"^\s*SUB_LOCAL\s+(?P<match>~?\w+)\s+(?P<repl>.+)$",
590
- x_sub_local,
591
- "SUB",
592
- "Define a local variable consisting of a string to match and a replacement for it.",
593
- )
594
- mcl.add(r"^\s*SUB_ENCRYPT\s+(?P<match>[+~]?\w+)\s+(?P<plaintext>.+)\s*$", x_sub_encrypt)
595
- mcl.add(r"^\s*SUB_DECRYPT\s+(?P<match>[+~]?\w+)\s+(?P<crypttext>.+)\s*$", x_sub_decrypt)
596
-
597
- # ------------------------------------------------------------------
598
- # WAIT_UNTIL
599
- # ------------------------------------------------------------------
600
- mcl.add(
601
- r"^\s*WAIT_UNTIL\s+(?P<condition>.+)\s+(?P<end>HALT|CONTINUE)\s+AFTER\s+(?P<seconds>\d+)\s+SECONDS\s*$",
602
- x_wait_until,
603
- )
604
-
605
- # ------------------------------------------------------------------
606
- # CONFIG * (various settings)
607
- # ------------------------------------------------------------------
608
- mcl.add(
609
- r"^\s*CONFIG\s+LOG_WRITE_MESSAGES\s+(?P<setting>Yes|No|On|Off|True|False|0|1)\s*$",
610
- x_logwritemessages,
611
- )
612
- mcl.add(
613
- r"^\s*CONFIG\s+QUOTE_ALL_TEXT\s+(?P<setting>Yes|No|On|Off|True|False|0|1)\s*$",
614
- x_quote_all_text,
615
- )
616
- mcl.add(r"^\s*CONFIG\s+IMPORT_ROW_BUFFER\s+(?P<rows>[1-9][0-9]*)\s*$", x_import_row_buffer)
617
- mcl.add(r"^\s*CONFIG\s+EXPORT_ROW_BUFFER\s+(?P<rows>[1-9][0-9]*)\s*$", x_export_row_buffer)
618
- mcl.add(r"^\s*CONFIG\s+ZIP_BUFFER_MB\s+(?P<size>[1-9][0-9]*)\s*$", x_zip_buffer_mb)
619
- mcl.add(
620
- r"^\s*CONFIG\s+EMPTY_STRINGS\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
621
- x_empty_strings,
622
- )
623
- mcl.add(
624
- r"^\s*CONFIG\s+TRIM_STRINGS\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
625
- x_trim_strings,
626
- )
627
- mcl.add(
628
- r"^\s*CONFIG\s+REPLACE_NEWLINES\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
629
- x_replace_newlines,
630
- )
631
- mcl.add(
632
- r"^\s*CONFIG\s+EMPTY_ROWS\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
633
- x_empty_rows,
634
- )
635
- mcl.add(
636
- r"^\s*CONFIG\s+ONLY_STRINGS\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
637
- x_only_strings,
638
- )
639
- mcl.add(
640
- r"^\s*(?:CONFIG\s+)?BOOLEAN_INT\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
641
- x_boolean_int,
642
- )
643
- mcl.add(
644
- r"^\s*CONFIG\s+BOOLEAN_WORDS\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
645
- x_boolean_words,
646
- )
647
- mcl.add(
648
- r"^\s*CONFIG\s+FOLD_COLUMN_HEADERS\s+(?P<foldspec>no|lower|upper)\s*$",
649
- x_fold_col_hdrs,
650
- )
651
- mcl.add(
652
- r"^\s*CONFIG\s+TRIM_COLUMN_HEADERS\s+(?P<which>NONE|BOTH|LEFT|RIGHT)\s*$",
653
- x_trim_col_hdrs,
654
- )
655
- mcl.add(
656
- r"^\s*CONFIG\s+CLEAN_COLUMN_HEADERS\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
657
- x_clean_col_hdrs,
658
- )
659
- mcl.add(
660
- r"^\s*CONFIG\s+DELETE_EMPTY_COLUMNS\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
661
- x_del_empty_cols,
662
- )
663
- mcl.add(
664
- r"^\s*CONFIG\s+CREATE_COLUMN_HEADERS\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
665
- x_create_col_hdrs,
666
- )
667
- mcl.add(
668
- r"^\s*CONFIG\s+DEDUP_COLUMN_HEADERS\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
669
- x_dedup_col_hdrs,
670
- )
671
- mcl.add(
672
- r"^\s*CONFIG\s+IMPORT_ONLY_COMMON_COLUMNS\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
673
- x_import_common_cols_only,
674
- )
675
- mcl.add(
676
- r"^\s*CONFIG\s+MAKE_EXPORT_DIRS\s+(?P<setting>Yes|No|On|Off|True|False|0|1)\s*$",
677
- x_make_export_dirs,
678
- )
679
- mcl.add(
680
- r"^\s*CONFIG\s+WRITE_WARNINGS\s+(?P<yesno>YES|NO|ON|OFF|TRUE|FALSE|0|1)\s*$",
681
- x_write_warnings,
682
- )
683
- mcl.add(r"^\s*CONFIG\s+GUI_LEVEL\s+(?P<level>[0-2])\s*$", x_gui_level)
684
- mcl.add(r"^\s*CONFIG\s+WRITE_PREFIX\s+(?P<prefix>.*)\s*$", x_write_prefix)
685
- mcl.add(r"^\s*CONFIG\s+WRITE_SUFFIX\s+(?P<suffix>.*)\s*$", x_write_suffix)
686
- mcl.add(r"^\s*CONFIG\s+SCAN_LINES\s+(?P<scanlines>[0-9]+)\s*$", x_scan_lines)
687
- mcl.add(r"^\s*CONFIG\s+HDF5_TEXT_LEN\s+(?P<textlen>[0-9]+)\s*$", x_hdf5_text_len)
688
- mcl.add(
689
- r"^\s*CONFIG\s+LOG_DATAVARS\s+(?P<setting>Yes|No|On|Off|True|False|0|1)\s*$",
690
- x_log_datavars,
691
- )
692
- mcl.add(
693
- r"^\s*CONFIG\s+DAO_FLUSH_DELAY_SECS\s+(?P<secs>[0-9]*\.?[0-9]+)\s*$",
694
- x_daoflushdelay,
695
- )
696
- mcl.add(
697
- r"^\s*CONFIG\s+CONSOLE\s+WAIT_WHEN_ERROR\s+(?P<onoff>ON|OFF|YES|NO|TRUE|FALSE|0|1)\s*$",
698
- x_consolewait_onerror,
699
- )
700
- mcl.add(
701
- r"^\s*CONFIG\s+CONSOLE\s+WAIT_WHEN_DONE\s+(?P<onoff>ON|OFF|YES|NO|TRUE|FALSE|0|1)\s*$",
702
- x_consolewait_whendone,
703
- )
704
-
705
- # ------------------------------------------------------------------
706
- # CONNECT — MS Access
707
- # ------------------------------------------------------------------
708
- mcl.add(
709
- ins_fn_rxs(
710
- r"^CONNECT\s+TO\s+ACCESS\s*\(\s*FILE\s*=\s*",
711
- r"(?:\s*,\s*NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?"
712
- r"(?:\s*,\s+PASSWORD\s*=\s*(?P<password>[^\s]+))?"
713
- 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*$",
714
- ),
715
- x_connect_access,
716
- )
717
-
718
- # ------------------------------------------------------------------
719
- # CONNECT — Firebird
720
- # ------------------------------------------------------------------
721
- mcl.add(
722
- (
723
- r"^CONNECT\s+USER\s+TO\s+FIREBIRD\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)\s*,\s*"
724
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
725
- 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*$",
726
- r'^CONNECT\s+USER\s+TO\s+FIREBIRD\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)"\s*,\s*'
727
- r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\- ]*)"(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?'
728
- 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*$",
729
- ),
730
- x_connect_user_fb,
731
- )
732
- mcl.add(
733
- r"^CONNECT\s+TO\s+FIREBIRD\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)\s*,\s*"
734
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_@\-\.]*)\s*,\s*"
735
- r"NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
736
- 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*$",
737
- x_connect_fb,
738
- )
739
-
740
- # ------------------------------------------------------------------
741
- # CONNECT — Oracle
742
- # ------------------------------------------------------------------
743
- mcl.add(
744
- (
745
- r"^CONNECT\s+USER\s+TO\s+ORACLE\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)\s*,\s*"
746
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
747
- 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*$",
748
- r'^CONNECT\s+USER\s+TO\s+ORACLE\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)"\s*,\s*'
749
- r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\- ]*)"(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?'
750
- 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*$",
751
- ),
752
- x_connect_user_ora,
753
- )
754
- mcl.add(
755
- (
756
- r"^CONNECT\s+TO\s+ORACLE\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)\s*,\s*"
757
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_\-@\.]*)\s*,\s*"
758
- r"NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
759
- r"(?:\s*,\s+PASSWORD\s*=\s*(?P<password>[^\s\)]+))?"
760
- 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*$",
761
- r'^CONNECT\s+TO\s+ORACLE\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)"\s*,\s*'
762
- r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\-]*)"(?:\s*,\s*USER\s*=\s*"(?P<user>[A-Z][A-Z0-9_\-@\.]*)"\s*,\s*'
763
- r"NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
764
- r'(?:\s*,\s+PASSWORD\s*=\s*"(?P<password>[^\s\)]+)")?'
765
- 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*$",
766
- ),
767
- x_connect_ora,
768
- )
769
-
770
- # ------------------------------------------------------------------
771
- # RUN / EXECUTE
772
- # ------------------------------------------------------------------
773
- mcl.add(
774
- r'^\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*$',
775
- x_executescript,
776
- )
777
- mcl.add(
778
- r'^\s*RUN\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*$',
779
- x_executescript,
780
- )
781
- mcl.add(
782
- r"^\s*(?P<cmd>RUN|EXECUTE)\s+(?P<queryname>\#?\w+)\s*$",
783
- x_execute,
784
- "RUN|EXECUTE",
785
- "Run a database function, view, or action query (DBMS-dependent)",
786
- )
787
-
788
- # ------------------------------------------------------------------
789
- # ON ERROR_HALT / ON CANCEL_HALT
790
- # ------------------------------------------------------------------
791
- mcl.add(r"^\s*ON\s+ERROR_HALT\s+WRITE\s+CLEAR\s*$", x_error_halt_write_clear)
792
- mcl.add(
793
- ins_fn_rxs(
794
- r'^\s*ON\s+ERROR_HALT\s+WRITE\s+"(?P<text>([^"]|\n)*)"(?:(?:\s+(?P<tee>TEE))?\s+TO\s+',
795
- r")?\s*$",
796
- ),
797
- x_error_halt_write,
798
- )
799
- mcl.add(r"^\s*ON\s+ERROR_HALT\s+EMAIL\s+CLEAR\s*$", x_error_halt_email_clear)
800
- mcl.add(
801
- ins_fn_rxs(
802
- ins_fn_rxs(
803
- r"^\s*ON\s+ERROR_HALT\s+EMAIL\s+"
804
- r"FROM\s+(?P<from>[A-Za-z0-9_\-\.!#$%&\'*+/=?^`{|}~]+@[A-Za-z0-9]+(-[A-Za-z0-9]+)*(\.[A-Za-z0-9]+)*)\s+"
805
- r"TO\s+(?P<to>[A-Za-z0-9_\-\.!#$%&\'*+/=?^`{|}~]+@[A-Za-z0-9]+(-[A-Za-z0-9]+)*(\.[A-Za-z0-9]+)*"
806
- r"([;,]\s*[A-Za-z0-9\-\.!#$%&\'*+/=?^`{|}~]+@[A-Za-z0-9]+(-[A-Za-z0-9]+)*(\.[A-Za-z0-9]+)*)*)\s+"
807
- r'SUBJECT "(?P<subject>[^"]+)"\s+'
808
- r'MESSAGE\s+"(?P<msg>[^"]*)"'
809
- r"(\s+MESSAGE_FILE\s+",
810
- r")?(\s+ATTACH(MEANT)?_FILE\s+",
811
- "msg_file",
812
- ),
813
- r")?\s*$",
814
- "att_file",
815
- ),
816
- x_error_halt_email,
817
- )
818
- mcl.add(r"^\s*ON\s+ERROR_HALT\s+EXEC\s+CLEAR\s*$", x_error_halt_exec_clear)
819
- mcl.add(r"^\s*ON\s+CANCEL_HALT\s+WRITE\s+CLEAR\s*$", x_cancel_halt_write_clear)
820
- mcl.add(
821
- ins_fn_rxs(
822
- r'^\s*ON\s+CANCEL_HALT\s+WRITE\s+"(?P<text>([^"]|\n)*)"(?:(?:\s+(?P<tee>TEE))?\s+TO\s+',
823
- r")?\s*$",
824
- ),
825
- x_cancel_halt_write,
826
- )
827
- mcl.add(r"^\s*ON\s+CANCEL_HALT\s+EMAIL\s+CLEAR\s*$", x_cancel_halt_email_clear)
828
- mcl.add(
829
- ins_fn_rxs(
830
- ins_fn_rxs(
831
- r"^\s*ON\s+CANCEL_HALT\s+EMAIL\s+"
832
- r"FROM\s+(?P<from>[A-Za-z0-9_\-\.!#$%&\'*+/=?^`{|}~]+@[A-Za-z0-9]+(-[A-Za-z0-9]+)*(\.[A-Za-z0-9]+)*)\s+"
833
- r"TO\s+(?P<to>[A-Za-z0-9_\-\.!#$%&\'*+/=?^`{|}~]+@[A-Za-z0-9]+(-[A-Za-z0-9]+)*(\.[A-Za-z0-9]+)*"
834
- r"([;,]\s*[A-Za-z0-9\-\.!#$%&\'*+/=?^`{|}~]+@[A-Za-z0-9]+(-[A-Za-z0-9]+)*(\.[A-Za-z0-9]+)*)*)\s+"
835
- r'SUBJECT "(?P<subject>[^"]+)"\s+'
836
- r'MESSAGE\s+"(?P<msg>[^"]*)"'
837
- r"(\s+MESSAGE_FILE\s+",
838
- r")?(\s+ATTACH(MEANT)?_FILE\s+",
839
- "msg_file",
840
- ),
841
- r")?\s*$",
842
- "att_file",
843
- ),
844
- x_cancel_halt_email,
845
- )
846
- mcl.add(r"^\s*ON\s+CANCEL_HALT\s+EXEC\s+CLEAR\s*$", x_cancel_halt_exec_clear)
847
-
848
- # ------------------------------------------------------------------
849
- # SUB_TEMPFILE
850
- # ------------------------------------------------------------------
851
- mcl.add(r"^\s*SUB_TEMPFILE\s+(?P<match>[+~]?\w+)\s*$", x_sub_tempfile)
852
-
853
- # ------------------------------------------------------------------
854
- # WRITE CREATE_TABLE (ODS / XLS / CSV / alias)
855
- # ------------------------------------------------------------------
856
- mcl.add(
857
- ins_table_rxs(
858
- r"^\s*WRITE\s+CREATE_TABLE\s+",
859
- ins_fn_rxs(
860
- r"\s+FROM\s+",
861
- ins_rxs(
862
- (
863
- r'"(?P<sheet>[A-Za-z0-9_\.\/\-\\ ]+)"',
864
- r"(?P<sheet>[A-Za-z0-9_\.\/\-\\]+)",
865
- ),
866
- r"\s+SHEET\s+",
867
- ins_fn_rxs(
868
- r'(?:\s+SKIP\s+(?P<skip>\d+))?(?:\s+COMMENT\s+"(?P<comment>[^"]+)")?'
869
- r"(?:\s+TO\s+",
870
- r")?\s*$",
871
- "outfile",
872
- ),
873
- ),
874
- ),
875
- ),
876
- x_write_create_table_ods,
877
- )
878
- mcl.add(
879
- ins_table_rxs(
880
- r"^\s*WRITE\s+CREATE_TABLE\s+",
881
- ins_fn_rxs(
882
- r"\s+FROM\s+EXCEL\s+",
883
- ins_rxs(
884
- (
885
- r'"(?P<sheet>[A-Za-z0-9_\.\/\-\\ ]+)"',
886
- r"(?P<sheet>[A-Za-z0-9_\.\/\-\\]+)",
887
- ),
888
- r"\s+SHEET\s+",
889
- ins_fn_rxs(
890
- r"(?:\s+SKIP\s+(?P<skip>\d+))?(?:\s+ENCODING\s+(?P<encoding>\w+))?"
891
- r'(?:\s+COMMENT\s+"(?P<comment>[^"]+)")?(?:\s+TO\s+',
892
- r")?\s*$",
893
- "outfile",
894
- ),
895
- ),
896
- ),
897
- ),
898
- x_write_create_table_xls,
899
- )
900
- mcl.add(
901
- ins_table_rxs(
902
- r"^\s*WRITE\s+CREATE_TABLE\s+",
903
- ins_table_rxs(
904
- r"\s+FROM\s+",
905
- ins_fn_rxs(
906
- r'\s+IN\s+(?P<alias>[A-Z][A-Z0-9_]*)(?:\s+COMMENT\s+"(?P<comment>[^"]+)")?(?:\s+TO\s+',
907
- r")?\s*$",
908
- ),
909
- "1",
910
- ),
911
- ),
912
- x_write_create_table_alias,
913
- )
914
- mcl.add(
915
- ins_table_rxs(
916
- r"^\s*WRITE\s+CREATE_TABLE\s+",
917
- ins_fn_rxs(
918
- r"\s+FROM\s+",
919
- ins_fn_rxs(
920
- r'(?:\s+WITH\s+QUOTE\s+(?P<quotechar>NONE|\'|")\s+DELIMITER\s+(?P<delimchar>TAB|UNITSEP|US|,|;|\|))?'
921
- r"(?:\s+ENCODING\s+(?P<encoding>\w+))?(?:\s+SKIP\s+(?P<skip>\d+))?"
922
- r'(?:\s+COMMENT\s+"(?P<comment>[^"]+)")?(?:\s+TO\s+',
923
- r")?\s*$",
924
- "outfile",
925
- ),
926
- ),
927
- ),
928
- x_write_create_table,
929
- )
930
-
931
- # ------------------------------------------------------------------
932
- # RESET / SET COUNTER
933
- # ------------------------------------------------------------------
934
- mcl.add(r"^\s*RESET\s+COUNTER\s+(?P<counter_no>\d+)\s*$", x_reset_counter)
935
- mcl.add(r"^\s*RESET\s+COUNTERS\s*$", x_reset_counters)
936
- mcl.add(
937
- r"^\s*SET\s+COUNTER\s+(?P<counter_no>\d+)\s+TO\s+(?P<value>[0-9+\-*/() ]+)\s*$",
938
- x_set_counter,
939
- )
940
-
941
- # ------------------------------------------------------------------
942
- # PROMPT CREDENTIALS / CONNECT
943
- # ------------------------------------------------------------------
944
- mcl.add(
945
- (
946
- r'^\s*PROMPT(?:\s+MESSAGE\s+"(?P<message>(.|\n)*)")?\s+CREDENTIALS\s+(?P<user>\w+)\s+(?P<pw>\w+)\s*$',
947
- r'^\s*PROMPT(?:\s+"(?P<message>(.|\n)*)")?\s+CREDENTIALS\s+(?P<user>\w+)\s+(?P<pw>\w+)\s*$',
948
- ),
949
- x_prompt_credentials,
950
- )
951
- mcl.add(
952
- (
953
- r'^\s*PROMPT(?:\s+MESSAGE\s+"(?P<message>(.|\n)*)")?\s+CONNECT\s+AS\s+(?P<alias>\w+)(?:\s+HELP\s+(?P<help>[^\s]+))?\s*$',
954
- r'^\s*PROMPT(?:\s+MESSAGE\s+"(?P<message>(.|\n)*)")?\s+CONNECT\s+AS\s+(?P<alias>\w+)(?:\s+HELP\s+"(?P<help>[^"]+)")?\s*$',
955
- r'^\s*CONNECT\s+PROMPT(?:\s+MESSAGE\s+"(?P<message>(.|\n)*)")?\s+AS\s+(?P<alias>\w+)(?:\s+HELP\s+(?P<help>[^\s]+))?\s*$',
956
- r'^\s*CONNECT\s+PROMPT(?:\s+MESSAGE\s+"(?P<message>(.|\n)*)")?\s+AS\s+(?P<alias>\w+)(?:\s+HELP\s+"(?P<help>[^"]+)")?\s*$',
957
- r'^\s*PROMPT(?:\s+"(?P<message>(.|\n)*)")?\s+CONNECT\s+AS\s+(?P<alias>\w+)(?:\s+HELP\s+(?P<help>[^\s]+))?\s*$',
958
- r'^\s*PROMPT(?:\s+"(?P<message>(.|\n)*)")?\s+CONNECT\s+AS\s+(?P<alias>\w+)(?:\s+HELP\s+"(?P<help>[^"]+)")?\s*$',
959
- r'^\s*CONNECT\s+PROMPT(?:\s+"(?P<message>(.|\n)*)")?\s+AS\s+(?P<alias>\w+)(?:\s+HELP\s+(?P<help>[^\s]+))?\s*$',
960
- r'^\s*CONNECT\s+PROMPT(?:\s+"(?P<message>(.|\n)*)")?\s+AS\s+(?P<alias>\w+)(?:\s+HELP\s+"(?P<help>[^"]+)")?\s*$',
961
- ),
962
- x_prompt_connect,
963
- )
964
-
965
- # ------------------------------------------------------------------
966
- # TIMER / LOG / SUB_INI
967
- # ------------------------------------------------------------------
968
- mcl.add(r"^\s*TIMER\s+(?P<onoff>ON|OFF)\s*$", x_timer)
969
- mcl.add(r'^\s*LOG\s+"(?P<message>.+)"\s*$', x_log)
970
- mcl.add(
971
- ins_fn_rxs(r"^\s*SUB_INI\s+(?:FILE\s+)?", r"(?:\s+SECTION)?\s+(?P<section>\w+)\s*$"),
972
- x_sub_ini,
973
- )
974
-
975
- # ------------------------------------------------------------------
976
- # CONSOLE
977
- # ------------------------------------------------------------------
978
- mcl.add(r"^\s*CONSOLE\s+(?P<hideshow>HIDE|SHOW)\s*$", x_console_hideshow)
979
- mcl.add(r"^\s*CONSOLE\s+WIDTH\s+(?P<width>\d+)\s*$", x_consolewidth)
980
- mcl.add(r"^\s*CONSOLE\s+HEIGHT\s+(?P<height>\d+)\s*$", x_consoleheight)
981
- mcl.add(r'^\s*CONSOLE\s+STATUS\s+"(?P<message>.*)"\s*$', x_consolestatus)
982
- mcl.add(
983
- ins_fn_rxs(r"^\s*CONSOLE\s+SAVE(?:\s+(?P<append>APPEND))?\s+TO\s+", r"\s*$"),
984
- x_consolesave,
985
- )
986
- mcl.add(r'^\s*CONSOLE\s+WAIT(?:\s+"(?P<message>.+)")?\s*$', x_consolewait)
987
- mcl.add(
988
- r"^\s*CONSOLE\s+PROGRESS\s+(?P<num>[0-9]+(?:\.[0-9]+)?)(?:\s*/\s*(?P<total>[0-9]+(?:\.[0-9]+)?))?\s*$",
989
- x_consoleprogress,
990
- )
991
- mcl.add(r"^\s*CONSOLE\s+(?P<onoff>ON|OFF)\s*$", x_console)
992
-
993
- # ------------------------------------------------------------------
994
- # DISCONNECT / AUTOCOMMIT
995
- # ------------------------------------------------------------------
996
- mcl.add(r"^\s*DISCONNECT(?:(?:\s+FROM)?\s+(?P<alias>[A-Z][A-Z0-9_]*))?\s*$", x_disconnect)
997
- mcl.add(r"^\s*AUTOCOMMIT\s+OFF\s*$", x_autocommit_off)
998
- mcl.add(r"^\s*AUTOCOMMIT\s+ON(?:\s+WITH\s+(?P<action>COMMIT|ROLLBACK))?\s*$", x_autocommit_on)
999
-
1000
- # ------------------------------------------------------------------
1001
- # WRITE SCRIPT / MAX_INT / PG_VACUUM
1002
- # ------------------------------------------------------------------
1003
- mcl.add(
1004
- ins_fn_rxs(
1005
- r"^\s*(?:DEBUG\s+)?WRITE\s+SCRIPT\s+(?P<script_id>\w+)(?:\s+(?P<append>APPEND\s+)?TO\s+",
1006
- r")?\s*$",
1007
- ),
1008
- x_writescript,
1009
- )
1010
- mcl.add(r"^\s*MAX_INT\s+(?P<maxint>[0-9]+)\s*$", x_max_int)
1011
- mcl.add(r"^\s*PG_VACUUM(?P<vacuum_args>.*)\s*$", x_pg_vacuum)
1012
-
1013
- # ------------------------------------------------------------------
1014
- # ZIP
1015
- # ------------------------------------------------------------------
1016
- mcl.add(
1017
- ins_fn_rxs(
1018
- r"^\s*ZIP\s+(?P<filename>[^ ]+)(?:\s+(?P<append>APPEND))?\s+TO\s+ZIPFILE\s+",
1019
- r"\s*$",
1020
- symbolicname="zipfilename",
1021
- ),
1022
- x_zip,
1023
- )
1024
- mcl.add(
1025
- ins_fn_rxs(
1026
- r'^\s*ZIP\s+"(?P<filename>[^"]+)"(?:\s+(?P<append>APPEND))?\s+TO\s+ZIPFILE\s+',
1027
- r"\s*$",
1028
- symbolicname="zipfilename",
1029
- ),
1030
- x_zip,
1031
- )
213
+ from execsql.script import MetaCommandList # noqa: F401
1032
214
 
1033
- # ------------------------------------------------------------------
1034
- # HALT (various forms)
1035
- # ------------------------------------------------------------------
1036
- mcl.add(
1037
- ins_fn_rxs(
1038
- r'^\s*HALT\s*(?:\s+MESSAGE)?(?:\s+"(?P<errmsg>.+)"(?:\s+(?P<tee>TEE\s+TO\s+',
1039
- r"))?)?(?:\s+EXIT_STATUS\s+(?P<errorlevel>\d+))?\s*$",
1040
- ),
1041
- x_halt,
1042
- )
1043
- for errmsg_delim in (r"\[", r"\#", r"\`", r"\'", r"\~", r'"'):
1044
- # Use the same open/close bracket pair for the errmsg capture
1045
- open_c = errmsg_delim if not errmsg_delim.startswith("\\") else errmsg_delim[1:]
1046
- close_c = "]" if open_c == "[" else open_c
1047
- mcl.add(
1048
- ins_table_rxs(
1049
- ins_fn_rxs(
1050
- rf"^\s*HALT(?:\s+MESSAGE)?\s+{errmsg_delim}(?P<errmsg>(.|\n)*){re.escape(close_c)}"
1051
- r"(?:\s+(?P<tee>TEE\s+TO\s+",
1052
- r"))?(?:\s+DISPLAY\s+",
1053
- ),
1054
- r")?(?:\s+EXIT_STATUS\s+(?P<errorlevel>\d+))?\s*$",
1055
- ),
1056
- x_halt_msg,
1057
- )
1058
-
1059
- # ------------------------------------------------------------------
1060
- # BEGIN / END BATCH / ROLLBACK
1061
- # ------------------------------------------------------------------
1062
- mcl.add(r"^\s*BEGIN\s+BATCH\s*$", x_begin_batch)
1063
- mcl.add(r"^\s*END\s+BATCH\s*$", x_end_batch, "END BATCH", run_in_batch=True)
1064
- mcl.add(r"^\s*ROLLBACK(:?\s+BATCH)?\s*$", x_rollback, "ROLLBACK BATCH", run_in_batch=True)
1065
-
1066
- # ------------------------------------------------------------------
1067
- # ERROR_HALT / METACOMMAND_ERROR_HALT / CANCEL_HALT
1068
- # ------------------------------------------------------------------
1069
- mcl.add(r"\s*ERROR_HALT\s+(?P<onoff>ON|OFF|YES|NO|TRUE|FALSE)\s*$", x_error_halt)
1070
- mcl.add(
1071
- r"\s*METACOMMAND_ERROR_HALT\s+(?P<onoff>ON|OFF|YES|NO|TRUE|FALSE)\s*$",
1072
- x_metacommand_error_halt,
1073
- set_error_flag=False,
1074
- )
1075
- mcl.add(r"^\s*CANCEL_HALT\s+(?P<onoff>ON|OFF|YES|NO|TRUE|FALSE)\s*$", x_cancel_halt)
1076
-
1077
- # ------------------------------------------------------------------
1078
- # LOOP
1079
- # ------------------------------------------------------------------
1080
- mcl.add(r"^\s*LOOP\s+(?P<looptype>WHILE|UNTIL)\s*\(\s*(?P<loopcond>.+)\s*\)\s*$", x_loop)
1081
-
1082
- # ------------------------------------------------------------------
1083
- # PAUSE
1084
- # ------------------------------------------------------------------
1085
- mcl.add(
1086
- (
1087
- r'^\s*PAUSE\s+"(?P<text>.+)"(?:\s+(?P<action>HALT|CONTINUE)\s+AFTER\s+(?P<countdown>\d+(?:\.\d*)?)\s+(?P<timeunit>SECONDS|MINUTES))?\s*$',
1088
- r"^\s*PAUSE\s+'(?P<text>.+)'(?:\s+(?P<action>HALT|CONTINUE)\s+AFTER\s+(?P<countdown>\d+(?:\.\d*)?)\s+(?P<timeunit>SECONDS|MINUTES))?\s*$",
1089
- r"^\s*PAUSE\s+\[(?P<text>.+)\](?:\s+(?P<action>HALT|CONTINUE)\s+AFTER\s+(?P<countdown>\d+(?:\.\d*)?)\s+(?P<timeunit>SECONDS|MINUTES))?\s*$",
1090
- ),
1091
- x_pause,
1092
- )
1093
-
1094
- # ------------------------------------------------------------------
1095
- # PROMPT ENTER_SUB
1096
- # ------------------------------------------------------------------
1097
- mcl.add(
1098
- ins_table_rxs(
1099
- r'^\s*PROMPT\s+ENTER_SUB\s+(?P<match_str>~?\w+)\s+(?:(?P<password>PASSWORD)\s+)?MESSAGE\s+"(?P<message>([^"]|\n)*)"(?:\s+DISPLAY\s+',
1100
- r")?(?:\s+TYPE\s+(?P<type>INT|FLOAT|BOOL|IDENT))?(?:\s+(?P<case>LCASE|UCASE))?"
1101
- r'(?:\s+INITIALLY\s+"(?P<initial>[^"]+)")?(?:\s+HELP\s+(?P<help>[^\s]+))?\s*$',
1102
- ),
1103
- x_prompt_enter,
1104
- )
1105
- mcl.add(
1106
- ins_table_rxs(
1107
- r'^\s*PROMPT\s+ENTER_SUB\s+(?P<match_str>~?\w+)\s+(?:(?P<password>PASSWORD)\s+)?MESSAGE\s+"(?P<message>([^"]|\n)*)"(?:\s+DISPLAY\s+',
1108
- r")?(?:\s+TYPE\s+(?P<type>INT|FLOAT|BOOL|IDENT))?(?:\s+(?P<case>LCASE|UCASE))?"
1109
- r'(?:\s+INITIALLY\s+"(?P<initial>[^"]+)")?(?:\s+HELP\s+"(?P<help>[^+]+)")?\s*$',
1110
- ),
1111
- x_prompt_enter,
1112
- )
1113
-
1114
- # ------------------------------------------------------------------
1115
- # PROMPT ENTRY_FORM
1116
- # ------------------------------------------------------------------
1117
- mcl.add(
1118
- ins_table_rxs(
1119
- r"^\s*PROMPT\s+ENTRY_FORM\s+",
1120
- ins_table_rxs(
1121
- r'(?:\s+HELP\s+(?P<help>[^\s]+))?\s+MESSAGE\s+"(?P<message>(.|\n)*)"(?:\s+DISPLAY\s+',
1122
- r")?\s*$",
1123
- suffix="disp",
1124
- ),
1125
- ),
1126
- x_prompt_entryform,
1127
- )
1128
- mcl.add(
1129
- ins_table_rxs(
1130
- r"^\s*PROMPT\s+ENTRY_FORM\s+",
1131
- ins_table_rxs(
1132
- r'(?:\s+HELP\s+"(?P<help>[^"]+)")?\s+MESSAGE\s+"(?P<message>(.|\n)*)"(?:\s+DISPLAY\s+',
1133
- r")?\s*$",
1134
- suffix="disp",
1135
- ),
1136
- ),
1137
- x_prompt_entryform,
1138
- )
1139
-
1140
- # ------------------------------------------------------------------
1141
- # PROMPT SELECT_SUB
1142
- # ------------------------------------------------------------------
1143
- mcl.add(
1144
- ins_table_rxs(
1145
- r"^\s*PROMPT\s+SELECT_SUB\s+",
1146
- r'\s+MESSAGE\s+"(?P<msg>(.|\n)*)"(?:\s+(?P<cont>CONTINUE))?(?:\s+HELP\s(?P<help>[^\s]+))?\s*$',
1147
- ),
1148
- x_prompt_selectsub,
1149
- )
1150
- mcl.add(
1151
- ins_table_rxs(
1152
- r"^\s*PROMPT\s+SELECT_SUB\s+",
1153
- r'\s+MESSAGE\s+"(?P<msg>(.|\n)*)"(?:\s+(?P<cont>CONTINUE))?(?:\s+HELP\s"(?P<help>[^"]+)")?\s*$',
1154
- ),
1155
- x_prompt_selectsub,
1156
- )
1157
-
1158
- # ------------------------------------------------------------------
1159
- # PROMPT PAUSE
1160
- # ------------------------------------------------------------------
1161
- mcl.add(
1162
- (
1163
- r'^\s*PROMPT\s+PAUSE\s+"(?P<text>.+)"(?:\s+(?P<action>HALT|CONTINUE)\s+AFTER\s+(?P<countdown>\d+(?:\.\d*)?)\s+(?P<timeunit>SECONDS|MINUTES))?\s*$',
1164
- r"^\s*PROMPT\s+PAUSE\s+'(?P<text>.+)'(?:\s+(?P<action>HALT|CONTINUE)\s+AFTER\s+(?P<countdown>\d+(?:\.\d*)?)\s+(?P<timeunit>SECONDS|MINUTES))?\s*$",
1165
- r"^\s*PROMPT\s+PAUSE\s+\[(?P<text>.+)\](?:\s+(?P<action>HALT|CONTINUE)\s+AFTER\s+(?P<countdown>\d+(?:\.\d*)?)\s+(?P<timeunit>SECONDS|MINUTES))?\s*$",
1166
- ),
1167
- x_prompt_pause,
1168
- )
1169
-
1170
- # ------------------------------------------------------------------
1171
- # ASK
1172
- # ------------------------------------------------------------------
1173
- mcl.add(
1174
- (
1175
- r'^\s*ASK\s+"(?P<question>.+)"\s+SUB\s+(?P<match>~?\w+)\s*$',
1176
- r"^\s*ASK\s+'(?P<question>.+)'\s+SUB\s+(?P<match>~?\w+)\s*$",
1177
- r"^\s*ASK\s+\[(?P<question>.+)\]\s+SUB\s+(?P<match>~?\w+)\s*$",
1178
- ),
1179
- x_ask,
1180
- )
1181
-
1182
- # ------------------------------------------------------------------
1183
- # PROMPT COMPARE / PROMPT ASK COMPARE
1184
- # ------------------------------------------------------------------
1185
- mcl.add(
1186
- ins_table_rxs(
1187
- r"^\s*PROMPT\s+COMPARE\s+",
1188
- ins_table_rxs(
1189
- r"(?:\s+IN\s+(?P<alias1>\w+))?\s+(?P<orient>AND|BESIDE)\s+",
1190
- r'(?:\s+IN\s+(?P<alias2>\w+))?\s+(?:PK|KEY)\s*\((?P<pks>(("[A-Z_0-9]+")|[A-Z_0-9]+)'
1191
- r'(\s*,\s*(("[A-Z_0-9]+")|[A-Z_0-9]+))*)\)(?:\s+HELP\s+(?P<help>[^\s]+))?\s+MESSAGE\s+"(?P<msg>(.|\n)*)"\s*$',
1192
- suffix="2",
1193
- ),
1194
- suffix="1",
1195
- ),
1196
- x_prompt_compare,
1197
- )
1198
- mcl.add(
1199
- ins_table_rxs(
1200
- r"^\s*PROMPT\s+COMPARE\s+",
1201
- ins_table_rxs(
1202
- r"(?:\s+IN\s+(?P<alias1>\w+))?\s+(?P<orient>AND|BESIDE)\s+",
1203
- r'(?:\s+IN\s+(?P<alias2>\w+))?\s+(?:PK|KEY)\s*\((?P<pks>(("[A-Z_0-9]+")|[A-Z_0-9]+)'
1204
- r'(\s*,\s*(("[A-Z_0-9]+")|[A-Z_0-9]+))*)\)(?:\s+HELP\s+"(?P<help>[^"]+)")?\s+MESSAGE\s+"(?P<msg>(.|\n)*)"\s*$',
1205
- suffix="2",
1206
- ),
1207
- suffix="1",
1208
- ),
1209
- x_prompt_compare,
1210
- )
1211
- mcl.add(
1212
- ins_table_rxs(
1213
- r'^\s*PROMPT\s+ASK\s+"(?P<msg>(.|\n)*)"\s+SUB\s+(?P<match>~?\w+)\s+COMPARE\s+',
1214
- ins_table_rxs(
1215
- r"(?:\s+IN\s+(?P<alias1>\w+))?\s+(?P<orient>AND|BESIDE)\s+",
1216
- r'(?:\s+IN\s+(?P<alias2>\w+))?\s+(?:PK|KEY)\s*\((?P<pks>(("[A-Z_0-9]+")|[A-Z_0-9]+)'
1217
- r'(\s*,\s*(("[A-Z_0-9]+")|[A-Z_0-9]+))*)\)(?:\s+HELP\s+(?P<help>[^\s]+))?\s*$',
1218
- suffix="2",
1219
- ),
1220
- suffix="1",
1221
- ),
1222
- x_prompt_ask_compare,
1223
- )
1224
- mcl.add(
1225
- ins_table_rxs(
1226
- r'^\s*PROMPT\s+ASK\s+"(?P<msg>(.|\n)*)"\s+SUB\s+(?P<match>~?\w+)\s+COMPARE\s+',
1227
- ins_table_rxs(
1228
- r"(?:\s+IN\s+(?P<alias1>\w+))?\s+(?P<orient>AND|BESIDE)\s+",
1229
- r'(?:\s+IN\s+(?P<alias2>\w+))?\s+(?:PK|KEY)\s*\((?P<pks>(("[A-Z_0-9]+")|[A-Z_0-9]+)'
1230
- r'(\s*,\s*(("[A-Z_0-9]+")|[A-Z_0-9]+))*)\)(?:\s+HELP\s+"(?P<help>[^"]+)")?\s*$',
1231
- suffix="2",
1232
- ),
1233
- suffix="1",
1234
- ),
1235
- x_prompt_ask_compare,
1236
- )
1237
-
1238
- # ------------------------------------------------------------------
1239
- # PROMPT MAP
1240
- # ------------------------------------------------------------------
1241
- mcl.add(
1242
- ins_table_rxs(
1243
- r'^\s*PROMPT\s+MESSAGE\s+"(?P<message>(.|\n)*)"\s+MAP\s+',
1244
- r"\s*LAT\s+(?P<lat_col>\w+)\s+LON\s+(?P<lon_col>\w+)"
1245
- r"(?:\s+LABEL\s+(?P<label_col>\w+))?(?:\s+COLOR\s+(?P<color_col>\w+))?"
1246
- r"(?:\s+SYMBOL\s+(?P<symbol_col>\w+))?\s*$",
1247
- ),
1248
- x_prompt_map,
1249
- )
1250
- mcl.add(
1251
- ins_table_rxs(
1252
- r'^\s*PROMPT\s+MESSAGE\s+"(?P<message>(.|\n)*)"\s+MAP\s+',
1253
- r'\s*LAT\s+"(?P<lat_col>[\w+ ])"\s+LON\s+"(?P<lon_col>[\w+ ])"'
1254
- r'(?:\s+LABEL\s+"(?P<label_col>[\w+ ])")?(?:\s+COLOR\s+"(?P<color_col>[\w+ ])")?'
1255
- r'(?:\s+SYMBOL\s+"(?P<symbol_col>[\w+ ])")?\s*$',
1256
- ),
1257
- x_prompt_map,
1258
- )
1259
-
1260
- # ------------------------------------------------------------------
1261
- # EMAIL
1262
- # ------------------------------------------------------------------
1263
- mcl.add(
1264
- ins_fn_rxs(
1265
- ins_fn_rxs(
1266
- r"^\s*EMAIL\s+"
1267
- r"FROM\s+(?P<from>[A-Za-z0-9_\-\.!#$%&\'*+/=?^`{|}~]+@[A-Za-z0-9]+(-[A-Za-z0-9]+)*(\.[A-Za-z0-9]+)*)\s+"
1268
- r"TO\s+(?P<to>[A-Za-z0-9_\-\.!#$%&\'*+/=?^`{|}~]+@[A-Za-z0-9]+(-[A-Za-z0-9]+)*(\.[A-Za-z0-9]+)*"
1269
- r"([;,]\s*[A-Za-z0-9\-\.!#$%&\'*+/=?^`{|}~]+@[A-Za-z0-9]+(-[A-Za-z0-9]+)*(\.[A-Za-z0-9]+)*)*)\s+"
1270
- r'SUBJECT "(?P<subject>[^"]+)"\s+'
1271
- r'MESSAGE\s+"(?P<msg>[^"]*)"'
1272
- r"(\s+MESSAGE_FILE\s+",
1273
- r")?(\s+ATTACH(MEANT)?_FILE\s+",
1274
- "msg_file",
1275
- ),
1276
- r")?\s*$",
1277
- "att_file",
1278
- ),
1279
- x_email,
1280
- )
1281
-
1282
- # ------------------------------------------------------------------
1283
- # EXPORT_METADATA
1284
- # ------------------------------------------------------------------
1285
- mcl.add(
1286
- ins_fn_rxs(
1287
- ins_fn_rxs(
1288
- r"^\s*EXPORT_METADATA(?:\s+(?P<append>APPEND))?(?:\s+(?P<all>ALL))?\s+TO\s+",
1289
- r"(?:\s+IN\s+ZIPFILE\s+",
1290
- ),
1291
- r")?\s+AS\s+(?P<format>CSV|TAB|TSV|TABQ|TSVQ|TXT|TEXT)",
1292
- symbolicname="zipfilename",
1293
- ),
1294
- x_export_metadata,
1295
- )
1296
- mcl.add(
1297
- ins_table_rxs(
1298
- r"^\s*EXPORT_METADATA(?:\s+(?P<all>ALL))?\s+INTO(?:\s+(?P<new>NEW|REPLACEMENT))?\s+TABLE\s+",
1299
- r"\s*$",
1300
- ),
1301
- x_export_metadata_table,
1302
- )
1303
-
1304
- # ------------------------------------------------------------------
1305
- # SUB operations
1306
- # ------------------------------------------------------------------
1307
- mcl.add(r"^\s*SUB_EMPTY\s+(?P<match>[+~]?\w+)\s*$", x_sub_empty)
1308
- mcl.add(
1309
- r"^\s*SUB_ADD\s+(?P<match>[+~]?\w+)\s+(?P<increment>[+\-0-9\.*/() ]+)\s*$",
1310
- x_sub_add,
1311
- )
1312
- mcl.add(r"^\s*SUB_APPEND\s+(?P<match>[+~]?\w+)\s(?P<repl>(.|\n)*)$", x_sub_append)
1313
-
1314
- # ------------------------------------------------------------------
1315
- # IF / ORIF / ANDIF / ELSEIF / ELSE / ENDIF
1316
- # ------------------------------------------------------------------
1317
- mcl.add(r"^\s*ORIF\s*\(\s*(?P<condtest>.+)\s*\)\s*$", x_if_orif, run_when_false=True)
1318
- mcl.add(r"^\s*ELSEIF\s*\(\s*(?P<condtest>.+)\s*\)\s*$", x_if_elseif, run_when_false=True)
1319
- mcl.add(r"^\s*ANDIF\s*\(\s*(?P<condtest>.+)\s*\)\s*$", x_if_andif)
1320
- mcl.add(r"^\s*ELSE\s*$", x_if_else, run_when_false=True)
1321
- mcl.add(r"^\s*IF\s*\(\s*(?P<condtest>.+)\s*\)\s*{\s*(?P<condcmd>.+)\s*}\s*$", x_if)
1322
- mcl.add(r"^\s*IF\s*\(\s*(?P<condtest>.+)\s*\)\s*$", x_if_block, run_when_false=True)
1323
- mcl.add(r"^\s*ENDIF\s*$", x_if_end, run_when_false=True)
1324
-
1325
- # ------------------------------------------------------------------
1326
- # CONNECT — SQL Server
1327
- # ------------------------------------------------------------------
1328
- mcl.add(
1329
- (
1330
- r"^CONNECT\s+USER\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)\s*,\s*"
1331
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
1332
- 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*$",
1333
- r'^CONNECT\s+USER\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)"\s*,\s*'
1334
- r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\- ]*)"(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?'
1335
- 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*$",
1336
- ),
1337
- x_connect_user_ssvr,
1338
- )
1339
- mcl.add(
1340
- (
1341
- r"^CONNECT\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\/\\\-\.]*)\s*,\s*"
1342
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_~`!@#$%^&\*\+=\/\?\.-]*)"
1343
- r"\s*,\s*NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
1344
- r"(?:\s*,\s+PASSWORD\s*=\s*(?P<password>[^\s\)]+))?"
1345
- 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*$",
1346
- r'^CONNECT\s+TO\s+SQLSERVER\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\/\\\s\-\.]*)"\s*,\s*'
1347
- 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_~`!@#$%^&\*\+=\/\?\.-]*)'
1348
- r"\s*,\s*NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
1349
- r"(?:\s*,\s+PASSWORD\s*=\s*(?P<password>[^\s\)]+))?"
1350
- 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*$",
1351
- ),
1352
- x_connect_ssvr,
1353
- )
1354
-
1355
- # ------------------------------------------------------------------
1356
- # COPY QUERY / COPY
1357
- # ------------------------------------------------------------------
1358
- mcl.add(
1359
- ins_table_rxs(
1360
- r"^COPY QUERY\s+<<\s*(?P<query>.*;)\s*>>\s+FROM\s+(?P<alias1>[A-Z][A-Z0-9_]*)\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?",
1361
- r" IN\s+(?P<alias2>[A-Z][A-Z0-9_]*)\s*$",
1362
- ),
1363
- x_copy_query,
1364
- )
1365
- mcl.add(
1366
- (
1367
- r"^COPY\s+(?:(?P<schema1>[A-Z][A-Z0-9_\-\/\:]*)\.)?(?P<table1>[A-Z][A-Z0-9_\-\/\:]*)\s+FROM\s+(?P<alias1>[A-Z][A-Z0-9_]*)\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?(?:(?P<schema2>[A-Z][A-Z0-9_\-\/\:]*)\.)?(?P<table2>[A-Z][A-Z0-9_\-\/\:]*)\s+IN\s+(?P<alias2>[A-Z][A-Z0-9_]*)\s*$",
1368
- r'^COPY\s+(?:"(?P<schema1>[A-Z][A-Z0-9_\-\/\: ]*)"\.)?"(?P<table1>[A-Z][A-Z0-9_\-\/\: ]*)"\s+FROM\s+(?P<alias1>[A-Z][A-Z0-9_]*)\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?(?:"(?P<schema2>[A-Z][A-Z0-9_\-\/\:]*)"\.)?"(?P<table2>[A-Z][A-Z0-9_\-\/\:]*)"\s+IN\s+(?P<alias2>[A-Z][A-Z0-9_]*)\s*$',
1369
- r'^COPY\s+(?:(?P<schema1>[A-Z][A-Z0-9_\-\/\:]*)\.)?(?P<table1>[A-Z][A-Z0-9_\-\/\:]*)\s+FROM\s+(?P<alias1>[A-Z][A-Z0-9_]*)\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?(?:"(?P<schema2>[A-Z][A-Z0-9_\-\/\:]*)"\.)?"(?P<table2>[A-Z][A-Z0-9_\-\/\:]*)"\s+IN\s+(?P<alias2>[A-Z][A-Z0-9_]*)\s*$',
1370
- r'^COPY\s+(?:"(?P<schema1>[A-Z][A-Z0-9_\-\/\: ]*)"\.)?"(?P<table1>[A-Z][A-Z0-9_\-\/\: ]*)"\s+FROM\s+(?P<alias1>[A-Z][A-Z0-9_]*)\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?(?:(?P<schema2>[A-Z][A-Z0-9_\-\/\:]*)\.)?(?P<table2>[A-Z][A-Z0-9_\-\/\:]*)\s+IN\s+(?P<alias2>[A-Z][A-Z0-9_]*)\s*$',
1371
- r"^COPY\s+(?:\[(?P<schema1>[A-Z][A-Z0-9_\-\/\: ]*)\]\.)?\[(?P<table1>[A-Z][A-Z0-9_\-\/\: ]*)\]\s+FROM\s+(?P<alias1>[A-Z][A-Z0-9_]*)\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?(?:\[(?P<schema2>[A-Z][A-Z0-9_\-\/\:]*)\]\.)?\[(?P<table2>[A-Z][A-Z0-9_\-\/\:]*)\]\s+IN\s+(?P<alias2>[A-Z][A-Z0-9_]*)\s*$",
1372
- ),
1373
- x_copy,
1374
- )
1375
-
1376
- # ------------------------------------------------------------------
1377
- # APPEND/EXTEND SCRIPT
1378
- # ------------------------------------------------------------------
1379
- mcl.add(
1380
- r"\s*APPEND\s+SCRIPT\s+(?P<script1>\w+)\s+TO\s+(?P<script2>\w+)\s*$",
1381
- x_extendscript,
1382
- )
1383
- mcl.add(
1384
- r"\s*EXTEND\s+SCRIPT\s+(?P<script>\w+)\s+WITH\s+METACOMMAND\s+(?P<cmd>.+)\s*$",
1385
- x_extendscript_metacommand,
1386
- )
1387
- mcl.add(
1388
- r"\s*EXTEND\s+SCRIPT\s+(?P<script>\w+)\s+WITH\s+SQL\s+(?P<sql>.+;)\s*$",
1389
- x_extendscript_sql,
1390
- )
1391
-
1392
- # ------------------------------------------------------------------
1393
- # CONNECT — DuckDB / SQLite / PostgreSQL / MySQL
1394
- # ------------------------------------------------------------------
1395
- mcl.add(
1396
- ins_fn_rxs(
1397
- r"^CONNECT\s+TO\s+DUCKDB\s*\(\s*FILE\s*=\s*",
1398
- r"(?:\s*,\s*(?P<new>NEW))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
1399
- ),
1400
- x_connect_duckdb,
1401
- )
1402
- mcl.add(
1403
- ins_fn_rxs(
1404
- r"^CONNECT\s+TO\s+SQLITE\s*\(\s*FILE\s*=\s*",
1405
- r"(?:\s*,\s*(?P<new>NEW))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
1406
- ),
1407
- x_connect_sqlite,
1408
- )
1409
- mcl.add(
1410
- (
1411
- r"^CONNECT\s+USER\s+TO\s+POSTGRESQL\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)\s*,\s*"
1412
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
1413
- 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*$",
1414
- r'^CONNECT\s+USER\s+TO\s+POSTGRESQL\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)"\s*,\s*'
1415
- r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\-]*)"(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?'
1416
- 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*$",
1417
- ),
1418
- x_connect_user_pg,
1419
- )
1420
- mcl.add(
1421
- (
1422
- r"^CONNECT\s+TO\s+POSTGRESQL\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)\s*,\s*"
1423
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_\-@\.]*)\s*,\s*"
1424
- r"NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
1425
- r"(?:\s*,\s+PASSWORD\s*=\s*(?P<password>[^\s\)]+))?"
1426
- r"(?:\s*,\s*ENCODING\s*=\s*(?P<encoding>[A-Z][A-Z0-9_-]+))?(?:\s*,\s*(?P<new>NEW))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
1427
- r'^CONNECT\s+TO\s+POSTGRESQL\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)"\s*,\s*'
1428
- r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\-]*)"(?:\s*,\s*USER\s*=\s*"(?P<user>[A-Z][A-Z0-9_\-@\.]*)"\s*,\s*'
1429
- r"NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
1430
- r'(?:\s*,\s+PASSWORD\s*=\s*"(?P<password>[^\s\)]+)")?'
1431
- r"(?:\s*,\s*ENCODING\s*=\s*(?P<encoding>[A-Z][A-Z0-9_-]+))?(?:\s*,\s*(?P<new>NEW))?\s*\)\s+AS\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$",
1432
- ),
1433
- x_connect_pg,
1434
- )
1435
- mcl.add(
1436
- (
1437
- r"^CONNECT\s+USER\s+TO\s+MYSQL\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)\s*,\s*"
1438
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
1439
- 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*$",
1440
- r'^CONNECT\s+USER\s+TO\s+MYSQL\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)"\s*,\s*'
1441
- r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\-]*)"(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?'
1442
- 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*$",
1443
- r"^CONNECT\s+USER\s+TO\s+MARIADB\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)\s*,\s*"
1444
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
1445
- 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*$",
1446
- r'^CONNECT\s+USER\s+TO\s+MARIADB\s*\(\s*SERVER\s*=\s*"(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)"\s*,\s*'
1447
- r'DB\s*=\s*"(?P<db_name>[A-Z][A-Z0-9_\-]*)"(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?'
1448
- 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*$",
1449
- ),
1450
- x_connect_user_mysql,
1451
- )
1452
- mcl.add(
1453
- (
1454
- r"^CONNECT\s+TO\s+MYSQL\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)\s*,\s*"
1455
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_@\-\.]*)\s*,\s*"
1456
- r"NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
1457
- r"(?:\s*,\s+PASSWORD\s*=\s*(?P<password>[^\s]+))?"
1458
- 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*$",
1459
- r"^CONNECT\s+TO\s+MARIADB\s*\(\s*SERVER\s*=\s*(?P<server>[A-Z0-9][A-Z0-9_\-\.]*)\s*,\s*"
1460
- r"DB\s*=\s*(?P<db_name>[A-Z][A-Z0-9_\-]*)(?:\s*,\s*USER\s*=\s*(?P<user>[A-Z][A-Z0-9_&\-\.]*)\s*,\s*"
1461
- r"NEED_PWD\s*=\s*(?P<need_pwd>TRUE|FALSE))?(?:\s*,\s*PORT\s*=\s*(?P<port>\d+))?"
1462
- r"(?:\s*,\s+PASSWORD\s*=\s*(?P<password>[^\s]+))?"
1463
- 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*$",
1464
- ),
1465
- x_connect_mysql,
1466
- )
1467
-
1468
- # ------------------------------------------------------------------
1469
- # USE / CONNECT DSN
1470
- # ------------------------------------------------------------------
1471
- mcl.add(r"^USE\s+(?P<db_alias>[A-Z][A-Z0-9_]*)\s*$", x_use)
1472
-
1473
- # ------------------------------------------------------------------
1474
- # SYSTEM_CMD
1475
- # ------------------------------------------------------------------
1476
- mcl.add(
1477
- r"^\s*SYSTEM_CMD\s*\(\s*(?P<command>.+)\s*\)(?:\s+(?P<continue>CONTINUE))?\s*$",
1478
- x_system_cmd,
1479
- )
1480
-
1481
- # ------------------------------------------------------------------
1482
- # INCLUDE
1483
- # ------------------------------------------------------------------
1484
- mcl.add(ins_fn_rxs(r"^\s*INCLUDE(?P<exists>\s+IF\s+EXISTS?)?\s+", r"\s*$"), x_include)
1485
-
1486
- # ------------------------------------------------------------------
1487
- # IMPORT (CSV / delimited)
1488
- # ------------------------------------------------------------------
1489
- mcl.add(
1490
- ins_table_rxs(
1491
- r"^\s*IMPORT\s+TO\s+(?:(?P<new>NEW|REPLACEMENT)\s+)?",
1492
- ins_fn_rxs(
1493
- r"\s+FROM\s+",
1494
- r'(?:\s+WITH)?(?:\s+QUOTE\s+(?P<quotechar>NONE|\'|")\s+DELIMITER\s+'
1495
- r"(?P<delimchar>TAB|UNITSEP|US|,|;|\|))?(?:\s+ENCODING\s+(?P<encoding>\w+))?"
1496
- r"(?:\s+SKIP\s+(?P<skip>\d+))?\s*$",
1497
- ),
1498
- ),
1499
- x_import,
1500
- )
1501
-
1502
- # ------------------------------------------------------------------
1503
- # RM_FILE / RM_SUB
1504
- # ------------------------------------------------------------------
1505
- mcl.add(
1506
- (
1507
- r"^RM_FILE\s+(?P<filename>.+)\s*$",
1508
- r'^RM_FILE\s+"(?P<filename>.+)"\s*$',
1509
- ),
1510
- x_rm_file,
1511
- )
1512
- mcl.add(r"^\s*RM_SUB\s+(?P<match>~?\w+)\s*$", x_rm_sub)
1513
-
1514
- # ------------------------------------------------------------------
1515
- # SELECT_SUB / SUBDATA
1516
- # ------------------------------------------------------------------
1517
- mcl.add(r"^\s*SELECT_SUB\s+(?P<datasource>.+)\s*$", x_selectsub)
1518
- mcl.add(r"^\s*SUBDATA\s+(?P<match>[+~]?\w+)\s+(?P<datasource>.+)\s*$", x_subdata)
1519
-
1520
- # ------------------------------------------------------------------
1521
- # PROMPT ASK (simple)
1522
- # ------------------------------------------------------------------
1523
- mcl.add(
1524
- ins_table_rxs(
1525
- r'^\s*PROMPT\s+ASK\s+"(?P<question>[^"]+)"\s+SUB\s+(?P<match>~?\w+)(?:\s+DISPLAY\s+',
1526
- r')?(?:\s+HELP\s+"(?P<help>[^"]+)")?\s*$',
1527
- ),
1528
- x_prompt_ask,
1529
- )
1530
-
1531
- # ------------------------------------------------------------------
1532
- # PROMPT DISPLAY (table viewer)
1533
- # ------------------------------------------------------------------
1534
- mcl.add(
1535
- ins_table_rxs(
1536
- r'^\s*PROMPT\s+MESSAGE\s+"(?P<message>(.|\n)*)"\s+DISPLAY\s+',
1537
- r"(?:\s+HELP\s+(?P<help>[^\s]+))?(?:\s+(?P<free>FREE))?\s*$",
1538
- ),
1539
- x_prompt,
1540
- )
1541
- mcl.add(
1542
- ins_table_rxs(
1543
- r'^\s*PROMPT\s+MESSAGE\s+"(?P<message>(.|\n)*)"\s+DISPLAY\s+',
1544
- r'(?:\s+HELP\s+"(?P<help>[^"]+)")?(?:\s+(?P<free>FREE))?\s*$',
1545
- ),
1546
- x_prompt,
1547
- )
1548
- mcl.add(
1549
- ins_table_rxs(
1550
- r"^\s*PROMPT\s+DISPLAY\s+",
1551
- r'\s+MESSAGE\s+"(?P<message>(.|\n)*)"(?:\s+HELP\s+(?P<help>[^\s]+))?(?:\s+(?P<free>FREE))?\s*$',
1552
- ),
1553
- x_prompt,
1554
- )
1555
- mcl.add(
1556
- ins_table_rxs(
1557
- r"^\s*PROMPT\s+DISPLAY\s+",
1558
- r'\s+MESSAGE\s+"(?P<message>(.|\n)*)"(?:\s+HELP\s+"(?P<help>[^"]+)")?(?:\s+(?P<free>FREE))?\s*$',
1559
- ),
1560
- x_prompt,
1561
- )
1562
-
1563
- # ------------------------------------------------------------------
1564
- # PROMPT MESSAGE (simple message / MSG)
1565
- # ------------------------------------------------------------------
1566
- mcl.add(r'^\s*PROMPT(?:\s+MESSAGE)?\s+"(?P<message>(.|\n)*)"\s*$', x_msg)
1567
-
1568
- # ------------------------------------------------------------------
1569
- # WRITE
1570
- # ------------------------------------------------------------------
1571
- mcl.add(
1572
- ins_fn_rxs(
1573
- r'^\s*WRITE\s+"(?P<text>([^"]|\n)*)"(?:(?:\s+(?P<tee>TEE))?\s+TO\s+',
1574
- r")?\s*$",
1575
- ),
1576
- x_write,
1577
- )
215
+ # ---------------------------------------------------------------------------
216
+ # Export format constants — single source of truth.
217
+ # Used in dispatch table regex patterns and by io_export.py for validation.
218
+ # ---------------------------------------------------------------------------
219
+ DELIMITED_FORMATS = ["CSV", "TAB", "TSV", "TABQ", "TSVQ", "UNITSEP", "US"]
220
+ TEXT_FORMATS = ["TXT", "TXT-AND", "PLAIN"]
221
+ JSON_VARIANT_FORMATS = ["JSON_TS", "JSON_TABLESCHEMA"]
1578
222
 
1579
- # ------------------------------------------------------------------
1580
- # SUB (top-level variable assignment kept near end so more specific
1581
- # SUB_* patterns above take precedence)
1582
- # ------------------------------------------------------------------
1583
- mcl.add(
1584
- r"^\s*SUB\s+(?P<match>[+~]?\w+)\s+(?P<repl>.+)$",
1585
- x_sub,
1586
- "SUB",
1587
- "Define a string to match and a replacement for it.",
1588
- )
223
+ QUERY_EXPORT_FORMATS = (
224
+ DELIMITED_FORMATS + TEXT_FORMATS + ["ODS", "JSON", "HTML", "CGI-HTML", "VALUES", "LATEX", "RAW", "B64", "FEATHER"]
225
+ )
226
+ TABLE_EXPORT_FORMATS = (
227
+ DELIMITED_FORMATS
228
+ + TEXT_FORMATS
229
+ + ["JSON", "XML", "VALUES", "HTML", "CGI-HTML", "SQLITE", "DUCKDB", "LATEX", "RAW", "B64", "FEATHER", "HDF5"]
230
+ )
231
+ SERVE_FORMATS = ["BINARY", "CSV", "TXT", "TEXT", "ODS", "JSON", "HTML", "PDF", "ZIP"]
232
+ METADATA_FORMATS = ["CSV", "TAB", "TSV", "TABQ", "TSVQ", "TXT", "TEXT"]
233
+ ALL_EXPORT_FORMATS = sorted(
234
+ set(QUERY_EXPORT_FORMATS + TABLE_EXPORT_FORMATS + JSON_VARIANT_FORMATS),
235
+ )
1589
236
 
1590
- return mcl
237
+ DATABASE_TYPES = [
238
+ "POSTGRESQL",
239
+ "MYSQL",
240
+ "MARIADB",
241
+ "ORACLE",
242
+ "SQLSERVER",
243
+ "FIREBIRD",
244
+ "ACCESS",
245
+ "DUCKDB",
246
+ "SQLITE",
247
+ "DSN",
248
+ ]
1591
249
 
1592
250
 
1593
251
  # ---------------------------------------------------------------------------
1594
252
  # Module-level DISPATCH_TABLE — built once at import time.
1595
253
  # ---------------------------------------------------------------------------
254
+ from execsql.metacommands.dispatch import build_dispatch_table # noqa: E402
255
+
1596
256
  DISPATCH_TABLE = build_dispatch_table()