execsql2 2.17.2__py3-none-any.whl → 2.18.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 (52) hide show
  1. execsql/cli/__init__.py +13 -1
  2. execsql/cli/lint.py +16 -565
  3. execsql/cli/run.py +29 -2
  4. execsql/config.py +20 -0
  5. execsql/db/access.py +6 -0
  6. execsql/db/base.py +57 -1
  7. execsql/db/dsn.py +19 -9
  8. execsql/db/firebird.py +6 -0
  9. execsql/db/mysql.py +81 -0
  10. execsql/db/oracle.py +6 -0
  11. execsql/db/sqlite.py +37 -18
  12. execsql/db/sqlserver.py +31 -6
  13. execsql/exporters/base.py +1 -1
  14. execsql/exporters/duckdb.py +8 -4
  15. execsql/exporters/ods.py +11 -0
  16. execsql/exporters/sqlite.py +10 -3
  17. execsql/exporters/templates.py +10 -0
  18. execsql/exporters/xls.py +4 -0
  19. execsql/exporters/xlsx.py +9 -0
  20. execsql/importers/json.py +49 -32
  21. execsql/metacommands/conditions.py +7 -2
  22. execsql/metacommands/io_export.py +21 -26
  23. execsql/metacommands/io_fileops.py +21 -3
  24. execsql/metacommands/io_import.py +23 -3
  25. execsql/script/ast.py +8 -0
  26. execsql/script/engine.py +32 -0
  27. execsql/script/executor.py +12 -0
  28. execsql/script/variables.py +41 -15
  29. execsql/utils/auth.py +49 -1
  30. execsql/utils/fileio.py +120 -0
  31. execsql/utils/gui.py +11 -1
  32. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/md_compare.sql +12 -12
  33. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/md_glossary.sql +5 -5
  34. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/md_upsert.sql +13 -13
  35. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/pg_compare.sql +24 -24
  36. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/pg_glossary.sql +5 -5
  37. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/pg_upsert.sql +29 -29
  38. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/script_template.sql +2 -2
  39. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/ss_compare.sql +24 -24
  40. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/ss_glossary.sql +6 -6
  41. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/ss_upsert.sql +2917 -2917
  42. {execsql2-2.17.2.dist-info → execsql2-2.18.0.dist-info}/METADATA +8 -3
  43. {execsql2-2.17.2.dist-info → execsql2-2.18.0.dist-info}/RECORD +52 -52
  44. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/README.md +0 -0
  45. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/config_settings.sqlite +0 -0
  46. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
  47. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/execsql.conf +0 -0
  48. {execsql2-2.17.2.data → execsql2-2.18.0.data}/data/execsql2_extras/make_config_db.sql +0 -0
  49. {execsql2-2.17.2.dist-info → execsql2-2.18.0.dist-info}/WHEEL +0 -0
  50. {execsql2-2.17.2.dist-info → execsql2-2.18.0.dist-info}/entry_points.txt +0 -0
  51. {execsql2-2.17.2.dist-info → execsql2-2.18.0.dist-info}/licenses/LICENSE.txt +0 -0
  52. {execsql2-2.17.2.dist-info → execsql2-2.18.0.dist-info}/licenses/NOTICE +0 -0
execsql/utils/fileio.py CHANGED
@@ -84,6 +84,102 @@ def check_dir(filename: str) -> None:
84
84
  raise ErrInfo(type="error", other_msg=f"The directory for file '{filename}' does not exist.")
85
85
 
86
86
 
87
+ def check_zip_decompression_ratio(
88
+ path: str | os.PathLike[str],
89
+ *,
90
+ max_uncompressed_mb: int = 500,
91
+ max_ratio: int = 100,
92
+ ) -> None:
93
+ """Reject a zip-based workbook that looks like a decompression bomb.
94
+
95
+ OOXML (``.xlsx``) is a zip archive. A maliciously crafted file
96
+ can name a 1 GB uncompressed member that compresses to a few KB,
97
+ so blindly handing the path to ``openpyxl.load_workbook`` lets
98
+ the parser allocate proportional memory. This wrapper inspects
99
+ the zip directory entries before any parsing happens and raises
100
+ :class:`ErrInfo` when either bound is exceeded:
101
+
102
+ * ``max_uncompressed_mb`` — sum of all members' uncompressed
103
+ sizes (default 500 MB).
104
+ * ``max_ratio`` — per-member uncompressed:compressed ratio
105
+ (default 100:1; legitimate XML-heavy XLSX rarely exceeds 30:1).
106
+
107
+ No-op when *path* is not a zipfile (e.g. legacy ``.xls`` OLE-CDF).
108
+ """
109
+ import zipfile
110
+
111
+ try:
112
+ with zipfile.ZipFile(path) as zf:
113
+ total_uncompressed = 0
114
+ for info in zf.infolist():
115
+ total_uncompressed += info.file_size
116
+ if info.compress_size > 0:
117
+ ratio = info.file_size / info.compress_size
118
+ if ratio > max_ratio:
119
+ raise ErrInfo(
120
+ type="error",
121
+ other_msg=(
122
+ f"Refusing to open '{path}': member '{info.filename}' has "
123
+ f"compression ratio {ratio:.1f}:1 (limit {max_ratio}:1) - "
124
+ "possible zip-bomb."
125
+ ),
126
+ )
127
+ limit_bytes = max_uncompressed_mb * 1024 * 1024
128
+ if total_uncompressed > limit_bytes:
129
+ raise ErrInfo(
130
+ type="error",
131
+ other_msg=(
132
+ f"Refusing to open '{path}': total uncompressed size "
133
+ f"{total_uncompressed / 1024 / 1024:.0f} MB exceeds limit "
134
+ f"{max_uncompressed_mb} MB - possible zip-bomb."
135
+ ),
136
+ )
137
+ except zipfile.BadZipFile:
138
+ # Not a zip file (legacy .xls is OLE-CDF, not zip). Nothing to check.
139
+ pass
140
+
141
+
142
+ def safe_output_path(user_path: str, root: str | os.PathLike[str] | None) -> str:
143
+ """Resolve *user_path* and verify it lives under *root*.
144
+
145
+ If *root* is ``None`` or empty, returns *user_path* unchanged — the
146
+ caller has opted out of containment (current default behavior, no
147
+ regression for users who don't set the corresponding config key).
148
+
149
+ If *root* is set, *user_path* is joined to *root* (when relative) or
150
+ interpreted directly (when absolute), then ``.resolve()``'d and
151
+ verified to be at or below the resolved root. Absolute paths,
152
+ Windows drive letters, and UNC paths that don't fall under *root*
153
+ raise :class:`ErrInfo` rather than silently bypassing the
154
+ boundary.
155
+
156
+ Returns the resolved path as a string. Raises :class:`ErrInfo`
157
+ when *user_path* escapes *root*.
158
+ """
159
+ if not root:
160
+ return user_path
161
+ root_path = Path(root).expanduser().resolve()
162
+ candidate = Path(user_path).expanduser()
163
+ # Reject UNC paths (//server/share or \\server\share) when a root
164
+ # is set — these always escape a local root.
165
+ if user_path.startswith(("//", r"\\")):
166
+ raise ErrInfo(
167
+ type="error",
168
+ other_msg=f"Path '{user_path}' is outside the allowed root '{root_path}'.",
169
+ )
170
+ if not candidate.is_absolute():
171
+ candidate = root_path / candidate
172
+ resolved = candidate.resolve()
173
+ try:
174
+ resolved.relative_to(root_path)
175
+ except ValueError:
176
+ raise ErrInfo(
177
+ type="error",
178
+ other_msg=f"Path '{user_path}' resolves to '{resolved}', which is outside the allowed root '{root_path}'.",
179
+ ) from None
180
+ return str(resolved)
181
+
182
+
87
183
  class FileWriter(multiprocessing.Process):
88
184
  # An object of this class is intended to be used as a subprocess.
89
185
  # All files that are to be written to are kept open until explicitly closed or the object is destroyed.
@@ -449,6 +545,22 @@ class EncodedFile:
449
545
  def close(self) -> None:
450
546
  if self.fo is not None:
451
547
  self.fo.close()
548
+ self.fo = None
549
+
550
+ # B11/F049: context-manager protocol so callers can use ``with
551
+ # EncodedFile(...) as fh:`` and have the file closed automatically.
552
+ # The previous code required every site to remember an explicit
553
+ # close in a try/finally, which several call paths didn't do.
554
+ def __enter__(self) -> io.TextIOWrapper:
555
+ # Default to read mode when used directly as a context manager.
556
+ # Callers that need a different mode should call ``open(mode)``
557
+ # before entering the ``with`` block.
558
+ if self.fo is None:
559
+ self.open("r")
560
+ return self.fo
561
+
562
+ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
563
+ self.close()
452
564
 
453
565
 
454
566
  class Logger:
@@ -499,6 +611,14 @@ class Logger:
499
611
  errmsg = f"Can't open log file {self.log_file_name}"
500
612
  e = ErrInfo("exception", exception_msg=exception_desc(), other_msg=errmsg)
501
613
  exit_now(1, e, errmsg)
614
+ # B12/F017: tighten log file mode to 0o600 on POSIX. The log
615
+ # captures substituted SQL, -a values, env vars, and DSN URLs;
616
+ # the default umask (typically 022) leaves it world-readable.
617
+ if os.name == "posix":
618
+ try:
619
+ os.chmod(self.log_file_name, 0o600)
620
+ except Exception:
621
+ pass # Best-effort hardening; don't break logging if chmod fails.
502
622
  if not f_exists:
503
623
  self.writelog(
504
624
  "# Execsql log.\n# The first value on each line is the record type.\n"
execsql/utils/gui.py CHANGED
@@ -248,11 +248,21 @@ def enable_gui() -> None:
248
248
 
249
249
  framework = _state.conf.gui_framework if _state.conf else "tkinter"
250
250
 
251
+ # --- Headless POSIX guard ----------------------------------------------
252
+ # B20/F041: on POSIX without DISPLAY or WAYLAND_DISPLAY, Tkinter's
253
+ # ``tk.Tk()`` constructor raises a cryptic _tkinter.TclError. Skip
254
+ # straight to a non-GUI backend on headless systems so the fallback
255
+ # path is taken cleanly rather than after a confusing TclError that
256
+ # the broad ``except Exception`` would swallow.
257
+ import os as _os
258
+
259
+ headless_posix = _os.name == "posix" and not _os.environ.get("DISPLAY") and not _os.environ.get("WAYLAND_DISPLAY")
260
+
251
261
  # --- Tkinter sync path --------------------------------------------------
252
262
  # Tkinter must run on the main thread (required on macOS). Use a sync
253
263
  # queue that dispatches dialogs directly in the calling thread instead of
254
264
  # routing through a background manager thread.
255
- if framework == "tkinter":
265
+ if framework == "tkinter" and not headless_posix:
256
266
  try:
257
267
  from execsql.gui.desktop import TkinterBackend, _TkinterSyncQueue
258
268
 
@@ -114,7 +114,7 @@ inner join information_schema.key_column_usage as k
114
114
  and tc.table_name = k.table_name
115
115
  and tc.constraint_name = k.constraint_name
116
116
  where
117
- k.table_name = '!!#table!!'
117
+ k.table_name = !'!#table!'!
118
118
  and tc.constraint_schema = '!!$db_name!!'
119
119
  order by k.ordinal_position
120
120
  ;
@@ -137,8 +137,8 @@ from information_schema.columns as s
137
137
  inner join information_schema.columns as b on s.column_name=b.column_name
138
138
  left join cmp_primary_key_columns as pk on pk.column_name = s.column_name
139
139
  where
140
- s.table_name = '!!#stage_pfx!!!!#table!!'
141
- and b.table_name = '!!#table!!'
140
+ s.table_name = concat(!'!#stage_pfx!'!, !'!#table!'!)
141
+ and b.table_name = !'!#table!'!
142
142
  and pk.column_name is null
143
143
  !!~col_sel!!
144
144
  order by s.ordinal_position;
@@ -251,7 +251,7 @@ inner join information_schema.key_column_usage as k
251
251
  and tc.table_name = k.table_name
252
252
  and tc.constraint_name = k.constraint_name
253
253
  where
254
- k.table_name = '!!#table!!'
254
+ k.table_name = !'!#table!'!
255
255
  and tc.constraint_schema = '!!$db_name!!'
256
256
  order by k.ordinal_position
257
257
  ;
@@ -274,8 +274,8 @@ from information_schema.columns as s
274
274
  inner join information_schema.columns as b on s.column_name=b.column_name
275
275
  left join cmp_primary_key_columns as pk on pk.column_name = s.column_name
276
276
  where
277
- s.table_name = '!!#stage_pfx!!!!#table!!'
278
- and b.table_name = '!!#table!!'
277
+ s.table_name = concat(!'!#stage_pfx!'!, !'!#table!'!)
278
+ and b.table_name = !'!#table!'!
279
279
  and pk.column_name is null
280
280
  !!~col_sel!!
281
281
  order by s.ordinal_position;
@@ -391,7 +391,7 @@ inner join information_schema.key_column_usage as k
391
391
  and tc.table_name = k.table_name
392
392
  and tc.constraint_name = k.constraint_name
393
393
  where
394
- k.table_name = '!!#table!!'
394
+ k.table_name = !'!#table!'!
395
395
  and tc.constraint_schema = '!!$db_name!!'
396
396
  order by k.ordinal_position
397
397
  ;
@@ -415,8 +415,8 @@ from information_schema.columns as s
415
415
  inner join information_schema.columns as b on s.column_name=b.column_name
416
416
  left join cmp_primary_key_columns as pk on pk.column_name = s.column_name
417
417
  where
418
- s.table_name = '!!#stage_pfx!!!!#table!!'
419
- and b.table_name = '!!#table!!'
418
+ s.table_name = concat(!'!#stage_pfx!'!, !'!#table!'!)
419
+ and b.table_name = !'!#table!'!
420
420
  and pk.column_name is null
421
421
  !!~col_sel!!
422
422
  order by s.ordinal_position;
@@ -542,7 +542,7 @@ inner join information_schema.key_column_usage as k
542
542
  and tc.table_name = k.table_name
543
543
  and tc.constraint_name = k.constraint_name
544
544
  where
545
- k.table_name = '!!#table!!'
545
+ k.table_name = !'!#table!'!
546
546
  and tc.constraint_schema = '!!$db_name!!'
547
547
  order by k.ordinal_position
548
548
  ;
@@ -565,8 +565,8 @@ from information_schema.columns as s
565
565
  inner join information_schema.columns as b on s.column_name=b.column_name
566
566
  left join cmp_primary_key_columns as pk on pk.column_name = s.column_name
567
567
  where
568
- s.table_name = '!!#stage_pfx!!!!#table!!'
569
- and b.table_name = '!!#table!!'
568
+ s.table_name = concat(!'!#stage_pfx!'!, !'!#table!'!)
569
+ and b.table_name = !'!#table!'!
570
570
  and pk.column_name is null
571
571
  !!~col_sel!!
572
572
  order by s.ordinal_position;
@@ -146,7 +146,7 @@ with recursive itemtable as (
146
146
  select
147
147
  trim(substring_index(data, ',', 1)) as column_name,
148
148
  right(data, length(data) - locate(',', data, 1)) as data
149
- from (select '!!#column_list!!' as data) as input
149
+ from (select !'!#column_list!'! as data) as input
150
150
  union
151
151
  select
152
152
  trim(substring_index(data, ',', 1)) as column_name,
@@ -254,7 +254,7 @@ select !!gls_collist!! from gls_newglossary;
254
254
  select
255
255
  inp.item, inp.definition, inp.url
256
256
  from
257
- (select '!!#item!!'::text as item, '!!#definition!!'::text as definition, '!!#def_url!!'::text as url) as inp
257
+ (select !'!#item!'!::text as item, !'!#definition!'!::text as definition, !'!#def_url!'!::text as url) as inp
258
258
  left join gls_glossary as g on g.!!gls_name!! = inp.item
259
259
  where
260
260
  g.!!gls_name!! is null;
@@ -264,8 +264,8 @@ select !!gls_collist!! from gls_newglossary;
264
264
  inp.item, inp.definition
265
265
  from
266
266
  (select
267
- cast('!!#item!!' as varchar(255)) as item,
268
- cast('!!#definition!!' as varchar(255)) as definition
267
+ cast(!'!#item!'! as varchar(255)) as item,
268
+ cast(!'!#definition!'! as varchar(255)) as definition
269
269
  ) as inp
270
270
  left join gls_glossary as g on g.!!gls_name!! = inp.item
271
271
  where
@@ -307,7 +307,7 @@ select
307
307
  from
308
308
  information_schema.columns
309
309
  where
310
- table_name = '!!#table!!'
310
+ table_name = !'!#table!'!
311
311
  ;
312
312
  -- !x! subdata ~collist gls_collist
313
313
 
@@ -182,12 +182,12 @@ from
182
182
  (
183
183
  select
184
184
  'base' as schema_type,
185
- '!!#table!!' as table_name
185
+ !'!#table!'! as table_name
186
186
  union
187
187
  select
188
188
 
189
189
  'staging' as schema_type,
190
- '!!#stage_pfx!!!!#table!!' as table_name
190
+ concat(!'!#stage_pfx!'!, !'!#table!'!) as table_name
191
191
  ) as tt
192
192
  left join information_schema.tables as iss on tt.table_name=iss.table_name
193
193
  where
@@ -276,7 +276,7 @@ where
276
276
  update ups_validate_control as vc, information_schema.tables as st
277
277
  set vc.staging_exists = True
278
278
  where
279
- st.table_name= concat('!!#stage_pfx!!', vc.table_name)
279
+ st.table_name= concat(!'!#stage_pfx!'!, vc.table_name)
280
280
  and st.table_type='BASE TABLE'
281
281
  and st.table_schema = '!!$DB_NAME!!'
282
282
  ;
@@ -293,7 +293,7 @@ from
293
293
  from ups_validate_control
294
294
  where not base_exists
295
295
  union
296
- select concat('!!#stage_pfx!!', table_name) as schema_table
296
+ select concat(!'!#stage_pfx!'!, table_name) as schema_table
297
297
  from ups_validate_control
298
298
  where not staging_exists
299
299
  ) as it
@@ -427,7 +427,7 @@ with recursive itemtable as (
427
427
  select
428
428
  trim(substring_index(data, ',', 1)) as table_name,
429
429
  right(data, length(data) - locate(',', data, 1)) as data
430
- from (select '!!#table_list!!' as data) as input
430
+ from (select !'!#table_list!'! as data) as input
431
431
  union
432
432
  select
433
433
  trim(substring_index(data, ',', 1)) as table_name,
@@ -624,7 +624,7 @@ from
624
624
  information_schema.columns
625
625
  where
626
626
  table_schema = '!!$DB_NAME!!'
627
- and table_name = '!!#table!!'
627
+ and table_name = !'!#table!'!
628
628
  and is_nullable = 'NO'
629
629
  and column_default is null
630
630
  !!~omitnull!!
@@ -783,7 +783,7 @@ inner join information_schema.key_column_usage as k
783
783
  and tc.table_name = k.table_name
784
784
  and tc.constraint_name = k.constraint_name
785
785
  where
786
- k.table_name = '!!#table!!'
786
+ k.table_name = !'!#table!'!
787
787
  and tc.constraint_schema = '!!$db_name!!'
788
788
  order by k.ordinal_position
789
789
  ;
@@ -998,7 +998,7 @@ from
998
998
  ups_foreign_key_columns
999
999
  where
1000
1000
  table_schema = '!!$DB_NAME!!'
1001
- and table_name = '!!#table!!';
1001
+ and table_name = !'!#table!'!;
1002
1002
 
1003
1003
  -- Create a table of all unique constraint names for
1004
1004
  -- this table, with an integer column to be populated with the
@@ -1257,7 +1257,7 @@ create table ups_cols
1257
1257
  select column_name
1258
1258
  from information_schema.columns
1259
1259
  where
1260
- table_name = '!!#stage_pfx!!!!#table!!'
1260
+ table_name = concat(!'!#stage_pfx!'!, !'!#table!'!)
1261
1261
  and table_schema = '!!$DB_NAME!!'
1262
1262
  !!~col_excl!!
1263
1263
  order by ordinal_position;
@@ -1280,7 +1280,7 @@ inner join information_schema.key_column_usage as k
1280
1280
  and tc.table_name = k.table_name
1281
1281
  and tc.constraint_name = k.constraint_name
1282
1282
  where
1283
- k.table_name = '!!#table!!'
1283
+ k.table_name = !'!#table!'!
1284
1284
  and k.table_schema = '!!$DB_NAME!!'
1285
1285
  order by k.ordinal_position;
1286
1286
 
@@ -2103,7 +2103,7 @@ inner join information_schema.key_column_usage as k
2103
2103
  and tc.table_name = k.table_name
2104
2104
  and tc.constraint_name = k.constraint_name
2105
2105
  where
2106
- k.table_name = '!!#table!!'
2106
+ k.table_name = !'!#table!'!
2107
2107
  and k.table_schema = '!!$DB_NAME!!'
2108
2108
  ;
2109
2109
 
@@ -2335,7 +2335,7 @@ where
2335
2335
  from information_schema.columns
2336
2336
  where
2337
2337
  table_schema = '!!$DB_NAME!!'
2338
- and table_name = '!!#stage_pfx!!!!#table!!'
2338
+ and table_name = concat(!'!#stage_pfx!'!, !'!#table!'!)
2339
2339
  ) as stag on pk.newpk_col=stag.column_name
2340
2340
  where
2341
2341
  stag.column_name is null
@@ -2731,7 +2731,7 @@ where
2731
2731
  and cu_uq.table_name = tc_uq.table_name
2732
2732
  and cu_uq.ordinal_position = cu.ordinal_position
2733
2733
  where
2734
- rc.table_name = '!!#table!!'
2734
+ rc.table_name = !'!#table!'!
2735
2735
  ;
2736
2736
 
2737
2737
  -- Narrow the list down to ONLY dependencies that affect PK columns
@@ -118,8 +118,8 @@ inner join information_schema.key_column_usage as k
118
118
  and tc.table_name = k.table_name
119
119
  and tc.constraint_name = k.constraint_name
120
120
  where
121
- k.table_name = '!!#table!!'
122
- and k.table_schema = '!!#base_schema!!'
121
+ k.table_name = !'!#table!'!
122
+ and k.table_schema = !'!#base_schema!'!
123
123
  order by k.ordinal_position
124
124
  ;
125
125
 
@@ -141,10 +141,10 @@ from information_schema.columns as s
141
141
  inner join information_schema.columns as b on s.column_name=b.column_name
142
142
  left join cmp_primary_key_columns as pk on pk.column_name = s.column_name
143
143
  where
144
- s.table_schema = '!!#staging!!'
145
- and s.table_name = '!!#table!!'
146
- and b.table_schema = '!!#base_schema!!'
147
- and b.table_name = '!!#table!!'
144
+ s.table_schema = !'!#staging!'!
145
+ and s.table_name = !'!#table!'!
146
+ and b.table_schema = !'!#base_schema!'!
147
+ and b.table_name = !'!#table!'!
148
148
  and pk.column_name is null
149
149
  !!~col_sel!!
150
150
  order by s.ordinal_position;
@@ -255,8 +255,8 @@ inner join information_schema.key_column_usage as k
255
255
  and tc.table_name = k.table_name
256
256
  and tc.constraint_name = k.constraint_name
257
257
  where
258
- k.table_name = '!!#table!!'
259
- and k.table_schema = '!!#base_schema!!'
258
+ k.table_name = !'!#table!'!
259
+ and k.table_schema = !'!#base_schema!'!
260
260
  order by k.ordinal_position
261
261
  ;
262
262
 
@@ -278,10 +278,10 @@ from information_schema.columns as s
278
278
  inner join information_schema.columns as b on s.column_name=b.column_name
279
279
  left join cmp_primary_key_columns as pk on pk.column_name = s.column_name
280
280
  where
281
- s.table_schema = '!!#staging!!'
282
- and s.table_name = '!!#table!!'
283
- and b.table_schema = '!!#base_schema!!'
284
- and b.table_name = '!!#table!!'
281
+ s.table_schema = !'!#staging!'!
282
+ and s.table_name = !'!#table!'!
283
+ and b.table_schema = !'!#base_schema!'!
284
+ and b.table_name = !'!#table!'!
285
285
  and pk.column_name is null
286
286
  !!~col_sel!!
287
287
  order by s.ordinal_position;
@@ -393,8 +393,8 @@ inner join information_schema.key_column_usage as k
393
393
  and tc.table_name = k.table_name
394
394
  and tc.constraint_name = k.constraint_name
395
395
  where
396
- k.table_name = '!!#table!!'
397
- and k.table_schema = '!!#base_schema!!'
396
+ k.table_name = !'!#table!'!
397
+ and k.table_schema = !'!#base_schema!'!
398
398
  order by k.ordinal_position
399
399
  ;
400
400
 
@@ -416,10 +416,10 @@ from information_schema.columns as s
416
416
  inner join information_schema.columns as b on s.column_name=b.column_name
417
417
  left join cmp_primary_key_columns as pk on pk.column_name = s.column_name
418
418
  where
419
- s.table_schema = '!!#staging!!'
420
- and s.table_name = '!!#table!!'
421
- and b.table_schema = '!!#base_schema!!'
422
- and b.table_name = '!!#table!!'
419
+ s.table_schema = !'!#staging!'!
420
+ and s.table_name = !'!#table!'!
421
+ and b.table_schema = !'!#base_schema!'!
422
+ and b.table_name = !'!#table!'!
423
423
  !!~col_sel!!
424
424
  order by s.ordinal_position;
425
425
 
@@ -540,8 +540,8 @@ inner join information_schema.key_column_usage as k
540
540
  and tc.table_name = k.table_name
541
541
  and tc.constraint_name = k.constraint_name
542
542
  where
543
- k.table_name = '!!#table!!'
544
- and k.table_schema = '!!#base_schema!!'
543
+ k.table_name = !'!#table!'!
544
+ and k.table_schema = !'!#base_schema!'!
545
545
  order by k.ordinal_position
546
546
  ;
547
547
 
@@ -563,10 +563,10 @@ from information_schema.columns as s
563
563
  inner join information_schema.columns as b on s.column_name=b.column_name
564
564
  left join cmp_primary_key_columns as pk on pk.column_name = s.column_name
565
565
  where
566
- s.table_schema = '!!#staging!!'
567
- and s.table_name = '!!#table!!'
568
- and b.table_schema = '!!#base_schema!!'
569
- and b.table_name = '!!#table!!'
566
+ s.table_schema = !'!#staging!'!
567
+ and s.table_name = !'!#table!'!
568
+ and b.table_schema = !'!#base_schema!'!
569
+ and b.table_name = !'!#table!'!
570
570
  !!~col_sel!!
571
571
  order by s.ordinal_position;
572
572
 
@@ -134,7 +134,7 @@ from gls_glossary order by !!gls_name!!;
134
134
 
135
135
  drop table if exists gls_column_list cascade;
136
136
  select
137
- trim(regexp_split_to_table('!!#column_list!!', E'\\s*,\\s*')) as !!gls_name!!
137
+ trim(regexp_split_to_table(!'!#column_list!'!, E'\\s*,\\s*')) as !!gls_name!!
138
138
  into
139
139
  gls_column_list;
140
140
 
@@ -220,7 +220,7 @@ drop table gls_newglossary cascade;
220
220
  select
221
221
  inp.item, inp.definition, inp.url
222
222
  from
223
- (select '!!#item!!'::text as item, '!!#definition!!'::text as definition, '!!#def_url!!'::text as url) as inp
223
+ (select !'!#item!'!::text as item, !'!#definition!'!::text as definition, !'!#def_url!'!::text as url) as inp
224
224
  left join gls_glossary as g on g.!!gls_name!! = inp.item
225
225
  where
226
226
  g.!!gls_name!! is null;
@@ -229,7 +229,7 @@ drop table gls_newglossary cascade;
229
229
  select
230
230
  inp.item, inp.definition
231
231
  from
232
- (select '!!#item!!'::text as item, '!!#definition!!'::text as definition) as inp
232
+ (select !'!#item!'!::text as item, !'!#definition!'!::text as definition) as inp
233
233
  left join gls_glossary as g on g.!!gls_name!! = inp.item
234
234
  where
235
235
  g.!!gls_name!! is null;
@@ -265,7 +265,7 @@ drop table gls_newglossary cascade;
265
265
  -- !x! if(is_null("!!#schema!!"))
266
266
  -- !x! sub_empty ~schema_sel
267
267
  -- !x! else
268
- -- !x! sub ~schema_sel and table_schema = '!!#schema!!'
268
+ -- !x! sub ~schema_sel and table_schema = !'!#schema!'!
269
269
  -- !x! endif
270
270
  drop view if exists gls_collist cascade;
271
271
  create temporary view gls_collist as
@@ -274,7 +274,7 @@ select
274
274
  from
275
275
  information_schema.columns
276
276
  where
277
- table_name = '!!#table!!'
277
+ table_name = !'!#table!'!
278
278
  !!~schema_sel!!
279
279
  ;
280
280
  -- !x! subdata ~collist gls_collist