execsql2 2.30.0__py3-none-any.whl → 2.31.1__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 (48) hide show
  1. execsql/api.py +1 -0
  2. execsql/cli/application.py +1 -1
  3. execsql/cli/commands/lint.py +1 -1
  4. execsql/cli/dsn.py +35 -1
  5. execsql/cli/lint.py +10 -1
  6. execsql/cli/run.py +8 -3
  7. execsql/config.py +26 -4
  8. execsql/data/execsql.conf.template +8 -2
  9. execsql/db/access.py +7 -5
  10. execsql/db/base.py +18 -0
  11. execsql/db/factory.py +11 -1
  12. execsql/db/mysql.py +56 -3
  13. execsql/db/odbc.py +45 -0
  14. execsql/db/postgres.py +1 -1
  15. execsql/db/sqlserver.py +37 -21
  16. execsql/exporters/ods.py +146 -41
  17. execsql/exporters/values.py +166 -9
  18. execsql/importers/base.py +1 -1
  19. execsql/importers/csv.py +1 -1
  20. execsql/importers/ods.py +2 -0
  21. execsql/lsp/diagnostics.py +1 -1
  22. execsql/lsp/document.py +3 -0
  23. execsql/metacommands/io_fileops.py +11 -5
  24. execsql/metacommands/reference.py +1 -1
  25. execsql/metacommands/upsert.py +10 -1
  26. execsql/utils/auth.py +21 -14
  27. execsql/utils/errors.py +1 -1
  28. execsql/utils/paths.py +31 -0
  29. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/README.md +9 -8
  30. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/md_compare.sql +53 -29
  31. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/md_glossary.sql +20 -20
  32. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/md_upsert.sql +59 -66
  33. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/pg_compare.sql +19 -22
  34. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/pg_glossary.sql +13 -17
  35. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/script_template.sql +302 -299
  36. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/ss_compare.sql +39 -29
  37. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/ss_glossary.sql +13 -17
  38. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/ss_upsert.sql +56 -66
  39. {execsql2-2.30.0.dist-info → execsql2-2.31.1.dist-info}/METADATA +17 -41
  40. {execsql2-2.30.0.dist-info → execsql2-2.31.1.dist-info}/RECORD +47 -46
  41. execsql2-2.30.0.data/data/execsql2_extras/pg_upsert.sql +0 -2791
  42. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/config_settings.sqlite +0 -0
  43. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
  44. {execsql2-2.30.0.data → execsql2-2.31.1.data}/data/execsql2_extras/make_config_db.sql +0 -0
  45. {execsql2-2.30.0.dist-info → execsql2-2.31.1.dist-info}/WHEEL +0 -0
  46. {execsql2-2.30.0.dist-info → execsql2-2.31.1.dist-info}/entry_points.txt +0 -0
  47. {execsql2-2.30.0.dist-info → execsql2-2.31.1.dist-info}/licenses/LICENSE.txt +0 -0
  48. {execsql2-2.30.0.dist-info → execsql2-2.31.1.dist-info}/licenses/NOTICE +0 -0
@@ -30,8 +30,9 @@
30
30
  -- begin with "cmp_".
31
31
  -- 4. This script requires SQL Server 2017 or later.
32
32
  --
33
- -- AUTHOR
33
+ -- AUTHORS
34
34
  -- Dreas Nielsen (RDN)
35
+ -- Caleb Grant (CG)
35
36
  --
36
37
  -- COPYRIGHT AND LICENSE
37
38
  -- Copyright (c) 2020 R.Dreas Nielsen
@@ -46,20 +47,25 @@
46
47
  -- The GNU General Public License is available at <http://www.gnu.org/licenses/>
47
48
  --
48
49
  -- VERSION
49
- -- 1.1.1
50
+ -- 1.2.0
50
51
  --
51
52
  -- HISTORY
52
53
  -- Date Remarks
53
54
  -- ---------- -----------------------------------------------------
54
55
  -- 2020-02-29 Created from v. 1.1.1 for Postgres. RDN.
55
56
  -- 2020-03-01 Modified for SQL Server. RDN.
57
+ -- 2026-10-15 execsql2: text values compare case- and accent-sensitively (the
58
+ -- default collation reported 'y' -> 'Y' as unchanged); each
59
+ -- script's notes are its docstring; include_cols and exclude_cols
60
+ -- are declared optional parameters. v. 1.2.0. Tested in
61
+ -- tests/templates of the execsql2 repository. CG.
56
62
  -- ==================================================================
57
63
 
58
64
 
59
65
  -- ################################################################
60
66
  -- Script COMPARE_COMMON
61
67
  -- ===============================================================
62
- --
68
+ -- !x! BEGIN SCRIPT COMPARE_COMMON with parameters (base_schema, staging, table, sql_var, include_cols="", exclude_cols="")
63
69
  -- Generate SQL to compare the attributes of base and staging
64
70
  -- tables for only those primary keys in common. This uses an
65
71
  -- inner join between the tables, and does not include any rows
@@ -100,8 +106,6 @@
100
106
  --
101
107
  -- Notes
102
108
  -- 1. The generated SQL is not terminated with a semicolon.
103
- -- ===============================================================
104
- -- !x! BEGIN SCRIPT COMPARE_COMMON with parameters (base_schema, staging, table, sql_var)
105
109
 
106
110
  -- Create a table of primary key columns for the table
107
111
  if object_id('tempdb..#cmp_primary_key_columns') is not null drop table #cmp_primary_key_columns;
@@ -128,13 +132,16 @@ order by k.ordinal_position
128
132
  -- that are to be compared.
129
133
  -- Include only those columns from the staging table that are also in the base table.
130
134
  -- !x! sub_empty ~col_sel
131
- -- !x! if(sub_defined(#include_cols))
135
+ -- !x! if(not is_null("!!#include_cols!!"))
132
136
  -- !x! sub ~col_sel and s.column_name in (!!#include_cols!!)
133
- -- !x! elseif(sub_defined(#exclude_cols))
137
+ -- !x! elseif(not is_null("!!#exclude_cols!!"))
134
138
  -- !x! sub ~col_sel and s.column_name not in (!!#exclude_cols!!)
135
139
  -- !x! endif
136
140
  if object_id('tempdb..#cmp_cols') is not null drop table #cmp_cols;
137
- select s.column_name
141
+ select
142
+ s.column_name,
143
+ -- Text compares case- and accent-sensitively below; the default collation does not.
144
+ case when s.data_type in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext') and b.data_type in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext') then 1 else 0 end as is_text
138
145
  into #cmp_cols
139
146
  from information_schema.columns as s
140
147
  inner join information_schema.columns as b on s.column_name=b.column_name
@@ -163,7 +170,7 @@ from
163
170
  alter table #cmp_cols add sqlcmd varchar(max);
164
171
  update #cmp_cols
165
172
  set sqlcmd =
166
- 'case when b.' + column_name + ' is null then case when s.' + column_name + ' is null then ''Same'' else ''New'' end else case when s.' + column_name + ' is null then ''Old'' else case when b.' + column_name + ' = s.' + column_name + ' then ''Same'' else ''Different'' end end end as ' + column_name
173
+ 'case when b.' + column_name + ' is null then case when s.' + column_name + ' is null then ''Same'' else ''New'' end else case when s.' + column_name + ' is null then ''Old'' else case when b.' + column_name + ' = s.' + column_name + case when is_text = 1 then ' collate Latin1_General_BIN2' else '' end + ' then ''Same'' else ''Different'' end end end as ' + column_name
167
174
  ;
168
175
 
169
176
  -- Create the comparison expression for all columns.
@@ -203,7 +210,7 @@ from
203
210
  -- ################################################################
204
211
  -- Script COMPARE_COMMON_VALS
205
212
  -- ===============================================================
206
- --
213
+ -- !x! BEGIN SCRIPT COMPARE_COMMON_VALS with parameters (base_schema, staging, table, sql_var, include_cols="", exclude_cols="")
207
214
  -- Generate SQL to compare the attributes of base and staging
208
215
  -- tables for only those primary keys in common. This uses an
209
216
  -- inner join between the tables, and does not include any rows
@@ -240,8 +247,6 @@ from
240
247
  --
241
248
  -- Notes
242
249
  -- 1. The generated SQL is not terminated with a semicolon.
243
- -- ===============================================================
244
- -- !x! BEGIN SCRIPT COMPARE_COMMON_VALS with parameters (base_schema, staging, table, sql_var)
245
250
 
246
251
  -- Create a table of primary key columns for the table
247
252
  if object_id('tempdb..#cmp_primary_key_columns') is not null drop table #cmp_primary_key_columns;
@@ -268,13 +273,16 @@ order by k.ordinal_position
268
273
  -- that are to be compared.
269
274
  -- Include only those columns from the staging table that are also in the base table.
270
275
  -- !x! sub_empty ~col_sel
271
- -- !x! if(sub_defined(#include_cols))
276
+ -- !x! if(not is_null("!!#include_cols!!"))
272
277
  -- !x! sub ~col_sel and s.column_name in (!!#include_cols!!)
273
- -- !x! elseif(sub_defined(#exclude_cols))
278
+ -- !x! elseif(not is_null("!!#exclude_cols!!"))
274
279
  -- !x! sub ~col_sel and s.column_name not in (!!#exclude_cols!!)
275
280
  -- !x! endif
276
281
  if object_id('tempdb..#cmp_cols') is not null drop table #cmp_cols;
277
- select s.column_name
282
+ select
283
+ s.column_name,
284
+ -- Text compares case- and accent-sensitively below; the default collation does not.
285
+ case when s.data_type in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext') and b.data_type in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext') then 1 else 0 end as is_text
278
286
  into #cmp_cols
279
287
  from information_schema.columns as s
280
288
  inner join information_schema.columns as b on s.column_name=b.column_name
@@ -345,7 +353,7 @@ from
345
353
  -- ################################################################
346
354
  -- Script COMPARE_CHANGES
347
355
  -- ===============================================================
348
- --
356
+ -- !x! BEGIN SCRIPT COMPARE_CHANGES with parameters (base_schema, staging, table, sql_var, include_cols="", exclude_cols="")
349
357
  -- Generate SQL to characterize every row of the staging table
350
358
  -- data as either a new row, a row with changed data, or a row
351
359
  -- with data that are unchanged relative to the base table.
@@ -381,8 +389,6 @@ from
381
389
  --
382
390
  -- Notes
383
391
  -- 1. The generated SQL is not terminated with a semicolon.
384
- -- ===============================================================
385
- -- !x! BEGIN SCRIPT COMPARE_CHANGES with parameters (base_schema, staging, table, sql_var)
386
392
 
387
393
  -- Create a table of primary key columns for the table
388
394
  if object_id('tempdb..#cmp_primary_key_columns') is not null drop table #cmp_primary_key_columns;
@@ -409,13 +415,16 @@ order by k.ordinal_position
409
415
  -- that are to be compared.
410
416
  -- Include only those columns from the staging table that are also in the base table.
411
417
  -- !x! sub_empty ~col_sel
412
- -- !x! if(sub_defined(#include_cols))
418
+ -- !x! if(not is_null("!!#include_cols!!"))
413
419
  -- !x! sub ~col_sel and s.column_name in (!!#include_cols!!)
414
- -- !x! elseif(sub_defined(#exclude_cols))
420
+ -- !x! elseif(not is_null("!!#exclude_cols!!"))
415
421
  -- !x! sub ~col_sel and s.column_name not in (!!#exclude_cols!!)
416
422
  -- !x! endif
417
423
  if object_id('tempdb..#cmp_cols') is not null drop table #cmp_cols;
418
- select s.column_name
424
+ select
425
+ s.column_name,
426
+ -- Text compares case- and accent-sensitively below; the default collation does not.
427
+ case when s.data_type in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext') and b.data_type in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext') then 1 else 0 end as is_text
419
428
  into #cmp_cols
420
429
  from information_schema.columns as s
421
430
  inner join information_schema.columns as b on s.column_name=b.column_name
@@ -444,7 +453,7 @@ from
444
453
  alter table #cmp_cols add sqlcmd varchar(max);
445
454
  update #cmp_cols
446
455
  set sqlcmd =
447
- 'case when b.' + column_name + ' is null then case when s.' + column_name + ' is null then 0 else 1 end else case when s.' + column_name + ' is null then 1 else case when b.' + column_name + ' = s.' + column_name + ' then 0 else 1 end end end'
456
+ 'case when b.' + column_name + ' is null then case when s.' + column_name + ' is null then 0 else 1 end else case when s.' + column_name + ' is null then 1 else case when b.' + column_name + ' = s.' + column_name + case when is_text = 1 then ' collate Latin1_General_BIN2' else '' end + ' then 0 else 1 end end end'
448
457
  ;
449
458
 
450
459
  -- Create the expression to determine whether there is a difference for any column.
@@ -494,7 +503,7 @@ from
494
503
  -- ################################################################
495
504
  -- Script COMPARE_CHANGED
496
505
  -- ===============================================================
497
- --
506
+ -- !x! BEGIN SCRIPT COMPARE_CHANGED with parameters (base_schema, staging, table, sql_var, include_cols="", exclude_cols="")
498
507
  -- Generate SQL to characterize every row of the base table
499
508
  -- depending on whether there is a matching row in the staging
500
509
  -- table, whether a matching row has new data, or whether a
@@ -531,8 +540,6 @@ from
531
540
  --
532
541
  -- Notes
533
542
  -- 1. The generated SQL is not terminated with a semicolon.
534
- -- ===============================================================
535
- -- !x! BEGIN SCRIPT COMPARE_CHANGED with parameters (base_schema, staging, table, sql_var)
536
543
 
537
544
  -- Create a table of primary key columns for the table
538
545
  if object_id('tempdb..#cmp_primary_key_columns') is not null drop table #cmp_primary_key_columns;
@@ -559,13 +566,16 @@ order by k.ordinal_position
559
566
  -- that are to be compared.
560
567
  -- Include only those columns from the staging table that are also in the base table.
561
568
  -- !x! sub_empty ~col_sel
562
- -- !x! if(sub_defined(#include_cols))
569
+ -- !x! if(not is_null("!!#include_cols!!"))
563
570
  -- !x! sub ~col_sel and s.column_name in (!!#include_cols!!)
564
- -- !x! elseif(sub_defined(#exclude_cols))
571
+ -- !x! elseif(not is_null("!!#exclude_cols!!"))
565
572
  -- !x! sub ~col_sel and s.column_name not in (!!#exclude_cols!!)
566
573
  -- !x! endif
567
574
  if object_id('tempdb..#cmp_cols') is not null drop table #cmp_cols;
568
- select s.column_name
575
+ select
576
+ s.column_name,
577
+ -- Text compares case- and accent-sensitively below; the default collation does not.
578
+ case when s.data_type in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext') and b.data_type in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext') then 1 else 0 end as is_text
569
579
  into #cmp_cols
570
580
  from information_schema.columns as s
571
581
  inner join information_schema.columns as b on s.column_name=b.column_name
@@ -594,7 +604,7 @@ from
594
604
  alter table #cmp_cols add sqlcmd varchar(max);
595
605
  update #cmp_cols
596
606
  set sqlcmd =
597
- 'case when b.' + column_name + ' is null then case when s.' + column_name + ' is null then 0 else 1 end else case when s.' + column_name + ' is null then 1 else case when b.' + column_name + ' = s.' + column_name + ' then 0 else 1 end end end'
607
+ 'case when b.' + column_name + ' is null then case when s.' + column_name + ' is null then 0 else 1 end else case when s.' + column_name + ' is null then 1 else case when b.' + column_name + ' = s.' + column_name + case when is_text = 1 then ' collate Latin1_General_BIN2' else '' end + ' then 0 else 1 end end end'
598
608
  ;
599
609
 
600
610
  -- Create the expression to determine whether there is a difference for any column.
@@ -37,9 +37,10 @@
37
37
  -- AUTHORS
38
38
  -- Dreas Nielsen (RDN)
39
39
  -- Elizabeth Shea (ES)
40
+ -- Caleb Grant (CG)
40
41
  --
41
42
  -- VERSION
42
- -- 1.0.0
43
+ -- 1.1.0
43
44
  --
44
45
  -- HISTORY
45
46
  -- Date Remarks
@@ -47,6 +48,10 @@
47
48
  -- 2019-05-01 Created SQL Server version from 2019-04-20 version for
48
49
  -- Postgres. RDN.
49
50
  -- 2019-05-11 Completed conversion to SQL Server. RDN.
51
+ -- 2026-10-15 execsql2: each script's notes are its docstring (SHOW SCRIPTS, the
52
+ -- language server); def_url is a declared optional parameter;
53
+ -- ADD_GLOSSARY_ITEM keeps def_url. Version 1.1.0. Tested in
54
+ -- tests/templates of the execsql2 repository. CG.
50
55
  -- ============================================================================
51
56
 
52
57
 
@@ -122,7 +127,7 @@ where row_num=(select max(row_num) from agg);
122
127
  -- ################################################################
123
128
  -- Script INIT_GLOSSARY
124
129
  -- ===============================================================
125
- --
130
+ -- !x! BEGIN SCRIPT INIT_GLOSSARY with parameters (glossary_db_alias, glossary_table, name_col, def_col, def_url="")
126
131
  -- Initialize the custom glossary and describe the master glossary
127
132
  -- that will provide descriptions to include in the custom glossary.
128
133
  --
@@ -139,14 +144,12 @@ where row_num=(select max(row_num) from agg);
139
144
  -- Optional input argument:
140
145
  -- def_url : The URL of a page that provides additional
141
146
  -- information about the column (or other object).
142
- -- ===============================================================
143
- -- !x! BEGIN SCRIPT INIT_GLOSSARY with parameters (glossary_db_alias, glossary_table, name_col, def_col)
144
147
 
145
148
  -- !x! sub gls_alias !!#glossary_db_alias!!
146
149
  -- !x! sub gls_table !!#glossary_table!!
147
150
  -- !x! sub gls_name !!#name_col!!
148
151
  -- !x! sub gls_def !!#def_col!!
149
- -- !x! if(sub_defined(#def_url))
152
+ -- !x! if(not is_null("!!#def_url!!"))
150
153
  -- !x! sub gls_has_url Yes
151
154
  -- !x! sub gls_url !!#def_url!!
152
155
  -- !x! sub ~url_colspec !!gls_url!! text,
@@ -187,13 +190,11 @@ from gls_glossary;
187
190
  -- ################################################################
188
191
  -- Script ADD_GLOSSARY_LIST
189
192
  -- ===============================================================
190
- --
193
+ -- !x! BEGIN SCRIPT ADD_GLOSSARY_LIST with parameters (column_list)
191
194
  -- Add a specific list of columns to the glossary.
192
195
  --
193
196
  -- Required input arguments:
194
197
  -- column_list : A string of comma-separated column names.
195
- -- ===============================================================
196
- -- !x! BEGIN SCRIPT ADD_GLOSSARY_LIST with parameters (column_list)
197
198
 
198
199
  -- !x! sub ~entry_alias !!$current_alias!!
199
200
  -- !x! use initial
@@ -301,7 +302,7 @@ drop table gls_newentries;
301
302
  -- ################################################################
302
303
  -- Script ADD_GLOSSARY_ITEM
303
304
  -- ===============================================================
304
- --
305
+ -- !x! BEGIN SCRIPT ADD_GLOSSARY_ITEM with parameters (item, definition, def_url="")
305
306
  -- Add an object name and definition to the custom glossary.
306
307
  -- This does not use the master glossary.
307
308
  --
@@ -313,14 +314,12 @@ drop table gls_newentries;
313
314
  -- Optional input argument:
314
315
  -- def_url : The URL of a page that provides additional
315
316
  -- information about the item.
316
- -- ===============================================================
317
- -- !x! BEGIN SCRIPT ADD_GLOSSARY_ITEM with parameters (item, definition)
318
317
 
319
318
  -- !x! sub ~entry_alias !!$current_alias!!
320
319
  -- !x! use initial
321
320
 
322
- -- !x! if(is_true(gls_has_url))
323
- -- !x! andif(sub_defined(#def_url))
321
+ -- !x! if(is_true(!!gls_has_url!!))
322
+ -- !x! andif(not is_null("!!#def_url!!"))
324
323
  insert into gls_glossary (!!gls_name!!, !!gls_def!!, !!gls_url!!)
325
324
  select
326
325
  inp.item, inp.definition, inp.url
@@ -353,16 +352,13 @@ drop table gls_newentries;
353
352
  -- ################################################################
354
353
  -- Script ADD_GLOSSARY_TABLE
355
354
  -- ===============================================================
356
- --
355
+ -- !x! BEGIN SCRIPT ADD_GLOSSARY_TABLE with parameters (schema, table)
357
356
  -- Add definitions of all columns in a specified table to the
358
357
  -- custom glossary.
359
358
  --
360
359
  -- Required input arguments:
361
360
  -- schema : The schema of the table.
362
361
  -- table : The table name.
363
- --
364
- -- ===============================================================
365
- -- !x! BEGIN SCRIPT ADD_GLOSSARY_TABLE with parameters (schema, table)
366
362
 
367
363
  -- !x! sub ~entry_alias !!$current_alias!!
368
364
 
@@ -90,6 +90,7 @@
90
90
  -- AUTHORS
91
91
  -- Elizabeth Shea (ES)
92
92
  -- Dreas Nielsen (RDN)
93
+ -- Caleb Grant (CG)
93
94
  --
94
95
  -- VERSION
95
96
  -- 2.0.0
@@ -128,12 +129,20 @@
128
129
  -- 2020-04-28 Explicitly rolled back the changes if 'do_commit' = "No". RDN.
129
130
  -- 2020-05-09 Moved the assignment of 'upsert_progress_denom' out of the
130
131
  -- 'update_console_qa' script. RDN.
132
+ -- 2026-10-15 execsql2: LOAD_STAGING with do_commit=No keeps the row counts it
133
+ -- writes to the control table, which the rollback undid; each
134
+ -- script's notes are its docstring (SHOW SCRIPTS, the language
135
+ -- server). UPSERT_ONE with exclude_cols no longer fails
136
+ -- (ambiguous column_name); FKQA_ONE rebuilds its table of
137
+ -- foreign keys on every call, so a copy left in the session
138
+ -- from an earlier load cannot hide foreign key errors. Tested
139
+ -- in tests/templates of the execsql2 repository. CG.
131
140
  -- ==================================================================
132
141
 
133
142
  -- ################################################################
134
143
  -- Script TEMPTABLE_ISVALID
135
144
  -- ===============================================================
136
- --
145
+ -- !x! BEGIN SCRIPT TEMPTABLE_ISVALID with parameters (temptable_name)
137
146
  -- Utility script to validate SQL Server temp table name.
138
147
  -- Confirms that the name passed by the user is prefixed with a '#',
139
148
  -- and raises an error if not
@@ -148,8 +157,6 @@
148
157
  --
149
158
  -- Example:
150
159
  -- -- !x! execute script temp_table_isvalid with (temptable_name=#stagingtables)
151
- -- ===============================================================
152
- -- !x! BEGIN SCRIPT TEMPTABLE_ISVALID with parameters (temptable_name)
153
160
 
154
161
  -- Take the user-provided temp_table argument and validate syntax
155
162
  if object_id('tempdb..#tmptbl_name') is not null drop table #tmptbl_name;
@@ -176,7 +183,7 @@ into #tmptbl_name
176
183
  -- ################################################################
177
184
  -- Script STRING_AGG
178
185
  -- ===============================================================
179
- --
186
+ -- !x! BEGIN SCRIPT STRING_AGG with parameters (table_name, string_col, order_col, delimiter, string_var)
180
187
  -- Utility script to perform string aggregation
181
188
  -- Beginning with 2017 edition, SQL Server *does* include the string_agg()
182
189
  -- function, but earlier versions do not.
@@ -195,8 +202,6 @@ into #tmptbl_name
195
202
  --
196
203
  -- Example:
197
204
  -- -- !x! execute script string_agg with (table_name=#nonnulcols, string_col=null_errors, order_col=null_errors, delimiter=", ", string_var=+nullcols)
198
- -- ===============================================================
199
- -- !x! BEGIN SCRIPT STRING_AGG with parameters (table_name, string_col, order_col, delimiter, string_var)
200
205
 
201
206
  if object_id('tempdb..#agg_string') is not null drop table #agg_string;
202
207
  with enum as
@@ -242,7 +247,7 @@ where row_num=(select max(row_num) from agg);
242
247
  -- ################################################################
243
248
  -- Script VALIDATE_SCHEMAS
244
249
  -- ===============================================================
245
- --
250
+ -- !x! BEGIN SCRIPT VALIDATE_SCHEMAS with parameters (base_schema, staging, error_list)
246
251
  -- Utility script to validate base and staging schema
247
252
  --
248
253
  -- Required input arguments:
@@ -253,8 +258,6 @@ where row_num=(select max(row_num) from agg);
253
258
  -- error_list : The name of the variable to receive a comma-
254
259
  -- delimited list of the names of invalid
255
260
  -- schema names.
256
- -- ===============================================================
257
- -- !x! BEGIN SCRIPT VALIDATE_SCHEMAS with parameters (base_schema, staging, error_list)
258
261
 
259
262
  if object_id('tempdb..#ups_ctrl_invl_schema') is not null drop table #ups_ctrl_invl_schema;
260
263
  select
@@ -290,7 +293,7 @@ where
290
293
  -- ################################################################
291
294
  -- Script VALIDATE_ONE
292
295
  -- ===============================================================
293
- --
296
+ -- !x! BEGIN SCRIPT VALIDATE_ONE with parameters (base_schema, staging, table, script, script_line)
294
297
  -- Utility script to validate one table in both base and staging schema
295
298
  -- Halts script processing if any either of the schemas are non-existent,
296
299
  -- or if either of the tables are not present within those schemas.
@@ -304,8 +307,6 @@ where
304
307
  -- (for error reporting).
305
308
  -- script_line : The script line in which they were referenced
306
309
  -- (for error reporting).
307
- -- ===============================================================
308
- -- !x! BEGIN SCRIPT VALIDATE_ONE with parameters (base_schema, staging, table, script, script_line)
309
310
 
310
311
  -- Initialize the strings used to compile error information
311
312
  -- !x! sub_empty ~err_info
@@ -381,7 +382,7 @@ where
381
382
  -- ################################################################
382
383
  -- Script VALIDATE_CONTROL
383
384
  -- ===============================================================
384
- --
385
+ -- !x! BEGIN SCRIPT VALIDATE_CONTROL with parameters (base_schema, staging, control_table, script, script_line)
385
386
  -- Utility script to validate contents of control table against about
386
387
  -- base and staging schema
387
388
  --
@@ -395,8 +396,6 @@ where
395
396
  -- (for error reporting).
396
397
  -- script_line : The script line in which they were referenced
397
398
  -- (for error reporting).
398
- -- ===============================================================
399
- -- !x! BEGIN SCRIPT VALIDATE_CONTROL with parameters (base_schema, staging, control_table, script, script_line)
400
399
 
401
400
  -- Initialize the strings used to compile error information
402
401
  -- !x! sub_empty ~err_info
@@ -484,7 +483,7 @@ where
484
483
  -- ################################################################
485
484
  -- Script STAGED_TO_LOAD
486
485
  -- ===============================================================
487
- --
486
+ -- !x! BEGIN SCRIPT STAGED_TO_LOAD with parameters (control_table, table_list)
488
487
  -- Creates a table having the structure that is used to drive other
489
488
  -- scripts that perform QA checks and the upsert operation on multiple
490
489
  -- staging tables.
@@ -544,9 +543,6 @@ where
544
543
  --
545
544
  -- Example:
546
545
  -- -- !x! execute script staged_to_load with (control_table=#stagingtables, table_list="tbla, tblb, tblc")
547
- -- ===============================================================
548
-
549
- -- !x! BEGIN SCRIPT STAGED_TO_LOAD with parameters (control_table, table_list)
550
546
 
551
547
  -- Run script to validate that control table name is valid temp table name
552
548
  -- !x! execute script temptable_isvalid with args (temptable_name=!!#control_table!!)
@@ -617,7 +613,7 @@ from itemtable;
617
613
  -- ################################################################
618
614
  -- Script LOAD_STAGING
619
615
  -- ===============================================================
620
- --
616
+ -- !x! BEGIN SCRIPT LOAD_STAGING with parameters (base_schema, staging, control_table, do_commit)
621
617
  -- Performs QA checks for nulls in non-null columns, for duplicated
622
618
  -- primary key values, and for invalid foreign keys in a set of staging
623
619
  -- tables to be loaded into base tables. If there are failures in the
@@ -660,9 +656,6 @@ from itemtable;
660
656
  --
661
657
  -- Tables and views created or modified:
662
658
  -- #ups_qa_fails : temporary table
663
- -- ===============================================================
664
-
665
- -- !x! BEGIN SCRIPT LOAD_STAGING with parameters (base_schema, staging, control_table, do_commit)
666
659
 
667
660
 
668
661
  -- Clear the columns of return values from the control table, in case this control
@@ -699,7 +692,26 @@ where null_errors is not null or pk_errors is not null or fk_errors is not null;
699
692
  -- !x! write "!!$current_time!! -- CHANGES COMMITTED." to !!logfile!!
700
693
  -- !x! endif
701
694
  -- !x! else
695
+ -- The rollback also undoes the counts UPSERT_ALL wrote to the control
696
+ -- table. Keep them, so that a dry run reports what it would change.
697
+ if object_id('tempdb..#ups_counts') is not null drop table #ups_counts;
698
+ select
699
+ string_agg(
700
+ '(' + quotename(table_name, '''') + ', '
701
+ + coalesce(cast(rows_updated as varchar(20)), 'null') + ', '
702
+ + coalesce(cast(rows_inserted as varchar(20)), 'null') + ')',
703
+ ', '
704
+ ) as counts
705
+ into #ups_counts
706
+ from !!#control_table!!;
707
+ -- !x! subdata ~ups_counts #ups_counts
702
708
  -- !x! autocommit on with rollback
709
+ update c
710
+ set rows_updated = v.rows_updated, rows_inserted = v.rows_inserted
711
+ from
712
+ !!#control_table!! as c
713
+ inner join (values !!~ups_counts!!) as v (table_name, rows_updated, rows_inserted)
714
+ on v.table_name = c.table_name;
703
715
  -- !x! write "CHANGES NOT COMMITTED ('do_commit' argument = !!#do_commit!!)"
704
716
  -- !x! if(sub_defined(log_changes))
705
717
  -- !x! andif(is_true(!!log_changes!!))
@@ -721,7 +733,7 @@ where null_errors is not null or pk_errors is not null or fk_errors is not null;
721
733
  -- ################################################################
722
734
  -- Script NULLQA_ONE
723
735
  -- ===============================================================
724
- --
736
+ -- !x! BEGIN SCRIPT NULLQA_ONE with parameters (base_schema, staging, table, error_list)
725
737
  -- Checks that non-nullable columns are fully populated in a
726
738
  -- staging table that is an image of the base table.
727
739
  -- Reports any non-conforming columns to the console and optionally
@@ -751,9 +763,6 @@ where null_errors is not null or pk_errors is not null or fk_errors is not null;
751
763
  -- #ups_next_column : temporary table
752
764
  -- #ups_null_error_list : temporary table
753
765
  -- #ups_qa_nonnull_col : temporary table
754
- -- ===============================================================
755
-
756
- -- !x! BEGIN SCRIPT NULLQA_ONE with parameters (base_schema, staging, table, error_list)
757
766
 
758
767
  -- Write an initial header to the logfile.
759
768
  -- !x! if(sub_defined(logfile))
@@ -879,7 +888,8 @@ where
879
888
 
880
889
  -- ################################################################
881
890
  -- Script PKQA_ONE
882
- --
891
+ -- ===============================================================
892
+ -- !x! BEGIN SCRIPT PKQA_ONE with parameters (base_schema, staging, table, display_errors, error_list)
883
893
  -- Check data a staging table for violations of the primary key
884
894
  -- of the corresponding base table.
885
895
  -- Reports any PK violations found to the console and optionally
@@ -912,9 +922,6 @@ where
912
922
  -- #ups_primary_key_columns : temporary table
913
923
  -- #ups_pk_check : temporary table
914
924
  -- #ups_ercnt : temporary table
915
- -- ===============================================================
916
-
917
- -- !x! BEGIN SCRIPT PKQA_ONE with parameters (base_schema, staging, table, display_errors, error_list)
918
925
 
919
926
  -- Write an initial header to the logfile.
920
927
  -- !x! if(sub_defined(logfile))
@@ -1009,7 +1016,8 @@ order by k.ordinal_position
1009
1016
 
1010
1017
  -- ################################################################
1011
1018
  -- Script FKQA_ONE
1012
- --
1019
+ -- ===============================================================
1020
+ -- !x! BEGIN SCRIPT FKQA_ONE with parameters (base_schema, staging, table, display_errors, error_list)
1013
1021
  -- Checks foreign keys from a staging table against a base table
1014
1022
  -- and, if it exists, another staging table that is an image of the
1015
1023
  -- base table.
@@ -1048,9 +1056,6 @@ order by k.ordinal_position
1048
1056
  -- ups_fk_joins : temporary table
1049
1057
  -- ups_fk_check : temporary table
1050
1058
  -- ups_ercnt : temporary table
1051
- -- ===============================================================
1052
-
1053
- -- !x! BEGIN SCRIPT FKQA_ONE with parameters (base_schema, staging, table, display_errors, error_list)
1054
1059
 
1055
1060
  -- Write an initial header to the logfile.
1056
1061
  -- !x! if(sub_defined(logfile))
@@ -1069,14 +1074,11 @@ order by k.ordinal_position
1069
1074
 
1070
1075
 
1071
1076
  -- Create a table of *all* foreign key dependencies in this database.
1072
- -- Because this may be an expensive operation (in terms of time), the
1073
- -- table is not re-created if it already exists. "Already exists"
1074
- -- means that a table with the expected name exists. No check is
1075
- -- done to ensure that this table has the correct structure. The
1076
- -- goal is to create the table of all foreign keys only once to
1077
- -- minimize the time required if QA checks are to be run on multiple
1078
- -- staging tables.
1079
- if object_id('tempdb..#ups_foreign_key_columns') is null
1077
+ -- It is rebuilt on every call: a copy left in the session from an
1078
+ -- earlier load (a second load in the same script, or a pooled
1079
+ -- connection that keeps its temporary tables) described other tables
1080
+ -- and let foreign key errors through.
1081
+ if object_id('tempdb..#ups_foreign_key_columns') is not null drop table #ups_foreign_key_columns;
1080
1082
  select
1081
1083
  rc.constraint_name,
1082
1084
  cu.table_schema,
@@ -1297,7 +1299,8 @@ where coalesce(fkerror_rows, 0) > 0;
1297
1299
 
1298
1300
  -- ################################################################
1299
1301
  -- Script UPSERT_ONE
1300
- --
1302
+ -- ===============================================================
1303
+ -- !x! BEGIN SCRIPT UPSERT_ONE with parameters (base_schema, staging, table, exclude_cols, display_changes, display_final, updcntvar, inscntvar)
1301
1304
  -- Adds data from a staging table to a base table, using UPDATE
1302
1305
  -- and INSERT statements. Displays data to be modified to the
1303
1306
  -- user before any modifications are done. Reports the changes
@@ -1347,9 +1350,6 @@ where coalesce(fkerror_rows, 0) > 0;
1347
1350
  -- ups_nk : temporary table
1348
1351
  -- ups_assexpr : temporary table
1349
1352
  -- ups_newrows : temporary table
1350
- -- ===============================================================
1351
-
1352
- -- !x! BEGIN SCRIPT UPSERT_ONE with parameters (base_schema, staging, table, exclude_cols, display_changes, display_final, updcntvar, inscntvar)
1353
1353
 
1354
1354
  -- Remove substitution variables that will contain the generated
1355
1355
  -- update and insert statements so that the existence of valid
@@ -1380,7 +1380,7 @@ where coalesce(fkerror_rows, 0) > 0;
1380
1380
  -- !x! if(is_null("!!#exclude_cols!!"))
1381
1381
  -- !x! sub_empty ~col_excl
1382
1382
  -- !x! else
1383
- -- !x! sub ~col_excl and column_name not in (!!#exclude_cols!!)
1383
+ -- !x! sub ~col_excl and s.column_name not in (!!#exclude_cols!!)
1384
1384
  -- !x! endif
1385
1385
  if object_id('tempdb..#ups_cols') is not null drop table #ups_cols;
1386
1386
  select s.column_name, s.ordinal_position
@@ -1623,7 +1623,8 @@ from
1623
1623
 
1624
1624
  -- ################################################################
1625
1625
  -- Script UPSERT_ALL
1626
- --
1626
+ -- ===============================================================
1627
+ -- !x! BEGIN SCRIPT UPSERT_ALL with parameters (base_schema, staging, control_table)
1627
1628
  -- Updates multiple base tables with new or revised data from
1628
1629
  -- staging tables, using the UPSERT_ONE script.
1629
1630
  --
@@ -1667,10 +1668,6 @@ from
1667
1668
  --
1668
1669
  -- Counter variables:
1669
1670
  -- 221585944 : Progress indicator.
1670
- --
1671
- -- ===============================================================
1672
-
1673
- -- !x! BEGIN SCRIPT UPSERT_ALL with parameters (base_schema, staging, control_table)
1674
1671
 
1675
1672
 
1676
1673
  -- Validate contents of control table
@@ -1865,7 +1862,8 @@ on pt.table_name = ct.table_name;
1865
1862
 
1866
1863
  -- ################################################################
1867
1864
  -- Script QA_ALL
1868
- --
1865
+ -- ===============================================================
1866
+ -- !x! BEGIN SCRIPT QA_ALL with parameters (base_schema, staging, control_table)
1869
1867
  -- Conducts null and foreign key checks on multiple staging tables
1870
1868
  -- containing new or revised data for staging tables, using the
1871
1869
  -- NULLQA_ONE, PKQA_ONE, and FKQA_ONE scripts.
@@ -1916,10 +1914,6 @@ on pt.table_name = ct.table_name;
1916
1914
  --
1917
1915
  -- Global variables modified:
1918
1916
  -- upsert_progress_denom : Created or redefined.
1919
- --
1920
- -- ===============================================================
1921
-
1922
- -- !x! BEGIN SCRIPT QA_ALL with parameters (base_schema, staging, control_table)
1923
1917
 
1924
1918
  -- Get denominator for progress bar if console is on.
1925
1919
  -- !x! if(console_on)
@@ -2092,7 +2086,8 @@ update #ups_proctables set processed = 0;
2092
2086
 
2093
2087
  -- ################################################################
2094
2088
  -- Script UPDTPK_ONE
2095
- --
2089
+ -- ===============================================================
2090
+ -- !x! BEGIN SCRIPT UPDTPK_ONE with parameters (base_schema, staging, table, display_errors, display_changes)
2096
2091
  -- Updates primary keys in base table, based on new and older
2097
2092
  -- values of PK columns in a staging table, using UPDATE
2098
2093
  -- statements. Displays data to be modified to the
@@ -2123,9 +2118,6 @@ update #ups_proctables set processed = 0;
2123
2118
  -- ups_pkqa_errors : temporary table
2124
2119
  -- ups_pkcollinfo : temporary table
2125
2120
  -- ups_pkupdates : temporary table
2126
- -- ===============================================================
2127
-
2128
- -- !x! BEGIN SCRIPT UPDTPK_ONE with parameters (base_schema, staging, table, display_errors, display_changes)
2129
2121
 
2130
2122
  -- !x! if(console_on)
2131
2123
  -- !x! console status "Primary key updates"
@@ -2294,7 +2286,8 @@ where
2294
2286
 
2295
2287
  -- ################################################################
2296
2288
  -- Script UPDTPKQA_ONE
2297
- --
2289
+ -- ===============================================================
2290
+ -- !x! BEGIN SCRIPT UPDTPKQA_ONE with parameters (base_schema, staging, table, pkinfo_table, qaerror_table, display_errors)
2298
2291
  -- Performs QA checks on requested primary key updates to a table,
2299
2292
  -- based on old and new values of the table's primary key columns
2300
2293
  -- in a staging table.
@@ -2328,9 +2321,6 @@ where
2328
2321
  -- Tables and views created or modified:
2329
2322
  -- ups_missing_pk_cols : temporary table
2330
2323
  -- ups_any_pk_cols : temporary table
2331
- -- ===============================================================
2332
-
2333
- -- !x! BEGIN SCRIPT UPDTPKQA_ONE with parameters (base_schema, staging, table, pkinfo_table, qaerror_table, display_errors)
2334
2324
 
2335
2325
 
2336
2326
  -- Write an initial header to the logfile.