Releases: redbase-app/redb
Release list
redb 3.7.2
redb 3.7.2
Ядро и провайдеры. Пакеты на nuget.org: redb.Core(.Pro), redb.Postgres(.Pro),
redb.MSSql(.Pro), redb.SQLite(.Pro), redb.Export, redb.CLI, redb.Templates, redb.Licensing.
Зачем этот выпуск. В 3.7.1 уехал регресс: array.Contains по nullable-массиву не
транслируется, а бросает исключение. Фильтр вида .Where(x => x.Tags.Contains(y))
перестаёт работать, как только Tags объявлен T[]? — а это то, что Nullable enable
даёт любому необязательному массиву. Виноват переход на .NET 10 в 3.7.1, а не
правка парсера: под net10 компилятор оборачивает коллекцию дважды.
3.7.1 остаётся в списке на nuget.org, образы остаются в реестре: небезопасного там
нет, версия вытеснена, а не отозвана.
Также в выпуске:
- PVT-префильтр перестал отказывать в трёх шаблонах запросов, где отказ был лишним:
вложенный OR под AND, несколько ветвей по одной структуре, ListItem.Id. - Найденный при этом дефект слияния ветвей: группировка шла по одной структуре, из-за
чего строковый шаблон мог склеиться с bigint-колонкой. - Планировщик префильтра объясняет себя в ToSqlStringAsync — девять кодов причин отказа.
Проверено на .NET 10.0.8, набор целится в net10.0: 1942 из 1944, два штатных Skip,
прогон дважды — с включённым и выключенным префильтром. Шесть провайдерских коллекций
плюс модульные: 1920 из 1920 в обоих режимах.
Установка:
dotnet add package redb.Core
dotnet add package redb.Postgres.Pro # Pro бесплатен на всей линии 3.x, ключ не нужен
redb 3.7.1
redb 3.7.1
Ядро и провайдеры. Пакеты на nuget.org: redb.Core(.Pro), redb.Postgres(.Pro),
redb.MSSql(.Pro), redb.SQLite(.Pro), redb.Export, redb.CLI, redb.Templates, redb.Licensing.
3.7.0 ОТОЗВАН. Он собран на .NET 9 и несёт известные уязвимости в зависимостях; все
пакеты 3.7.0 разлистованы на nuget.org. Разлистованная версия остаётся устанавливаемой
по точному номеру, но ставить её не нужно — 3.7.1 заменяет её полностью.
Безопасность:
- redb.Export тянул уязвимый SQLitePCLRaw.lib.e_sqlite3 2.1.10 транзитивно через
Microsoft.Data.Sqlite 9.0.3 (GHSA-2m69-gcr7-jv3q, высокий уровень). В redb.SQLite эта
дыра была закрыта пином давно, redb.Export прошёл мимо защиты. Пакет поднят до 10.0.0
плюс явный пин lib.e_sqlite3 3.50.3.
Сборка:
- Библиотеки по-прежнему мультитаргетятся net8.0;net9.0;net10.0 — ничего не сломано.
- redb.CLI переведён на net10.0 и ТЕПЕРЬ ТРЕБУЕТ .NET 10 на машине. Раньше он собирался
под net8.0 и вставал на любой рантайм .NET 8 и новее; роллфорвард работает только вверх,
поэтому на машине с одним лишь .NET 8 или .NET 9 тул больше не установится.
.NET 8 и .NET 9 уходят из поддержки Microsoft 10 ноября 2026, .NET 10 — до 14 ноября 2028.
Установка:
dotnet add package redb.Core
dotnet add package redb.Postgres.Pro # Pro бесплатен на всей линии 3.x, ключ не нужен
redb 3.6.0
redb 3.6.0
Ядро и провайдеры. Пакеты на nuget.org: redb.Core(.Pro), redb.Postgres(.Pro),
redb.MSSql(.Pro), redb.SQLite(.Pro), redb.Export, redb.CLI, redb.Templates, redb.Licensing.
Исправления этого выпуска:
- TreeQuery(root).WhereLeaves()/.WhereRoots() игнорировали корень и сканировали всю схему —
запрос молча возвращал узлы соседних деревьев. Починено на всех шести комбинациях
провайдер x Free/Pro, включая нативное расширение SQLite (redb_pvt.c). - SumRedbAsync/AverageRedbAsync бросали InvalidOperationException на пустой выборке.
- Хеширование падало на Blazor WebAssembly (в браузере нет MD5-провайдера) — добавлена
управляемая реализация RFC 1321, побитово совпадающая с System.Security.Cryptography.MD5. - Props-кэш мог отдать объект, изменённый на месте после кэширования.
- RedbHash зависел от порядка ключей в Dictionary.
- Android-приложения тащили ~360 КБ неработающих Linux-бинарей: нативное расширение Free-тира
переехало из runtimes//native/ в buildTransitive/native//. Раскладка в выходном
каталоге потребителя не изменилась.
Установка:
dotnet add package redb.Core
dotnet add package redb.Postgres.Pro # Pro бесплатен на всей линии 3.x, ключ не нужен
v3.4.0
Why 3.4.0 (a minor bump), not 3.3.4. This release adds features, not just fixes: explicit scheme
names ([RedbScheme(Name = "...")]), scheme-name validation triggers on MSSql/SQLite, and the new
ThrowOnSchemeMismatchload-time guard. Under SemVer that is a minor version. The core packages
(RedBase.Core, the three providers Free/Pro,RedBase.Export,RedBase.CLI) move together to
3.4.0;redb.Route,redb.Tsakandredb.Identitykeep their own version lines.
Added
-
Explicit scheme names —
[RedbScheme(Name = "...")](RedBase.Core+ all providers). Until now
a scheme was always named after the CLR type'sFullName, and the string in the attribute was only
a cosmetic_alias. A scheme name can now be pinned explicitly, which decouples the database
identity of a scheme from C# namespace/class refactoring.The positional argument is, and stays, the alias — an explicit name is only settable through the
namedNameparameter, so not one existing declaration changes meaning. Types that declare no
Namebehave exactly as before.On the first sync a type with an explicit name has its scheme renamed in the database. The
scheme is looked up along a three-step chain — explicit name,FullName, short type name — and the
first match is renamed in place. The rename is a single-rowUPDATEof_schemes._name: the id is
preserved, so objects, structures and values are untouched, and polymorphic loading (which resolves
throughscheme_id) is unaffected.Renaming requires every consumer of that database to be updated together. An application
version that predates the explicit name will not find the scheme under its new name and will
create a second one, splitting objects between them silently. If that has already happened, redb
now detects it and refuses to continue rather than picking one of the two.Explicit names must follow C# identifier rules (Latin letters, digits,
_,.,+; no reserved
words; 128 characters max) and are validated in C# before any SQL is issued, so the error names the
offending type. Human-readable titles belong inAlias, which is free-form. -
Scheme-name validation in MSSql and SQLite (
RedBase.MSSql,RedBase.SQLite). Both providers
now carry a_schemesname-validation trigger mirroring the PostgreSQLvalidate_scheme_name()
rule for rule, so a name accepted by one provider is accepted by all three. Applies to
newly created databases only —EnsureDatabaseAsyncskips initialisation when_schemes
already exists. The C#-level validation covers databases of any age. -
RedbServiceConfiguration.ThrowOnSchemeMismatch(RedBase.Core, defaultfalse). Chooses how
LoadAsync<TProps>reacts when the object's scheme does not matchTProps(see Fixed):false
returnsnull(so a soft-deleted object, scheme-10, reads asnull— what soft-delete callers
expect);truethrowsRedbSchemeMismatchExceptionto surface a genuine type mistake loudly.
Changed
- The SQLite native extension is renamed
redb→redbsqlite(RedBase.SQLite, Free tier).
The package now shipsruntimes/<rid>/native/redbsqlite.{dll,so}(win-x64, linux-x64, linux-arm64)
instead ofredb.{dll,so}. The generic name collided with the managedredb.*assemblies and with
theredb.*prune globs a host applies to its own bin directory — a native loadable module was
being swept up as if it were one of ours. The C init symbol is unchanged (sqlite3_redb_init)
and the binaries are byte-for-byte the ones shipped asredb.*in 3.3.3: this is a rename of the
file, not a rebuild, andLoadExtensionhas always been called with an explicit entry point.- Nothing to do if you let the package resolve the extension (
SqliteDataSource .LocatePackagedExtension(), the default for the Free DI registration) — it looks for the new name. - Action required if you pin the path yourself —
REDB_SQLITE_EXTENSION, an explicit
NativeExtensionPath, a DockerfileCOPY, or a deploy script that copiesredb.soby name:
point it atredbsqlite.{dll,so}. A stale path fails at connection open, not at build.
- Nothing to do if you let the package resolve the extension (
Fixed
-
Concurrent start-up of several nodes could fail to create a scheme (
RedBase.Core+ all
providers). Reproduced in production on a three-node cluster. When several instances started
against a database that did not yet have a given scheme, all of them missed the lookup and all
issuedINSERT INTO _schemes; every instance but one failed with an unhandledUNIQUE(_name)
violation during initialisation.Scheme creation now uses a conflict-free statement per dialect (
ON CONFLICT (_name) DO NOTHINGon
PostgreSQL and SQLite,INSERT ... WHERE NOT EXISTSwithUPDLOCK, HOLDLOCKon MSSql) and the
instance that loses the race reads back the winner's row. Catching the violation instead would not
have worked: on PostgreSQL a failed statement inside a transaction poisons it, so the follow-up
read would fail with25P02. Both creation paths are covered — typed
(EnsureSchemeFromTypeAsync<T>) and untyped (EnsureObjectSchemeAsync). -
Pro data migrations never ran — on any provider (
RedBase.Core.Pro,RedBase.SQLite,
RedBase.MSSql). Four separate defects stacked on top of each other, and the feature had no test
coverage at all, so none of them had ever surfaced:MigrationExtensions.CreateExecutorfetched the DB context by reflection asking for a
NonPublicContextproperty, butRedbServiceBase.Contextis public — the lookup never
matched and every migration died with "Cannot get IRedbContext from RedbService". It now uses
redb.Contextand(ISchemeSyncProvider)redbdirectly; both are part ofIRedbService.- The generated UPDATE was hardcoded to PostgreSQL syntax (
UPDATE _values target ...). SQLite
forbids aliasing an UPDATE target (near "target": syntax error) and T-SQL needs the alias
bound in a trailingFROM. AddedISqlDialectPro.Migration_UpdateTarget(table, alias)with
one implementation per provider. - SQLite had no
_migrationshistory table at all: PG/MSSql get it from the concatenated
redb_init.sql, and SQLite has no such concatenation step, so the sharedredb_migrations.sql
never reached it. A SQLite-native DDL (INTEGER PK, REAL Julian_applied_at, INTEGER
_dry_run) now ships inredbSqlite.sql. - MSSql declared
_migrations._idasIDENTITY(1,1)— the only IDENTITY in the whole MSSql
schema — while the executor supplies ids explicitly like every other redb table, so writing
history failed with "Cannot insert explicit value for identity column". IDENTITY removed.
Covered by a new
MigrationTestsBasesuite (apply / history row / idempotency / dry-run) running
against all three Pro fixtures. Note: existing databases do not receive the corrected_migrations
DDL, sinceEnsureDatabaseAsyncskips initialisation when_schemesalready exists — but no
database can hold real migration history, because the feature could not complete a single run. -
A scheme's
_aliaswas never updated after creation (RedBase.Core+ all providers). It was
written once onINSERTand then frozen: changing[RedbScheme("...")]on a class left the old
value in the database forever. Structure aliases have always synchronised (Structures_UpdateAlias);
schemes simply had no equivalent. They do now — the attribute is the source of truth, removing it
resets_aliastoNULL, and a value edited by hand in the database is overwritten on the next sync. -
ClrSchemeTypeIndexpinned hot-reloaded plugin modules in memory (RedBase.Core). The
process-globalschemeName → Typeindex held strongTypereferences, and aTypekeeps its
AssemblyLoadContextalive — so a collectible ALC (Tsak hot-swap) could never be collected, and after
a reload the stale instance produced a falseRedbSchemeNameConflictExceptionagainst the fresh one,
blocking the module from loading. Entries are nowWeakReference<Type>(dead ones pruned on lookup),
and two instances of the sameFullNamefrom different ALCs are recognised as a reload, not a name
clash. Distinct types sharing one explicitNamestill conflict, by design. -
LoadAsync<TProps>did not verify the loaded object's scheme (RedBase.Core+ all providers).
Loading an object of one scheme under an unrelatedTPropsdeserialised garbage into the Props and —
withEnablePropsCache— cached it underobjectId, so a laterGetWithoutHashValidationkept
returning the garbage.LoadAsync<TProps>now checks the object's_id_schemeagainst the scheme
TPropsmaps to before anything is cached. By default a mismatch returnsnull— so a soft-deleted
object (scheme-10, set bySoftDeleteAsync) reads asnull, which is what soft-delete callers
expect; setRedbServiceConfiguration.ThrowOnSchemeMismatch = trueto instead throw
RedbSchemeMismatchExceptionon a genuine type mistake. Either way garbage never reaches the cache.
The untypedLoadAsync(objectId)is never affected. -
Invalid explicit scheme names failed one at a time (
RedBase.Core). Auto-sync validates every
[RedbScheme(Name = "...")]and (by design) refuses to boot on an invalid name — but it stopped at
the first offender, so a codebase with several had to be fixed one rerun at a time. Names are now all
validated up front and reported together in a singleAggregateException.
Removed
- Dead metadata-cache interface layer (
RedBase.Core).ICompositeMetadataCache,
ISchemeMetadataCache,IStructureMetadataCache,ITypeMetadataCache,IStaticMetadataCacheand
StaticMetadataCache— 679 lines across five files that referenced only each other. None was ever
implemented, none was ever consumed; the live cache...
v3.3.3
Why 3.3.3 and not 3.3.1. The number jumps to stay in step with the rest of the ecosystem, which
had drifted ahead:redb.Routeandredb.Tsakwere at 3.3.1, andredb.Route.Sql/redb.Route.Sqs
at 3.3.2 (a partial connector release). From 3.3.3 every package ships one number — redb core,
redb.Route and redb.Tsak — so "which versions go together" stops being a question. There are no core
releases numbered 3.3.1 or 3.3.2; the fix below is the only functional change here.
redb.Identitykeeps its own line (1.2.2) but is released together with this — it depends on redb
storage, and without the rebuild its users would stay on the broken init below.
Fixed
- Schema init failed under a non-superuser database owner (
RedBase.Postgres). The embedded
redb_init.sqlcarried a singleALTER FUNCTION migrate_structure_type(...) OWNER TO postgres;
(a leftover from a debugging session — the onlyOWNER TOin the whole script).EnsureCreated=trueruns
the script as one batch, so on a least-privilege setup (app user owns the database but is not a
member of thepostgresrole) the statement failed with "must be able to SET ROLE postgres"
and rolled back the entire first-start initialization. The statement is removed: no function in
the script isSECURITY DEFINER, so ownership never affected execution, and the function now
belongs to the connecting role like every other object — which also keeps future
CREATE OR REPLACEmigrations working. Required app privileges are now just
CONNECT+CREATEon the schema + DML. Note:CREATE EXTENSION IF NOT EXISTS pg_trgmstill
requires the extension to be preinstalled on PostgreSQL ≤ 12 (on PG 13+pg_trgmis a trusted
extension, installable by the database owner).
v3.3.0
Added
- Fail-fast concurrency guard on the provider connection (
RedBase.Postgres,RedBase.MSSql,
RedBase.SQLite+.Pro). AnIRedbServicewraps a single, non-thread-safe DB connection
(EF-DbContext model). If the same instance is entered from two threads at once, each provider now
throws a clearInvalidOperationExceptionnaming the cause — instead of an opaque driver error
("A command is already in progress", "connection is busy", "another read operation is already
in progress"). LightweightInterlockedcheck with zero cost on the normal single-threaded path;
correct scoped usage is never affected.
Fixed
- Query parser:
array.Contains(x)inWhereRedbthrew on .NET 9 / C# 13 (RedBase.Core).
Astring[](or any array).Contains(x)inside aWhereRedb(...)predicate now binds to the
ReadOnlySpanoverload (System.MemoryExtensions.Contains) rather thanEnumerable.Contains,
which the filter parser rejected withNotSupportedException. The parser now recognises
MemoryExtensions.Contains, unwraps the array→span conversion, and translates it to the same
INclause asEnumerable.Contains/List.Contains. (Refactored the two-argContains
translation into a sharedVisitContainsCore.) ComputeHash()NRE on an object withProps == null(RedBase.Core).RedbHash.ComputeForObject
dereferenced the object before a null check, so the genericComputeFor<TProps>path (used by
RedbObject<TProps>.ComputeHash()) threwNullReferenceExceptionwhenPropswas null — even
though null Props is a supported case (the reflection-basedComputeFor(IRedbObject)already
returned null, andComputeForBaseFieldsexists for exactly this). Added the missing guard so the
generic path returnsnull(→Guid.Empty) consistently, instead of throwing.- Connection-pool leak on transaction/connection dispose (
RedBase.Postgres,RedBase.MSSql,
RedBase.SQLite+.Pro). Disposing the provider connection could skip returning the physical
connection to the pool: a throw from the driver's transactionDisposeAsync()(possible mid
error-storm on an already-broken connection) bypassed_connectiondisposal. BecauseSaveAsync
runs inside an explicit transaction, every write armed this path, so under a burst of failures the
leak was self-amplifying and eventually exhausted the pool (symptom: a healthy pool suddenly climbs
pastMaxPoolSizewith connection-timeout errors, cleared only by a restart). The connection's
DisposeAsync/Disposeand the transaction wrapper'sDisposeAsyncnow usetry/finally, so the
connection is always returned and the transaction-cleanup callback always runs; the dispose fault is
no longer swallowed — it propagates so it stays observable.
v3.2.0
RedBase 3.2.0 - see CHANGELOG.md. NuGet: https://www.nuget.org/profiles/relikt
v3.0.0
Added
-
PG Free: full v2-pvt query engine reaches Pro-parity (0.5.x → 0.6.1).
The PostgreSQL Free path got the feature-complete v2-pvt module ahead of
MSSql Free (commits 2026-05-21 … 2026-05-28). Before this series the Free
path was emitting-- not available in Open Sourcestubs for several
preview surfaces and was missing several Pro-only operators. Now in Free
on PG:- Universal "no black box" SQL preview for
GroupBy/Window/
GroupedWindow/Tree-*via two-pass compile (pvt_build_*_sql);
tree previews resolve the subtree and delegate to the matching non-tree
preview with a-- Tree …: subtree resolved to N object(s)header. Sql.Function<T>whitelist at the SQL boundary
(17_pvt_expr.sql) with a
hardcoded ELSIF chain andRAISE EXCEPTIONfor non-whitelisted names;
parser routesSql.Function<T>(name, args)to
CustomFunctionExpression(FREE-OVER-PRO §2.4).ValueTuplecomposite dict keys (Dictionary<(int,int), V>)
consistently encoded as Base64-JSON on both write and read sides
(FREE-OVER-PRO §2.2).arr.Length/coll.Countin filters via the array-aware
FacetFilterBuilder(.$countmodifier in Free);e.Tags.Any()
1-arg form mapped to<field>.$length > 0.Take(0)returns empty instead ofArgumentException.HAVINGparser +ArrayGroupBywith PVT agg arrayunnest
(19_pvt_agg_expr.sql) —
fixes42883 function sum(bigint[]) does not exist;
26_pvt_array_groupby.sql
added.ListItem.Value/.Aliasvia a singleLEFT JOIN _list_items
(v2-pvt 0.6.1) — plan-shape parity with Pro; replaces correlated
subquery per field.- Nested-dict CTE pushdown for
Field[key].Child(FREE-OVER-PRO §2.x):
outerWHEREreferences the already-built pivot column instead of a
redundantEXISTSover_values. - Auto-deploy of the v2-pvt bundle on version mismatch (see the
matching item below — same infrastructure serves both PG and MSSql).
The MSSql Free engine described next ports this PG Free baseline; the
parity line in the next item ("145/145 parity with PG Free") refers to
this newly-completed PG Free feature set, not a pre-existing one. - Universal "no black box" SQL preview for
-
MSSql Free: full v2-pvt query engine (0.1.0 → 0.1.3) — 145/145 parity
with PG Free. The old MSSql Free path generated a wide inline CASE WHEN
aggregate; it is now replaced with the Pro-shape CTE: a single pass over
_valuesusingMAX(CASE WHEN _id_structure = X AND _array_index IS NULL THEN ...)and a singleLEFT JOIN _list_items. All modes present in PG
Free are implemented: flat/tree, scalar/array/dict fields, ListItem
(.Id/.Value/.Alias), same-scheme nested POCO (compound path),
OrderBy/DistinctBy/Take/Skip,GroupBy/HAVING,ArrayGroupBy
(viaOUTER APPLY), array aggregates ($count,$sum/$avg/$min/$max
over_Long/_Double/_Numeric/_DateTimeOffset), array operators
($arrayContains,$arrayAny,$arrayCount*,$arrayAt,
$arrayStartsWith, etc.),Sql.Function(whitelist),$expr, null
semantics ($exists/$notNull). The SQL module is split into 27 source
files under redb.MSSql/sql/v2-pvt/ assembled
into a singlepvt_bundle.sqlby MSBuild. Delivery stages: Stage 1 (pivot
CTE) → 2a (tree TVFs) → 2b (tree provider) → 2c.E (nested-dict accessor
Field[key].Child) → 0.1.1 LIKE-pattern fix → 0.1.2 string$const
unwrap + ListItem$arrayContains→ 0.1.3 nested-dict CTE pushdown +
outerWHEREreferences pivot column instead of a redundantEXISTS.
Shape parity with Pro throughout:_id_scheme+extra_where+
tree-filter pushed into inner_objectssubquery, narrow-with-nested CTE
(skips_valuesJOIN when no scalar sids), stable defaultORDER BYwhen
paging without an explicit order. -
Auto-deploy v2-pvt bundle on version mismatch (both databases).
ISqlDialectgainedQuery_PvtRequiredVersion()— the semver the embedded
bundle ships.RedbServiceBase.EnsurePvtModuleDeployedAsyncreads
pvt_module_version()onInitializeAsync(), compares with an exact-match,
and automatically applies the embeddedpvt_bundle.sqlresource when the
deployed version differs. No more manualDROP FUNCTION … CREATE FUNCTION …
after a SQL change. The MSBuild targetConcatenateSqlFilesregenerates the
bundle whenever any.sqlsource changes (hooked toDispatchToInnerBuilds
for multi-TFM builds;EmbeddedResourceuses an explicitLogicalName—
without it MSBuild silently replaces-with_in resource paths, causing
GetManifestResourceStreamto returnnull). -
Pro:
GroupBy+HAVINGvia PVT pipeline on both providers
(Postgres.Pro + MSSql.Pro).HavingAsyncexisted in Free but had no Pro
counterpart. Added full HAVING parser in the shared facet layer
(FacetFilterBuilder), SQL generation in both Pro providers, and a base
test suite in
GroupByHavingTestsBase
with per-dialect wrappers (PG, PG.Pro, MSSql.Pro). 33/33 HAVING + 6/6
no-HAVING — all green. -
Pro:
GroupByover array fields (ArrayGroupBy) — unified implementation
for Postgres.Pro + MSSql.Pro. PG.Pro uses an inlineGroupByArrayoverride
with PVT agg arrayunnest; MSSql.Pro has its own override.
GroupBy(items => items.SelectMany(o => o.Skills))with aggregates works
on all four tiers (PG Free, PG.Pro, MSSql Free, MSSql.Pro). -
MSSql Pro:
AggregateBatchparity with PG.Pro — non-numeric MIN/MAX and
inline filter subquery.MinAsync/MaxAsyncoverstring/DateTime/Guid
fields and aWherefilter inside a batch aggregation now produce the same
query shape as PG.Pro (PVT CTE + outer aggregate). -
MSSql Free: pushdown parity with Pro/PG for expression-form predicates
and$expr— the filter-splitting optimizer
pvt_split_filternow pushes
top-level$eq/$ne/$lt/$lte/$gt/$gte/$like/$ilike/$in/$nin/$between/$null/ $notnull/$contains/$startsWith/$endsWithexpressions and arbitrary boolean
$exprtrees into the inner_objects osubquery (Shape A) when all
$fieldreferences resolve tokind='base'. If any props field is present
the node stays in the residual (Shape C). The new classifier
pvt_expr_is_base_onlymakes
this decision; the pushdown SQL itself is generated by the existing
pvt_build_where_from_json
walker (extended with a$exprbranch). Covered by 4 functional and 3
shape-inspect tests in
99_smoke_auto.sql
(195 PASS / 0 FAIL / 1 SKIP).
Fixed
- Schema sync now honors
Configuration.DefaultStrictDeleteExtra
(FREE-OVER-PRO §4 #1). Prior to this fixRedbServiceConfiguration.DefaultStrictDeleteExtra
was set by builders, copied across configuration clones and read from
appsettings, but no execution-path code consumed it —
SchemeSyncProviderBase.SyncSchemeAsync<T>
hardcodedstrictDeleteExtra: true, so old binaries restarting in a
multi-version rolling deploy would unconditionally remove_structures
rows added by the new binary, and every_valuesrow referencing those
structures along with them. On PostgreSQL this is done via the FK
_values._id_structure -> _structures._id ON DELETE CASCADE
(redbPostgre.sql:215). On MSSQL
the same effect is produced by theINSTEAD OF DELETEtrigger
TR__structures__cascade_values
(redbMSSQL.sql:717) — the FK
NO ACTIONat redbMSSQL.sql:270
is a workaround for the MSSQL multiple-cascade-paths restriction, not a
behavioral difference.SyncSchemeAsync<T>now reads
now readsConfiguration.DefaultStrictDeleteExtrainstead. The default
value is preserved (true) so users on the default config see no
behavioral change. Behavioral change: the built-in presets
Development,HighPerformance, andMigration(in
PredefinedConfigurations.cs)
already declaredDefaultStrictDeleteExtra = false; that setting was
silently ignored before and now actually takes effect — apps on those
presets will no longer auto-delete_structuresrows missing from the
Propsclass on startup.
Added
a fallback to ROW_NUMBER() OVER (PARTITION BY <key> ORDER BY (SELECT 1))
WHERE _rn = 1(symmetric with the Free path), plus support for
CoalesceExpressionin theDistinctBykey.
-
PG v2-pvt 0.6.1: ListItem
.Value/.Aliasnow uses a single
LEFT JOIN _list_itemsinstead of a correlated subquery per field —
plan-shape parity with Pro. Additionally: nested-dict predicates in the
outerWHEREnow reference_pvt_cte.[<field>](the already-built pivot
column) instead of re-running a separateEXISTSover_values. -
MSSql Free:
ORDER BY $expron base fields no longer produces "constant
in ORDER BY" — two regressions fixed: (1)
pvt_collect_fields
did not walk$exprnodes in order entries, so a field likeAgewas not
collected, the shape was classified as A, andpvt_b2_expr_sqlemitted
/*unknown-b2-field:Age*/NULLturningAge*2into a constant; (2)
[pvt_build_order_conditions](redb.MSSql/sql/v2-pvt...
v2.0.2
RedBase 2.0.2. See CHANGELOG.md for details. NuGet: https://www.nuget.org/profiles/relikt
v2.0.1
RedBase 2.0.1 — Pro EAV LINQ→SQL fix. License migrated MIT → Apache-2.0 for all OSS packages. Strong-name signing active for Pro assemblies. See CHANGELOG.md for details. NuGet: https://www.nuget.org/profiles/relikt