Repository navigation
Commit d2b4ce2
authored
fix: Snowflake, scenario, rule and type correctness batch (#1250)
* fix(snowflake): bind listed source columns as unquoted identifiers
Planning rebinds models against the source columns it lists from the
warehouse. The Snowflake adapter lists column names lowercased, and the
rebinding stored them quoted ("bundle_sku"), so an ordinary unquoted
reference, which Snowflake resolves as BUNDLE_SKU, failed with B002
unless the session set QUOTED_IDENTIFIERS_IGNORE_CASE.
Plain single-case names are now stored unquoted on Snowflake, so they
bind the way Snowflake resolves unquoted names. Mixed-case or special
names stay quoted.
BREAKING CHANGE: on Snowflake without QUOTED_IDENTIFIERS_IGNORE_CASE, a
quoted lowercase reference such as "bundle_sku" to a listed source column
now reports B002 during planning, as Snowflake would reject it against an
upper-case column. The listing cannot tell a column really created with a
quoted lowercase name apart, so such columns now bind as unquoted names.
* fix(snowflake): parse loader JSON in the select list, not inside VALUES
Row-returning managed-source loaders rendered VARIANT values as
PARSE_JSON(...) inside the VALUES list, but Snowflake allows only
constants there, so those loads failed. JSON values are now written as
string constants and parsed with PARSE_JSON in the projection over the
VALUES rows.
Snowflake string literals treat backslashes as escapes, so the adapter
now doubles them when quoting loader strings. Without that, JSON escapes
such as \" and any backslash in a loaded string were altered.
* fix(scenario): fingerprint local snapshots from the authored fixture SQL
The local snapshot fingerprint hashed fixture SQL after the running
adapter rendered it. Capture on Snowflake and replay on DuckDB render a
partial fixture's wrapper alias in different case, and capture can add
casts from warehouse column types that offline planning does not, so a
snapshot was reported stale (X602) right after it was captured, and
capturing again did not help.
Fixture plans now carry the authored fixture SQL, and the fingerprint
uses it, so capture and local replay agree.
BREAKING CHANGE: local scenario snapshots captured by earlier versions
report as stale once. Run `sqb scenario capture` to refresh them.
* fix(scenario): stop treating lambda parameters as mock columns
The fixture checker's column-read walk counted lambda parameters, such as
i in FILTER(items, i -> ...) and acc and q in (acc, q) -> acc + q, as
unqualified column reads. When one relation in scope was read through a
star, those names resolved to it and the scenario failed with S510
asking the mock to supply them.
Unqualified references to a lambda's own parameters are now skipped in
projections and in clauses. Compile lineage and column-reference
rewriting already scoped lambda parameters. DuckShop's cart funnel
scenario drops its placeholder acc, i and q mock columns.
* fix(scenario): treat contract-enforced models as authoritative fixture schemas
A contract-enforced model whose query selected a star was treated as
having a non-authoritative schema, so `__empty_fixture()` mocks of it were
rejected (S510), and so were the `__empty_fixture()` fixtures `sqb format`
writes for typed `WHERE FALSE` fixtures of contracted models. An enforced
contract fixes the model's output columns, so its declared schema is now
authoritative whatever the query looks like.
* fix(rules): do not flag LIMIT 0 as nondeterministic row selection
SQBRSQL004 flagged `LIMIT 0` without ORDER BY, though it selects no rows
in any order. Empty fixtures written as `SELECT ... LIMIT 0` tripped it.
* fix(test): cast bare NULL columns of set-operation fixtures to declared types
A fixture's bare NULL columns are cast to the mocked relation's declared
types, but only when the fixture was a single SELECT. A fixture written as
a UNION ALL of rows kept untyped NULLs, so typed functions over them
failed, for example YEAR(NULL) on Snowflake or DuckDB. Set operations now
take their NULL columns from the first branch, which names the output.
* fix(build): skip tests and end-of-build audits that read unbuilt resources
When a model failed, an end-of-build audit that read it still ran and
failed with "object does not exist". A SQL test that called a table
function skipped because of the same failure also ran: failure blocking
only reached selected models and functions, not tests in the execution
order. Both are now skipped, like the audits attached to a skipped model.
* fix(scenario): build cursor-intrinsic incremental models over a wide window
A scenario rebuilds every model it runs from scratch, and a
non-microbatch full rebuild has no cursor interval, so a scenario that
ran an incremental model calling __cursor_start() or __cursor_end()
failed. Such models now run over the same wide window SQL tests use
(1900-01-01 to 2999-12-31, or the integer equivalent), so mocked rows
are not filtered out. Microbatch models keep discovering their range
from their inputs.
* fix(audits): require a relation reference as the relationships target
A built-in relationships audit written as `to "fct_orders"` compiled
without complaint, but it queried a bare, unqualified table name and did
not depend on the model, so it could run before that table existed, or
read another one. The documentation showed that form. The `to` argument
must now be a `__ref(...)`, `__source(...)`, `__seed(...)` or
`__dbt_ref(...)` call, and compile says which reference to write.
BREAKING CHANGE: a built-in `relationships` audit whose `to` is a plain
or quoted relation name is now a compile error (P001). Write
`to __ref("name")` (or `__source` / `__seed`) instead.
* fix(build): do not reload managed sources when loading is off
Without --select, a build's default selection included every managed
source and its Python loader, so `sqb build --no-load` and
`auto_load_sources = false` still ran the loaders. With loading off, the
default selection now leaves managed sources and their loaders out. A
source selected by name still loads.
BREAKING CHANGE: `sqb build --no-load`, or a build with
`auto_load_sources = false`, no longer runs managed-source loaders unless
the source is selected explicitly.
* fix(types): compare sized TEXT and STRING as VARCHAR
A sized TEXT(n) or STRING(n) normalised as an unrelated type, so a
contract declaring VARCHAR(n) rejected a column cast to TEXT(n).
Sized variable-length text now normalises as VARCHAR(n) outside
BigQuery, and BigQuery spells every variable-length text type STRING.
The generated-type golden is re-recorded for the new spellings.
* fix(headers): read a meta description as an ordinary string
Header scanners and the tokenizer applied the prose quoting rules to
any string after a description key, so a meta value such as
meta (description "say \", then") ended at the escaped quote and the
header failed to parse. Prose rules now apply only to description keys
outside a meta value.
* fix(rules): compare contract casts as the dialect does and point at the cast
SQBRCONTRACT105 compared an outer cast's type with the declared contract
type by spelling, so on Snowflake CAST(... AS VARCHAR(16777216)) or
CAST(... AS STRING) was rejected against a VARCHAR contract. Both types
are now normalized for the target dialect before comparing.
A mismatched outer cast now names the cast's type and the declared
type, points at the CAST itself, and asks to change the cast rather
than wrap the expression in another one.
Model rule locations were relative to the query below the header, so
they pointed at header lines. They are now lines of the model file.
* fix(format): lay out column and audit descriptions like the model's
sqb format laid out only a header's own description: one line when
it fits, otherwise an indented triple-quoted block. Column and audit
descriptions now get the same layout at their own nesting depth.
Formatting is idempotent and stored text is unchanged.
* fix(rules): lint parameterised SQL tests instead of failing with L005
SQL rules expand a test file before linting it, and @PARAM("name")
is not a macro, so every parameterised test failed with L005 while a
SQBRSQL rule was selected. Test parameter references now stand as
string sentinels for linting, as audit parameters already do.
* fix(scenario): stop asking fixtures for CONNECT BY pseudo-columns
The fixture checker read LEVEL, CONNECT_BY_ISLEAF and CONNECT_BY_ISCYCLE
in a CONNECT BY query as unqualified input columns. When a relation in
scope was read through a star, they resolved to it and the scenario
failed with S510 asking the mock for them. They now read no input in a
SELECT that has a CONNECT BY clause.
* fix(test): let a macro mock name its value
A macro mock had to be a bare SELECT of one string literal, which
SQBRSQL022 rejects as a calculated projection with no stable name, so
every macro mock needed a rule exception. The literal may now carry an
AS alias, which is ignored. DuckShop's mock uses one and drops its
exception.
* fix(rules): accept a test file of several TEST blocks in SQBRTEST102
SQBRTEST102 asked a test file to be named after each of its blocks'
behaviours, which no file holding two differently named blocks can
satisfy. A file of several blocks now needs only the
test_<subject>__<behavior>.sql grammar. DuckShop drops its exception.
* fix(macros): check SQL macro argument types for every adapter's dialect
SQL macro argument types were parsed only for four adapters, so a
Postgres argument of type FOO BAR or a MotherDuck INTEGER NOT NULL
compiled silently, and argument decimals were never range-checked.
Argument types now go through the same per-dialect check as returns.
BigQuery NUMERIC and BIGNUMERIC types beyond their integer-digit and
scale limits, such as NUMERIC(40, 2), are now reported too. Adds an E2E
for BigQuery STRING contracts filled by sized VARCHAR casts.
BREAKING CHANGE: SQL macros whose argument types the adapter's dialect
cannot parse or hold, and BigQuery NUMERIC or BIGNUMERIC types wider
than BigQuery allows, now fail to compile with P015.
* docs(duckshop): drop known limitations that are now fixed
Removes the limitations this batch fixes: unquoted Snowflake column
references after rebinding, JSON loader rows, managed sources reloaded
with loading off, cursor-intrinsic incremental models and empty fixtures
in scenarios, stale snapshots, untyped NULL source fixtures, tests and
audits over skipped resources, and macro tests of folder-scoped macros.
* fix(test): cast only set-operation fixture columns that are NULL in every branch
Casting a set-operation fixture's bare NULL columns to the declared types
also cast columns that a later branch already typed, changing that
branch's values. Only columns that are a bare NULL in every branch are
now cast; a typed value in any branch types the column as before.
* test: update expectations for model rule lines, nested description layout and BigQuery STRING
Model rule findings now carry file lines, column descriptions are laid
out like the model's, BigQuery compares VARCHAR and STRING as one type,
and builds that should run loaders opt in to loading sources.
* test: run the new build and scenario E2E files in their DuckDB shards
* refactor: share the description layout and first-select walks with their new siblings
* fix(rules): stop exempting typed SQL macro calls from SQBRCONTRACT105
A select-list item that was one call to a macro with returns passed
SQBRCONTRACT105 without a cast. returns is analysis-only and never
reaches the generated SQL, so a body such as 'ACTIVE' created a
VARCHAR(6) column under a VARCHAR contract with no error. A call now
establishes the contract type only when the generated SQL casts it to
that type: the macro body ends in CAST(... AS type) or ...::type, or the
call is cast. Otherwise the rule names the macro and its returns type
and asks for a cast in the macro or at the call. returns TYPE OF calls
follow the same rule.
BREAKING CHANGE: a contracted output that is one call to a SQL macro
with returns, whose body is not cast to the contract type, now fails
SQBRCONTRACT105 until the body or the call is cast.
* fix(scenario): create local replay databases at the latest DuckDB storage version
Local scenario replay created its DuckDB file at DuckDB's default
storage version, v1.0.0, which cannot hold VARIANT columns, so a
captured snapshot with a VARIANT column, such as a PARSE_JSON fixture
on Snowflake, failed with X699. The local database is sqlbuild's own
and recreated on every run, so it is now opened with
storage_compatibility_version = latest. The DuckDB adapter passes that
connection option through; existing database files keep their own
storage version and still open.
* fix(scenario): fingerprint the helper CTEs and references behind a fixture
The local snapshot fingerprint hashed only a fixture's own authored
text, so editing a helper CTE the fixture reads, such as changing
helper_ids from SELECT 1 to SELECT 2, left a stale snapshot looking
fresh. The fingerprint now also covers the authored body of every
helper CTE the fixture reads, transitively, and whether each relation
reference in them reads a scenario fixture or the warehouse. All of it
is authored, adapter-neutral text, so a snapshot captured on one
adapter stays fresh when replayed on another.
BREAKING CHANGE: local scenario snapshots captured by earlier versions
report as stale once. Run sqb scenario capture to refresh them.
* fix(build): audit managed sources instead of dropping them when loading is off
With loading off, the previous fix dropped managed sources from the
default selection along with their loaders, so their audits stopped
running and a build over bad source data passed. Loading off now means
only that no loader runs: managed sources stay in the plan without a
load step, and their audits check the data they already hold. This
holds for --no-load and auto_load_sources = false, and now also with
--select, where naming a managed source used to run its loader anyway.
Audits of a selected source that loads nothing and that no model read
during the build run at the end of the build.
BREAKING CHANGE: with --no-load or auto_load_sources = false, no
managed-source loader runs, even for a source selected by name.
Selected managed sources are audited against their existing data, so
a build over failing source data now fails.
* fix(build): report end-of-build audits over unbuilt resources as skipped
An end-of-build audit that read a resource the build did not build was
dropped from the results without a trace. It is now recorded with a new
skipped audit outcome and the reason, such as "reads broken_orders,
which was not built", shown on its progress row, in the skipped rollup,
in the JSON checks and in the SKIP count. Skipped audits are not
written to audit result history.
A model counted as unbuilt whenever it failed or was skipped, including
a model a Python hook skipped on purpose, whose relation still holds
earlier data. Only a model that was not built and has no existing
relation now counts as unbuilt, so the end-of-build audits over a
hook-skipped model run.
* docs(loaders): note that Snowflake loader strings keep their backslashes
Loader string values on Snowflake now have every backslash escaped, so
values are stored exactly as returned. Documents the effect on keys
loaded by earlier releases.
BREAKING CHANGE: Snowflake loader string values containing backslashes
are now stored literally. Earlier releases wrote them unescaped, so
merge, delete_insert or append deduplication keys containing
backslashes will not match rows those releases loaded.
* fix(duckdb): keep the replay storage version out of user connection config
The DuckDB adapter read storage_compatibility_version from the
connection config, which made it a user setting for project
warehouses. The latest storage version now applies only to the local
scenario replay database, through an internal adapter method, and a
user config naming the key ignores it like any other unknown key.
* fix(build): audit unread sources only with loading off or when selected
End-of-build source audits ran for every source no model read, on every
build, so a plain build over an unmanaged source with a missing table
failed. They now run only when loading is off (--no-load or
auto_load_sources = false), or for a source selected by name. With
loading on and no such selection, a source is audited only before a
model that reads it, as before.
An unbuilt model is now one that was not built and whose relation the
inspected warehouse does not hold, rather than one planned as a first
run, so a full refresh on a fresh warehouse skips the end audits over a
failed model.
* fix(dagster): emit no check result for an audit that did not run
An end-of-build audit skipped because it reads a resource the build did
not build has passed: false in the JSON checks, so Dagster reported it
as a failed asset check, even in a green build. The Dagster integration
now emits no check result for a skipped audit, which Dagster shows as
not evaluated, and logs the audit and its skip reason instead. The JSON
shape is unchanged.1 parent 9a7d605 commit d2b4ce2
149 files changed
Lines changed: 4106 additions & 642 deletions
File tree
- benchmarks/duckshop
- project
- tests
- scenarios/clickstream
- unit/staging/storefront
- crates
- sqlbuild-analysis/src
- assembly/analysis_session
- _helpers
- compiler/_helpers/sql_tests
- planner_scope/main
- required_columns
- _helpers
- sql_macros
- _helpers
- rendering
- typing
- tests
- sql_test_attachment/tests
- type_system
- _helpers
- tests
- sqlbuild-attachments/src/audits
- _helpers
- main
- tests
- sqlbuild-core/src
- build_aggregate
- main
- build_progress
- _helpers
- integration_results
- progress
- sqlbuild-host/src
- tests
- sqlbuild-python/src/bindings/_helpers
- build_progress
- compile_driver
- dagster_invocation
- planner_entries
- planner_records
- planner_scenario
- planner_scope
- planner_strategy
- result_output
- rules
- semantic_shapes
- sql_test_glue
- sqlbuild-rules/src
- dsl_headers
- _helpers
- main
- engine
- _helpers
- tests
- lint_text
- main
- tests
- query_facts
- rules/_helpers
- sql_lint
- _helpers
- tests
- sqlbuild-sqltext/src/header_strings
- _helpers
- main
- tests
- src/sqlbuild
- .agents/skills/sqlbuild/references/docs
- cli
- concepts
- macros
- python-nodes
- adapters/snowflake/classes
- adapter/contract
- classes
- compiler/auditing
- executor
- auditing
- build
- _helpers
- classes
- main
- scenario
- _helpers
- local
- snapshots
- integrations/dagster/_helpers
- tests
- e2e/src/sqlbuild
- cli/commands/main
- build
- compile
- header_strings
- sql_macros
- format
- rules
- scenario
- test
- integrations/dagster
- goldens/python_oracle
- integration/src/sqlbuild
- adapters/duckdb
- cli/commands/main
- compiler/pipeline
- executor
- build
- concurrent
- snowflake_metadata
- scenario
- rule_engine/native_rows
- unit/src/sqlbuild
- adapter/contract
- lint/_helpers
- website/src/content/docs/docs
- cli
- concepts
- macros
- python-nodes
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
110 | 110 | | |
111 | 111 | | |
112 | 112 | | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
113 | 117 | | |
114 | 118 | | |
115 | 119 | | |
| |||
147 | 151 | | |
148 | 152 | | |
149 | 153 | | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
150 | 157 | | |
151 | 158 | | |
152 | 159 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
129 | 129 | | |
130 | 130 | | |
131 | 131 | | |
132 | | - | |
| 132 | + | |
| 133 | + | |
133 | 134 | | |
134 | 135 | | |
135 | 136 | | |
| |||
148 | 149 | | |
149 | 150 | | |
150 | 151 | | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | | - | |
173 | 152 | | |
174 | 153 | | |
175 | | - | |
176 | | - | |
177 | 154 | | |
178 | 155 | | |
179 | 156 | | |
180 | 157 | | |
181 | 158 | | |
182 | 159 | | |
183 | 160 | | |
184 | | - | |
185 | | - | |
186 | | - | |
187 | | - | |
188 | | - | |
189 | | - | |
190 | | - | |
191 | | - | |
192 | | - | |
193 | | - | |
194 | | - | |
195 | | - | |
196 | | - | |
197 | | - | |
198 | 161 | | |
199 | 162 | | |
200 | 163 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
235 | 235 | | |
236 | 236 | | |
237 | 237 | | |
238 | | - | |
239 | | - | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
245 | | - | |
246 | | - | |
247 | | - | |
248 | | - | |
249 | | - | |
250 | | - | |
251 | | - | |
252 | | - | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
| 25 | + | |
31 | 26 | | |
32 | 27 | | |
33 | 28 | | |
| |||
46 | 41 | | |
47 | 42 | | |
48 | 43 | | |
49 | | - | |
50 | | - | |
51 | | - | |
52 | | - | |
| 44 | + | |
53 | 45 | | |
54 | 46 | | |
55 | 47 | | |
| |||
68 | 60 | | |
69 | 61 | | |
70 | 62 | | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
| 63 | + | |
75 | 64 | | |
76 | 65 | | |
77 | 66 | | |
| |||
103 | 92 | | |
104 | 93 | | |
105 | 94 | | |
106 | | - | |
107 | | - | |
108 | | - | |
| 95 | + | |
109 | 96 | | |
110 | 97 | | |
111 | 98 | | |
| |||
125 | 112 | | |
126 | 113 | | |
127 | 114 | | |
128 | | - | |
129 | | - | |
| 115 | + | |
130 | 116 | | |
131 | 117 | | |
132 | 118 | | |
| |||
153 | 139 | | |
154 | 140 | | |
155 | 141 | | |
156 | | - | |
157 | | - | |
| 142 | + | |
158 | 143 | | |
159 | 144 | | |
160 | 145 | | |
| |||
174 | 159 | | |
175 | 160 | | |
176 | 161 | | |
177 | | - | |
178 | | - | |
| 162 | + | |
179 | 163 | | |
180 | 164 | | |
181 | 165 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
16 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
452 | 453 | | |
453 | 454 | | |
454 | 455 | | |
| 456 | + | |
455 | 457 | | |
456 | | - | |
457 | | - | |
458 | | - | |
| 458 | + | |
459 | 459 | | |
460 | 460 | | |
461 | | - | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
462 | 467 | | |
463 | 468 | | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
464 | 483 | | |
465 | 484 | | |
466 | 485 | | |
467 | | - | |
468 | | - | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
469 | 489 | | |
470 | 490 | | |
471 | 491 | | |
472 | 492 | | |
473 | 493 | | |
474 | | - | |
| 494 | + | |
| 495 | + | |
475 | 496 | | |
476 | 497 | | |
477 | 498 | | |
478 | 499 | | |
479 | 500 | | |
480 | 501 | | |
481 | 502 | | |
482 | | - | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
483 | 551 | | |
484 | 552 | | |
485 | 553 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
212 | 212 | | |
213 | 213 | | |
214 | 214 | | |
| 215 | + | |
| 216 | + | |
215 | 217 | | |
216 | 218 | | |
217 | 219 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
683 | 683 | | |
684 | 684 | | |
685 | 685 | | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
686 | 694 | | |
687 | 695 | | |
688 | 696 | | |
| |||
692 | 700 | | |
693 | 701 | | |
694 | 702 | | |
| 703 | + | |
| 704 | + | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
695 | 717 | | |
696 | 718 | | |
697 | 719 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | | - | |
| 10 | + | |
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
25 | | - | |
| 26 | + | |
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
31 | 35 | | |
32 | 36 | | |
33 | 37 | | |
| |||
0 commit comments