Skip to content

Commit 4771ae1

Browse files
committed
Design-time caching fix
1 parent bfa248b commit 4771ae1

27 files changed

Lines changed: 136 additions & 104 deletions

File tree

‎docs/RELEASE_NOTES.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
### 1.5.26 - 09.07.2026
2+
- HAVING OR fix
3+
- Math.Round(col, n) support
4+
- apostrophe-escape fix on ODBC
5+
16
### 1.5.25 - 03.07.2026
27
* leftOuterJoin: groupBy after a left outer join is now supported (SQL semantics: COUNT counts the unmatched NULL row)
38
* groupJoin: `groupJoin ... into g` + `for x in g do` now works (inner join semantics); aggregating the group (e.g. `g.Count()`) fails with a clear message instead of returning wrong results

‎src/SQLProvider.Common/AssemblyInfo.fs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ open System.Reflection
55
[<assembly: AssemblyTitleAttribute("SQLProvider.Common")>]
66
[<assembly: AssemblyProductAttribute("SQLProvider")>]
77
[<assembly: AssemblyDescriptionAttribute("Type provider for SQL database access, common library")>]
8-
[<assembly: AssemblyVersionAttribute("1.5.25")>]
9-
[<assembly: AssemblyFileVersionAttribute("1.5.25")>]
8+
[<assembly: AssemblyVersionAttribute("1.5.26")>]
9+
[<assembly: AssemblyFileVersionAttribute("1.5.26")>]
1010
do ()
1111

1212
module internal AssemblyVersionInformation =
1313
let [<Literal>] AssemblyTitle = "SQLProvider.Common"
1414
let [<Literal>] AssemblyProduct = "SQLProvider"
1515
let [<Literal>] AssemblyDescription = "Type provider for SQL database access, common library"
16-
let [<Literal>] AssemblyVersion = "1.5.25"
17-
let [<Literal>] AssemblyFileVersion = "1.5.25"
16+
let [<Literal>] AssemblyVersion = "1.5.26"
17+
let [<Literal>] AssemblyFileVersion = "1.5.26"

‎src/SQLProvider.DesignTime/AssemblyInfo.fs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ open System.Reflection
55
[<assembly: AssemblyTitleAttribute("SQLProvider.DesignTime")>]
66
[<assembly: AssemblyProductAttribute("SQLProvider")>]
77
[<assembly: AssemblyDescriptionAttribute("Type providers for any SQL database access.")>]
8-
[<assembly: AssemblyVersionAttribute("1.5.25")>]
9-
[<assembly: AssemblyFileVersionAttribute("1.5.25")>]
8+
[<assembly: AssemblyVersionAttribute("1.5.26")>]
9+
[<assembly: AssemblyFileVersionAttribute("1.5.26")>]
1010
do ()
1111

1212
module internal AssemblyVersionInformation =
1313
let [<Literal>] AssemblyTitle = "SQLProvider.DesignTime"
1414
let [<Literal>] AssemblyProduct = "SQLProvider"
1515
let [<Literal>] AssemblyDescription = "Type providers for any SQL database access."
16-
let [<Literal>] AssemblyVersion = "1.5.25"
17-
let [<Literal>] AssemblyFileVersion = "1.5.25"
16+
let [<Literal>] AssemblyVersion = "1.5.26"
17+
let [<Literal>] AssemblyFileVersion = "1.5.26"

‎src/SQLProvider.DesignTime/SqlDesignTime.fs‎

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,9 +1541,13 @@ type public SqlTypeProvider(config: TypeProviderConfig) as this =
15411541
createConstructors config (rootType, serviceType, readServiceType, args)
15421542

15431543
// Refresh no sooner than the idle expiration, and on a slow system no sooner than
1544-
// 5x the time a build takes, so refreshes cannot put the system under pressure.
1544+
// 10x the time a build takes. Fetching the full schema of a big database is heavy;
1545+
// the staleness window must stay well above the fetch time so a refresh always
1546+
// finishes long before the next one is due. Otherwise refreshes (each followed by a
1547+
// re-check) would overlap and build back-pressure that eventually stalls the UI.
1548+
// The window is derived from this build's own duration, so it adapts as the schema grows.
15451549
let buildDuration = DateTime.UtcNow - buildStarted
1546-
let staleAfter = max idleExpiration (TimeSpan.FromTicks(buildDuration.Ticks * 5L))
1550+
let staleAfter = max idleExpiration (TimeSpan.FromTicks(buildDuration.Ticks * 10L))
15471551
rootType, DateTime.UtcNow, staleAfter
15481552

15491553
let dropDesignTimeDcProvider (key:DesignCacheKey) =
@@ -1570,7 +1574,11 @@ type public SqlTypeProvider(config: TypeProviderConfig) as this =
15701574
{ Root =
15711575
lazy
15721576
let generation = buildRoot key
1573-
idleWatcher key |> Async.Start
1577+
// Only reclaim idle entries in a live host (IDE). In a batch compile
1578+
// (fsc/CI, IsInvalidationSupported=false) the process is short-lived and an
1579+
// eviction+rebuild would hand out a second generation of erased provided
1580+
// types, which then fail to unify against the first.
1581+
if config.IsInvalidationSupported then idleWatcher key |> Async.Start
15741582
generation
15751583
LastAccess = DateTime.UtcNow.Ticks
15761584
Refreshing = 0 }
@@ -1582,18 +1590,37 @@ type public SqlTypeProvider(config: TypeProviderConfig) as this =
15821590
// Stale-while-revalidate: always serve the current tree; if it has gone stale,
15831591
// rebuild it once in the background and swap the entry atomically. Callers never
15841592
// wait on a refresh, and concurrent VS threads can never start a second one.
1585-
if entry.Root.IsValueCreated then
1593+
//
1594+
// Only ever swap generations in a live host (IDE, IsInvalidationSupported=true).
1595+
// In a batch compile (fsc/CI) the swap is unsafe: erased provided types have
1596+
// reference identity, so if a long compilation binds some sites to the original
1597+
// generation and later sites to the swapped-in one, the two identical-looking
1598+
// 'CustomersEntity' types fail to unify (FS0001/FS0193). Windows CI builds two
1599+
// target frameworks and so is slow enough to cross the staleness window mid-build,
1600+
// which is why it fails there while Linux/Mac and warm local builds pass.
1601+
if config.IsInvalidationSupported && entry.Root.IsValueCreated then
15861602
let _, builtAt, staleAfter = entry.Root.Value
15871603
if DateTime.UtcNow - builtAt >= staleAfter
15881604
&& System.Threading.Interlocked.CompareExchange(&entry.Refreshing, 1, 0) = 0 then
15891605
async {
15901606
try
15911607
try
1608+
// 1. Fetch/build the new generation fully in the background. Nothing
1609+
// waits on it: on-demand callers keep getting the previous tree, so
1610+
// a slow big-database schema fetch never blocks the editor.
15921611
let freshGeneration = buildRoot arguments
15931612
let freshEntry =
15941613
{ Root = Lazy<_>.CreateFromValue freshGeneration
15951614
LastAccess = DateTime.UtcNow.Ticks
15961615
Refreshing = 0 }
1616+
// 2. Only now that the new generation is ready, invalidate. This makes
1617+
// the host re-check bind straight to the finished tree instead of
1618+
// driving a fresh blocking build on demand. It fires at most once per
1619+
// staleness window (>= 10x the build time), so it cannot churn.
1620+
this.Invalidate()
1621+
// 3. Publish it. Invalidate() only schedules a later re-check, so the
1622+
// atomic swap always lands before the host re-reads the cache; the
1623+
// re-check then finds a fresh (non-stale) entry and triggers no rebuild.
15971624
if DesignTimeCache.cache.TryUpdate(arguments, freshEntry, entry) then
15981625
dropDesignTimeDcProvider arguments
15991626
with

‎src/SQLProvider.DuckDb.DesignTime/AssemblyInfo.fs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ open System.Reflection
55
[<assembly: AssemblyTitleAttribute("SQLProvider.DuckDb.DesignTime")>]
66
[<assembly: AssemblyProductAttribute("SQLProvider")>]
77
[<assembly: AssemblyDescriptionAttribute("Type providers for DuckDb database access.")>]
8-
[<assembly: AssemblyVersionAttribute("1.5.25")>]
9-
[<assembly: AssemblyFileVersionAttribute("1.5.25")>]
8+
[<assembly: AssemblyVersionAttribute("1.5.26")>]
9+
[<assembly: AssemblyFileVersionAttribute("1.5.26")>]
1010
do ()
1111

1212
module internal AssemblyVersionInformation =
1313
let [<Literal>] AssemblyTitle = "SQLProvider.DuckDb.DesignTime"
1414
let [<Literal>] AssemblyProduct = "SQLProvider"
1515
let [<Literal>] AssemblyDescription = "Type providers for DuckDb database access."
16-
let [<Literal>] AssemblyVersion = "1.5.25"
17-
let [<Literal>] AssemblyFileVersion = "1.5.25"
16+
let [<Literal>] AssemblyVersion = "1.5.26"
17+
let [<Literal>] AssemblyFileVersion = "1.5.26"

‎src/SQLProvider.DuckDb.Runtime/AssemblyInfo.fs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ open System.Reflection
55
[<assembly: AssemblyTitleAttribute("SQLProvider.DuckDb.Runtime")>]
66
[<assembly: AssemblyProductAttribute("SQLProvider")>]
77
[<assembly: AssemblyDescriptionAttribute("Type providers for DuckDb database access.")>]
8-
[<assembly: AssemblyVersionAttribute("1.5.25")>]
9-
[<assembly: AssemblyFileVersionAttribute("1.5.25")>]
8+
[<assembly: AssemblyVersionAttribute("1.5.26")>]
9+
[<assembly: AssemblyFileVersionAttribute("1.5.26")>]
1010
do ()
1111

1212
module internal AssemblyVersionInformation =
1313
let [<Literal>] AssemblyTitle = "SQLProvider.DuckDb.Runtime"
1414
let [<Literal>] AssemblyProduct = "SQLProvider"
1515
let [<Literal>] AssemblyDescription = "Type providers for DuckDb database access."
16-
let [<Literal>] AssemblyVersion = "1.5.25"
17-
let [<Literal>] AssemblyFileVersion = "1.5.25"
16+
let [<Literal>] AssemblyVersion = "1.5.26"
17+
let [<Literal>] AssemblyFileVersion = "1.5.26"

‎src/SQLProvider.Firebird.DesignTime/AssemblyInfo.fs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ open System.Reflection
55
[<assembly: AssemblyTitleAttribute("SQLProvider.Firebird.DesignTime")>]
66
[<assembly: AssemblyProductAttribute("SQLProvider")>]
77
[<assembly: AssemblyDescriptionAttribute("Type providers for Firebird database access.")>]
8-
[<assembly: AssemblyVersionAttribute("1.5.25")>]
9-
[<assembly: AssemblyFileVersionAttribute("1.5.25")>]
8+
[<assembly: AssemblyVersionAttribute("1.5.26")>]
9+
[<assembly: AssemblyFileVersionAttribute("1.5.26")>]
1010
do ()
1111

1212
module internal AssemblyVersionInformation =
1313
let [<Literal>] AssemblyTitle = "SQLProvider.Firebird.DesignTime"
1414
let [<Literal>] AssemblyProduct = "SQLProvider"
1515
let [<Literal>] AssemblyDescription = "Type providers for Firebird database access."
16-
let [<Literal>] AssemblyVersion = "1.5.25"
17-
let [<Literal>] AssemblyFileVersion = "1.5.25"
16+
let [<Literal>] AssemblyVersion = "1.5.26"
17+
let [<Literal>] AssemblyFileVersion = "1.5.26"

‎src/SQLProvider.Firebird.Runtime/AssemblyInfo.fs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ open System.Reflection
55
[<assembly: AssemblyTitleAttribute("SQLProvider.Firebird.Runtime")>]
66
[<assembly: AssemblyProductAttribute("SQLProvider")>]
77
[<assembly: AssemblyDescriptionAttribute("Type providers for Firebird database access.")>]
8-
[<assembly: AssemblyVersionAttribute("1.5.25")>]
9-
[<assembly: AssemblyFileVersionAttribute("1.5.25")>]
8+
[<assembly: AssemblyVersionAttribute("1.5.26")>]
9+
[<assembly: AssemblyFileVersionAttribute("1.5.26")>]
1010
do ()
1111

1212
module internal AssemblyVersionInformation =
1313
let [<Literal>] AssemblyTitle = "SQLProvider.Firebird.Runtime"
1414
let [<Literal>] AssemblyProduct = "SQLProvider"
1515
let [<Literal>] AssemblyDescription = "Type providers for Firebird database access."
16-
let [<Literal>] AssemblyVersion = "1.5.25"
17-
let [<Literal>] AssemblyFileVersion = "1.5.25"
16+
let [<Literal>] AssemblyVersion = "1.5.26"
17+
let [<Literal>] AssemblyFileVersion = "1.5.26"

‎src/SQLProvider.MsAccess.DesignTime/AssemblyInfo.fs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ open System.Reflection
55
[<assembly: AssemblyTitleAttribute("SQLProvider.MsAccess.DesignTime")>]
66
[<assembly: AssemblyProductAttribute("SQLProvider")>]
77
[<assembly: AssemblyDescriptionAttribute("Type providers for Microsoft Access database access.")>]
8-
[<assembly: AssemblyVersionAttribute("1.5.25")>]
9-
[<assembly: AssemblyFileVersionAttribute("1.5.25")>]
8+
[<assembly: AssemblyVersionAttribute("1.5.26")>]
9+
[<assembly: AssemblyFileVersionAttribute("1.5.26")>]
1010
do ()
1111

1212
module internal AssemblyVersionInformation =
1313
let [<Literal>] AssemblyTitle = "SQLProvider.MsAccess.DesignTime"
1414
let [<Literal>] AssemblyProduct = "SQLProvider"
1515
let [<Literal>] AssemblyDescription = "Type providers for Microsoft Access database access."
16-
let [<Literal>] AssemblyVersion = "1.5.25"
17-
let [<Literal>] AssemblyFileVersion = "1.5.25"
16+
let [<Literal>] AssemblyVersion = "1.5.26"
17+
let [<Literal>] AssemblyFileVersion = "1.5.26"

‎src/SQLProvider.MsAccess.Runtime/AssemblyInfo.fs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ open System.Reflection
55
[<assembly: AssemblyTitleAttribute("SQLProvider.MsAccess.Runtime")>]
66
[<assembly: AssemblyProductAttribute("SQLProvider")>]
77
[<assembly: AssemblyDescriptionAttribute("Type providers for Microsoft Access database access.")>]
8-
[<assembly: AssemblyVersionAttribute("1.5.25")>]
9-
[<assembly: AssemblyFileVersionAttribute("1.5.25")>]
8+
[<assembly: AssemblyVersionAttribute("1.5.26")>]
9+
[<assembly: AssemblyFileVersionAttribute("1.5.26")>]
1010
do ()
1111

1212
module internal AssemblyVersionInformation =
1313
let [<Literal>] AssemblyTitle = "SQLProvider.MsAccess.Runtime"
1414
let [<Literal>] AssemblyProduct = "SQLProvider"
1515
let [<Literal>] AssemblyDescription = "Type providers for Microsoft Access database access."
16-
let [<Literal>] AssemblyVersion = "1.5.25"
17-
let [<Literal>] AssemblyFileVersion = "1.5.25"
16+
let [<Literal>] AssemblyVersion = "1.5.26"
17+
let [<Literal>] AssemblyFileVersion = "1.5.26"

0 commit comments

Comments
 (0)