weaverstack 0.1.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.
- weaver/__init__.py +59 -0
- weaver/build_bundle/__init__.py +109 -0
- weaver/build_bundle/aliases.py +325 -0
- weaver/build_bundle/bundle.py +359 -0
- weaver/build_bundle/catalogue_actions.py +275 -0
- weaver/build_bundle/changes.py +186 -0
- weaver/build_bundle/endpoints.py +83 -0
- weaver/build_bundle/executors/__init__.py +69 -0
- weaver/build_bundle/executors/alias.py +202 -0
- weaver/build_bundle/executors/base.py +132 -0
- weaver/build_bundle/executors/folder.py +71 -0
- weaver/build_bundle/executors/load_file.py +205 -0
- weaver/build_bundle/executors/spark_case.py +26 -0
- weaver/build_bundle/executors/spark_schema.py +60 -0
- weaver/build_bundle/executors/spark_sql.py +59 -0
- weaver/build_bundle/executors/spark_sql_batch.py +57 -0
- weaver/build_bundle/executors/spark_table.py +213 -0
- weaver/build_bundle/executors/sql_endpoint_refresh.py +34 -0
- weaver/build_bundle/executors/tsql.py +81 -0
- weaver/build_bundle/incremental.py +288 -0
- weaver/build_bundle/installer.py +384 -0
- weaver/build_bundle/models.py +288 -0
- weaver/build_bundle/payloads.py +34 -0
- weaver/build_bundle/physical.py +625 -0
- weaver/build_bundle/planner.py +389 -0
- weaver/build_bundle/prune.py +620 -0
- weaver/build_bundle/report.py +108 -0
- weaver/build_bundle/stages.py +196 -0
- weaver/build_bundle/targets.py +272 -0
- weaver/build_bundle/workflow.py +585 -0
- weaver/catalogue/__init__.py +73 -0
- weaver/catalogue/builtin.py +238 -0
- weaver/catalogue/claims.py +121 -0
- weaver/catalogue/projection.py +437 -0
- weaver/catalogue/reader.py +152 -0
- weaver/catalogue/reconcile.py +231 -0
- weaver/catalogue/render.py +410 -0
- weaver/catalogue/state.py +660 -0
- weaver/catalogue/tables.py +648 -0
- weaver/config.py +178 -0
- weaver/declaration/__init__.py +171 -0
- weaver/declaration/columns.py +223 -0
- weaver/declaration/ddl.py +266 -0
- weaver/declaration/dependencies.py +544 -0
- weaver/declaration/graph.py +240 -0
- weaver/declaration/item_dependencies.py +292 -0
- weaver/declaration/load.py +191 -0
- weaver/declaration/metadata.py +1405 -0
- weaver/declaration/model.py +448 -0
- weaver/declaration/references.py +294 -0
- weaver/declaration/repository.py +959 -0
- weaver/declaration/schemas.py +135 -0
- weaver/declaration/source.py +674 -0
- weaver/declaration/spark_load.py +759 -0
- weaver/declaration/sql_shaping.py +591 -0
- weaver/declaration/templates/ddl/declared_create_table.sql +64 -0
- weaver/declaration/templates/ddl/infer_create_table.sql +97 -0
- weaver/declaration/templates/ddl/metadata_column_validation.sql +30 -0
- weaver/declaration/templates/load/column_metadata.sql +40 -0
- weaver/declaration/templates/load/full_replace_body.sql +21 -0
- weaver/declaration/templates/load/install_load_procedure.sql +27 -0
- weaver/declaration/templates/load/load_procedure.sql +48 -0
- weaver/declaration/templates/load/primary_key_body.sql +113 -0
- weaver/declaration/tsql_ddl.py +468 -0
- weaver/declaration/tsql_load.py +417 -0
- weaver/declaration/warehouse_type_mapping.yml +93 -0
- weaver/diagnostics.py +247 -0
- weaver/errors.py +61 -0
- weaver/etl.py +469 -0
- weaver/fabric/__init__.py +107 -0
- weaver/fabric/auth.py +137 -0
- weaver/fabric/capacity.py +143 -0
- weaver/fabric/client.py +147 -0
- weaver/fabric/environment.py +460 -0
- weaver/fabric/livy.py +478 -0
- weaver/fabric/notebooks.py +201 -0
- weaver/fabric/onelake.py +263 -0
- weaver/fabric/resolution.py +344 -0
- weaver/fabric/resources.py +245 -0
- weaver/fabric/session.py +148 -0
- weaver/fabric/shortcuts.py +120 -0
- weaver/fabric/sql.py +118 -0
- weaver/fabric/store.py +198 -0
- weaver/initialise.py +209 -0
- weaver/lakehouse.py +386 -0
- weaver/load.py +474 -0
- weaver/load_execution.py +483 -0
- weaver/load_plan.py +912 -0
- weaver/load_report.py +330 -0
- weaver/load_resolution.py +386 -0
- weaver/locations.py +164 -0
- weaver/objects.py +392 -0
- weaver/operations.py +757 -0
- weaver/physical_wipe.py +369 -0
- weaver/push.py +76 -0
- weaver/resolution.py +292 -0
- weaver/runtime/__init__.py +30 -0
- weaver/runtime/folder_load.py +402 -0
- weaver/runtime/load_contract.py +245 -0
- weaver/runtime/load_result.py +104 -0
- weaver/runtime/spark_load.py +152 -0
- weaver/runtime/table_load.py +497 -0
- weaver/spark/__init__.py +49 -0
- weaver/spark/catalogue.py +245 -0
- weaver/spark/destination.py +195 -0
- weaver/spark/session.py +84 -0
- weaver/spark/tokens.py +138 -0
- weaver/sql/__init__.py +40 -0
- weaver/sql/authentication.py +38 -0
- weaver/sql/connection.py +90 -0
- weaver/sql/errors.py +25 -0
- weaver/sql/execution.py +123 -0
- weaver/sql/pool.py +174 -0
- weaver/sql/wipe.py +156 -0
- weaver/store.py +209 -0
- weaver/targets.py +257 -0
- weaver/task_logging.py +215 -0
- weaver/unbind.py +74 -0
- weaver/workspaces.py +175 -0
- weaver_cli/__init__.py +12 -0
- weaver_cli/__main__.py +7 -0
- weaver_cli/main.py +626 -0
- weaverstack-0.1.1.dist-info/METADATA +113 -0
- weaverstack-0.1.1.dist-info/RECORD +127 -0
- weaverstack-0.1.1.dist-info/WHEEL +4 -0
- weaverstack-0.1.1.dist-info/entry_points.txt +2 -0
- weaverstack-0.1.1.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
declare @weaver_create_sql nvarchar(max);
|
|
2
|
+
declare @weaver_pk_sql nvarchar(max);
|
|
3
|
+
|
|
4
|
+
if not exists (
|
|
5
|
+
select 1
|
|
6
|
+
from tempdb.sys.columns as c
|
|
7
|
+
where c.[object_id] = object_id($temp_object_literal)
|
|
8
|
+
)
|
|
9
|
+
begin
|
|
10
|
+
throw 51001, 'weaver found no temp table columns to create.', 1;
|
|
11
|
+
end;
|
|
12
|
+
|
|
13
|
+
$metadata_validation_sql
|
|
14
|
+
|
|
15
|
+
$identity_guard_sql
|
|
16
|
+
|
|
17
|
+
;with primary_key_columns as (
|
|
18
|
+
$primary_key_columns_cte
|
|
19
|
+
),
|
|
20
|
+
not_null_columns as (
|
|
21
|
+
$not_null_columns_cte
|
|
22
|
+
),
|
|
23
|
+
described as (
|
|
24
|
+
select
|
|
25
|
+
c.column_id as column_ordinal,
|
|
26
|
+
coalesce(nullif(c.name, ''), concat('Column', c.column_id)) as column_name,
|
|
27
|
+
t.name as system_type_name,
|
|
28
|
+
c.max_length,
|
|
29
|
+
c.precision,
|
|
30
|
+
c.scale
|
|
31
|
+
from tempdb.sys.columns as c
|
|
32
|
+
inner join tempdb.sys.types as t on t.user_type_id = c.user_type_id
|
|
33
|
+
where c.[object_id] = object_id($temp_object_literal)
|
|
34
|
+
),
|
|
35
|
+
mapped as (
|
|
36
|
+
select
|
|
37
|
+
d.column_ordinal,
|
|
38
|
+
quotename(d.column_name) as quoted_column_name,
|
|
39
|
+
$type_case as warehouse_type,
|
|
40
|
+
-- Nullability is a Weaver contract from the Weaver document header (primary key or
|
|
41
|
+
-- Not null), not the query's own nullability, so both engines agree.
|
|
42
|
+
case
|
|
43
|
+
when nn.column_name is not null then N' not null'
|
|
44
|
+
else N' null'
|
|
45
|
+
end as nullability
|
|
46
|
+
from described as d
|
|
47
|
+
left join not_null_columns as nn
|
|
48
|
+
on nn.column_name = d.column_name collate Latin1_General_BIN2
|
|
49
|
+
cross apply (
|
|
50
|
+
select lower(d.system_type_name) as base_type
|
|
51
|
+
) as bt
|
|
52
|
+
),
|
|
53
|
+
all_columns as (
|
|
54
|
+
$identity_column_sql select
|
|
55
|
+
column_ordinal,
|
|
56
|
+
quoted_column_name + N' ' + warehouse_type + nullability as column_definition
|
|
57
|
+
from mapped
|
|
58
|
+
|
|
59
|
+
union all
|
|
60
|
+
|
|
61
|
+
select 1000001, N'[Row insert datetime] datetime2(6) not null'
|
|
62
|
+
union all
|
|
63
|
+
select 1000002, N'[Row update datetime] datetime2(6) not null'
|
|
64
|
+
union all
|
|
65
|
+
select 1000003, N'[Row delete datetime] datetime2(6) not null'
|
|
66
|
+
)
|
|
67
|
+
select
|
|
68
|
+
@weaver_create_sql = (
|
|
69
|
+
select
|
|
70
|
+
N'create table $target_table (' + char(10)
|
|
71
|
+
+ string_agg(
|
|
72
|
+
case
|
|
73
|
+
when column_ordinal = $first_ordinal then N' ' + column_definition
|
|
74
|
+
else N' , ' + column_definition
|
|
75
|
+
end,
|
|
76
|
+
char(10)
|
|
77
|
+
) within group (order by column_ordinal)
|
|
78
|
+
+ char(10) + N');'
|
|
79
|
+
from all_columns
|
|
80
|
+
),
|
|
81
|
+
@weaver_pk_sql = (
|
|
82
|
+
select
|
|
83
|
+
N'alter table $target_table add constraint $pk_constraint '
|
|
84
|
+
+ N'primary key nonclustered ('
|
|
85
|
+
+ string_agg(quotename(column_name), N', ') within group (order by column_ordinal)
|
|
86
|
+
+ N') not enforced;'
|
|
87
|
+
from primary_key_columns
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
print @weaver_create_sql;
|
|
91
|
+
exec sys.sp_executesql @weaver_create_sql;
|
|
92
|
+
|
|
93
|
+
if @weaver_pk_sql is not null
|
|
94
|
+
begin
|
|
95
|
+
print @weaver_pk_sql;
|
|
96
|
+
exec sys.sp_executesql @weaver_pk_sql;
|
|
97
|
+
end;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
declare @weaver_missing_metadata_column nvarchar(2048);
|
|
2
|
+
|
|
3
|
+
;with described as (
|
|
4
|
+
select
|
|
5
|
+
coalesce(nullif(c.name, ''), concat('Column', c.column_id)) as column_name
|
|
6
|
+
from tempdb.sys.columns as c
|
|
7
|
+
where c.[object_id] = object_id($temp_object_literal)$identity_available_sql
|
|
8
|
+
),
|
|
9
|
+
metadata_columns as (
|
|
10
|
+
$metadata_columns_cte
|
|
11
|
+
)
|
|
12
|
+
select top (1)
|
|
13
|
+
@weaver_missing_metadata_column =
|
|
14
|
+
concat(m.metadata_kind, N' ', m.column_name, N' does not exist')
|
|
15
|
+
from metadata_columns as m
|
|
16
|
+
where not exists (
|
|
17
|
+
select 1
|
|
18
|
+
from described as d
|
|
19
|
+
-- Column names are exact, case-sensitive Weaver contracts, so compare under
|
|
20
|
+
-- a binary collation rather than the database's (often case-insensitive) one.
|
|
21
|
+
where d.column_name = m.column_name collate Latin1_General_BIN2
|
|
22
|
+
)
|
|
23
|
+
order by
|
|
24
|
+
m.metadata_kind
|
|
25
|
+
, m.column_name;
|
|
26
|
+
|
|
27
|
+
if @weaver_missing_metadata_column is not null
|
|
28
|
+
begin
|
|
29
|
+
throw 51004, @weaver_missing_metadata_column, 1;
|
|
30
|
+
end;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
-- The loadable columns, read from the table the load will write to.
|
|
2
|
+
--
|
|
3
|
+
-- Read from sys.columns rather than from the declaration, because the physical
|
|
4
|
+
-- table is what the procedure has to name. That is also what excludes the
|
|
5
|
+
-- identity column for free: the Warehouse generates it, so `is_identity = 0`
|
|
6
|
+
-- keeps it out of every insert list without the generator having to know which
|
|
7
|
+
-- column it was.
|
|
8
|
+
;with source_columns as (
|
|
9
|
+
select
|
|
10
|
+
c.name
|
|
11
|
+
, c.column_id
|
|
12
|
+
, row_number() over (order by c.column_id) as row_ordinal
|
|
13
|
+
from sys.columns as c
|
|
14
|
+
where c.[object_id] = object_id($target_table_literal)
|
|
15
|
+
and $source_column_filter
|
|
16
|
+
)
|
|
17
|
+
select
|
|
18
|
+
@weaver_source_columns = string_agg(
|
|
19
|
+
case when row_ordinal = 1 then quotename(name) else char(10) + N' , ' + quotename(name) end,
|
|
20
|
+
N''
|
|
21
|
+
) within group (order by column_id)
|
|
22
|
+
, @weaver_staging_select_columns = string_agg(
|
|
23
|
+
case when row_ordinal = 1 then N's.' + quotename(name) else char(10) + N' , s.' + quotename(name) end,
|
|
24
|
+
N''
|
|
25
|
+
) within group (order by column_id)
|
|
26
|
+
, @weaver_staging_except_columns = string_agg(
|
|
27
|
+
case when row_ordinal = 1 then N's.' + quotename(name) else char(10) + N' , s.' + quotename(name) end,
|
|
28
|
+
N''
|
|
29
|
+
) within group (order by column_id)
|
|
30
|
+
, @weaver_target_except_columns = string_agg(
|
|
31
|
+
case when row_ordinal = 1 then N't.' + quotename(name) else char(10) + N' , t.' + quotename(name) end,
|
|
32
|
+
N''
|
|
33
|
+
) within group (order by column_id)
|
|
34
|
+
, @weaver_upsert_select_columns = string_agg(
|
|
35
|
+
case when row_ordinal = 1 then N'u.' + quotename(name) else char(10) + N' , u.' + quotename(name) end,
|
|
36
|
+
N''
|
|
37
|
+
) within group (order by column_id)
|
|
38
|
+
from source_columns;
|
|
39
|
+
|
|
40
|
+
$update_select
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- No primary key, so no row can be matched to a target row: there is no such
|
|
2
|
+
-- thing as an update here, and nothing to reject. The target's contents become
|
|
3
|
+
-- the source's.
|
|
4
|
+
select @weaver_target_before = count(*) from $target_table;
|
|
5
|
+
|
|
6
|
+
delete from $target_table;
|
|
7
|
+
|
|
8
|
+
insert into $target_table (
|
|
9
|
+
__SOURCE_COLUMNS__
|
|
10
|
+
, [Row insert datetime]
|
|
11
|
+
, [Row update datetime]
|
|
12
|
+
, [Row delete datetime]
|
|
13
|
+
)
|
|
14
|
+
select
|
|
15
|
+
__STAGING_SELECT_COLUMNS__
|
|
16
|
+
, @weaver_load_datetime
|
|
17
|
+
, @weaver_load_datetime
|
|
18
|
+
, @weaver_live_datetime
|
|
19
|
+
from $staging_table as s;
|
|
20
|
+
|
|
21
|
+
set @weaver_rows_inserted = @@rowcount;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* weaver generated load procedure installer. */
|
|
2
|
+
set nocount on;
|
|
3
|
+
|
|
4
|
+
declare @weaver_proc_sql nvarchar(max);
|
|
5
|
+
declare @weaver_source_columns nvarchar(max);
|
|
6
|
+
declare @weaver_staging_select_columns nvarchar(max);
|
|
7
|
+
declare @weaver_staging_except_columns nvarchar(max);
|
|
8
|
+
declare @weaver_target_except_columns nvarchar(max);
|
|
9
|
+
declare @weaver_upsert_select_columns nvarchar(max);
|
|
10
|
+
declare @weaver_update_set_columns nvarchar(max);
|
|
11
|
+
|
|
12
|
+
$column_metadata_sql
|
|
13
|
+
|
|
14
|
+
if @weaver_source_columns is null
|
|
15
|
+
begin
|
|
16
|
+
throw 51010, 'weaver: the load target has no loadable columns. Build the table before installing its load.', 1;
|
|
17
|
+
end;
|
|
18
|
+
|
|
19
|
+
set @weaver_proc_sql = $procedure_template_sql_literal;
|
|
20
|
+
set @weaver_proc_sql = replace(@weaver_proc_sql, N'__SOURCE_COLUMNS__', @weaver_source_columns);
|
|
21
|
+
set @weaver_proc_sql = replace(@weaver_proc_sql, N'__STAGING_SELECT_COLUMNS__', @weaver_staging_select_columns);
|
|
22
|
+
set @weaver_proc_sql = replace(@weaver_proc_sql, N'__STAGING_EXCEPT_COLUMNS__', @weaver_staging_except_columns);
|
|
23
|
+
set @weaver_proc_sql = replace(@weaver_proc_sql, N'__TARGET_EXCEPT_COLUMNS__', @weaver_target_except_columns);
|
|
24
|
+
set @weaver_proc_sql = replace(@weaver_proc_sql, N'__UPSERT_SELECT_COLUMNS__', @weaver_upsert_select_columns);
|
|
25
|
+
set @weaver_proc_sql = replace(@weaver_proc_sql, N'__UPDATE_SET_COLUMNS__', @weaver_update_set_columns);
|
|
26
|
+
|
|
27
|
+
exec sys.sp_executesql @weaver_proc_sql;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
create or alter procedure $load_procedure
|
|
2
|
+
@fault_tolerant bit = 0
|
|
3
|
+
, @ignore_stability_threshold bit = 0
|
|
4
|
+
as
|
|
5
|
+
begin
|
|
6
|
+
set nocount on;
|
|
7
|
+
|
|
8
|
+
declare @weaver_load_datetime datetime2(6) = sysutcdatetime();
|
|
9
|
+
declare @weaver_live_datetime datetime2(6) = convert(datetime2(6), '$live_delete_datetime');
|
|
10
|
+
declare @weaver_rows_read bigint = 0;
|
|
11
|
+
declare @weaver_rows_inserted bigint = 0;
|
|
12
|
+
declare @weaver_rows_updated bigint = 0;
|
|
13
|
+
declare @weaver_rows_deleted bigint = 0;
|
|
14
|
+
declare @weaver_rows_rejected bigint = 0;
|
|
15
|
+
declare @weaver_error varchar(4000) = null;
|
|
16
|
+
declare @weaver_target_rows bigint = 0;
|
|
17
|
+
declare @weaver_prospective_deletes bigint = 0;
|
|
18
|
+
declare @weaver_prospective_updates bigint = 0;
|
|
19
|
+
declare @weaver_target_before bigint = 0;
|
|
20
|
+
|
|
21
|
+
$preprocessing_banner
|
|
22
|
+
$start_artifact_cleanup
|
|
23
|
+
|
|
24
|
+
$staging_sql
|
|
25
|
+
|
|
26
|
+
select @weaver_rows_read = count(*) from $staging_table;
|
|
27
|
+
|
|
28
|
+
$postprocessing_banner
|
|
29
|
+
$load_body
|
|
30
|
+
|
|
31
|
+
$end_artifact_cleanup
|
|
32
|
+
|
|
33
|
+
-- What the target actually lost, from its own cardinality. The delete
|
|
34
|
+
-- driver says what the load intended; this says what happened, and the two
|
|
35
|
+
-- differ whenever a key named for deletion was not there to begin with.
|
|
36
|
+
select @weaver_rows_deleted =
|
|
37
|
+
@weaver_target_before + @weaver_rows_inserted - count(*)
|
|
38
|
+
from $target_table;
|
|
39
|
+
|
|
40
|
+
select
|
|
41
|
+
cast(case when @weaver_error is null then 1 else 0 end as bit) as succeeded
|
|
42
|
+
, @weaver_rows_read as rows_read
|
|
43
|
+
, @weaver_rows_inserted as rows_inserted
|
|
44
|
+
, @weaver_rows_updated as rows_updated
|
|
45
|
+
, @weaver_rows_deleted as rows_deleted
|
|
46
|
+
, @weaver_rows_rejected as rows_rejected
|
|
47
|
+
, @weaver_error as error_message;
|
|
48
|
+
end;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
create table $reject_table as
|
|
2
|
+
select
|
|
3
|
+
__STAGING_SELECT_COLUMNS__
|
|
4
|
+
, case
|
|
5
|
+
when $staging_blank_predicate then cast('$blank_reason' as varchar(100))
|
|
6
|
+
else cast('$duplicate_reason' as varchar(100))
|
|
7
|
+
end as [$rejection_reason]
|
|
8
|
+
from $staging_table as s
|
|
9
|
+
where $staging_blank_predicate
|
|
10
|
+
or s.[$rank_column] > 1;
|
|
11
|
+
|
|
12
|
+
select @weaver_rows_rejected = count(*) from $reject_table;
|
|
13
|
+
|
|
14
|
+
delete s
|
|
15
|
+
from $staging_table as s
|
|
16
|
+
where $staging_blank_predicate
|
|
17
|
+
or s.[$rank_column] > 1;
|
|
18
|
+
|
|
19
|
+
-- Intolerant of rejects: the target is left exactly as it was. Nothing has been
|
|
20
|
+
-- written yet, so refusing here is a decision not to start rather than an
|
|
21
|
+
-- unwind — and the reject table survives as the evidence.
|
|
22
|
+
--
|
|
23
|
+
-- Raised rather than returned, so `exec [_].[Load S.N]` fails the same way
|
|
24
|
+
-- `.load()` does. A primitive that returned a quiet row where its sibling
|
|
25
|
+
-- raised would make every caller special-case which one it was talking to.
|
|
26
|
+
if @weaver_rows_rejected > 0 and @fault_tolerant = 0
|
|
27
|
+
throw 51020, '$intolerant_message', 1;
|
|
28
|
+
|
|
29
|
+
create table $upsert_table as
|
|
30
|
+
select
|
|
31
|
+
__STAGING_SELECT_COLUMNS__
|
|
32
|
+
, case when $target_missing_predicate then cast(1 as int) else cast(0 as int) end as [_Is new row]
|
|
33
|
+
from $staging_table as s
|
|
34
|
+
left join $target_table as t on $staging_target_join
|
|
35
|
+
where
|
|
36
|
+
$target_missing_predicate
|
|
37
|
+
or exists (
|
|
38
|
+
select __STAGING_EXCEPT_COLUMNS__
|
|
39
|
+
except
|
|
40
|
+
select __TARGET_EXCEPT_COLUMNS__
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
-- Everything this load is about to do, counted before it does any of it. A
|
|
44
|
+
-- breach with @fault_tolerant = 0 leaves the target exactly as it was, so
|
|
45
|
+
-- refusing is a decision not to start rather than an unwind.
|
|
46
|
+
select @weaver_target_rows = count(*) from $target_table;
|
|
47
|
+
set @weaver_target_before = @weaver_target_rows;
|
|
48
|
+
select @weaver_prospective_updates = count(*) from $upsert_table where [_Is new row] = 0;
|
|
49
|
+
$prospective_deletes
|
|
50
|
+
|
|
51
|
+
if @ignore_stability_threshold = 0 and @weaver_target_rows > 0
|
|
52
|
+
and @weaver_target_rows >= $stability_rows
|
|
53
|
+
begin
|
|
54
|
+
if @weaver_prospective_deletes * 100.0 / @weaver_target_rows > $delete_threshold
|
|
55
|
+
set @weaver_error = 'delete of ' + cast(@weaver_prospective_deletes as varchar(20))
|
|
56
|
+
+ ' rows is over the $delete_threshold% threshold of '
|
|
57
|
+
+ cast(@weaver_target_rows as varchar(20));
|
|
58
|
+
else if @weaver_prospective_updates * 100.0 / @weaver_target_rows > $update_threshold
|
|
59
|
+
set @weaver_error = 'update of ' + cast(@weaver_prospective_updates as varchar(20))
|
|
60
|
+
+ ' rows is over the $update_threshold% threshold of '
|
|
61
|
+
+ cast(@weaver_target_rows as varchar(20));
|
|
62
|
+
|
|
63
|
+
-- A breach never writes. Tolerating exactly the change the threshold was
|
|
64
|
+
-- declared to prevent would defeat the guard, so @fault_tolerant decides
|
|
65
|
+
-- only whether the refusal is raised or returned. Permitting it is what
|
|
66
|
+
-- @ignore_stability_threshold is for.
|
|
67
|
+
if @weaver_error is not null
|
|
68
|
+
begin
|
|
69
|
+
set @weaver_error = @weaver_error + '; the target was not modified';
|
|
70
|
+
if @fault_tolerant = 0
|
|
71
|
+
throw 51021, @weaver_error, 1;
|
|
72
|
+
select
|
|
73
|
+
cast(0 as bit) as succeeded
|
|
74
|
+
, @weaver_rows_read as rows_read
|
|
75
|
+
, cast(0 as bigint) as rows_inserted
|
|
76
|
+
, cast(0 as bigint) as rows_updated
|
|
77
|
+
, cast(0 as bigint) as rows_deleted
|
|
78
|
+
, @weaver_rows_rejected as rows_rejected
|
|
79
|
+
, @weaver_error as error_message;
|
|
80
|
+
return;
|
|
81
|
+
end;
|
|
82
|
+
end;
|
|
83
|
+
|
|
84
|
+
insert into $target_table (
|
|
85
|
+
__SOURCE_COLUMNS__
|
|
86
|
+
, [Row insert datetime]
|
|
87
|
+
, [Row update datetime]
|
|
88
|
+
, [Row delete datetime]
|
|
89
|
+
)
|
|
90
|
+
select
|
|
91
|
+
__UPSERT_SELECT_COLUMNS__
|
|
92
|
+
, @weaver_load_datetime
|
|
93
|
+
, @weaver_load_datetime
|
|
94
|
+
, @weaver_live_datetime
|
|
95
|
+
from $upsert_table as u
|
|
96
|
+
where u.[_Is new row] = 1;
|
|
97
|
+
|
|
98
|
+
set @weaver_rows_inserted = @@rowcount;
|
|
99
|
+
|
|
100
|
+
update c
|
|
101
|
+
set
|
|
102
|
+
__UPDATE_SET_COLUMNS__
|
|
103
|
+
from $target_table as c
|
|
104
|
+
inner join $upsert_table as u on $target_upsert_join
|
|
105
|
+
where u.[_Is new row] = 0;
|
|
106
|
+
|
|
107
|
+
set @weaver_rows_updated = @@rowcount;
|
|
108
|
+
|
|
109
|
+
$missing_reconciliation
|
|
110
|
+
|
|
111
|
+
if @weaver_rows_rejected > 0 and @weaver_error is null
|
|
112
|
+
set @weaver_error = cast(@weaver_rows_rejected as varchar(20))
|
|
113
|
+
+ ' $tolerated_message';
|