@minnowdb/core 0.7.1 → 0.7.2
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.
package/dist/engine/database.js
CHANGED
|
@@ -5373,13 +5373,14 @@ ${notes.map((note) => `-- ${note}`).join("\n")}`;
|
|
|
5373
5373
|
}
|
|
5374
5374
|
const open = this.#openTransaction;
|
|
5375
5375
|
if (open !== void 0) {
|
|
5376
|
-
const
|
|
5377
|
-
if (!isTransactionalStatement(
|
|
5378
|
-
throw new TypeError(`${
|
|
5376
|
+
const boundStatement2 = bindStatementParameters(statement, params);
|
|
5377
|
+
if (!isTransactionalStatement(boundStatement2)) {
|
|
5378
|
+
throw new TypeError(`${boundStatement2.kind.toUpperCase().replace("-", " ")} is not allowed inside a transaction`);
|
|
5379
5379
|
}
|
|
5380
|
-
return externalizeExecuteResult(await this.#projectReturningItems(
|
|
5380
|
+
return externalizeExecuteResult(await this.#projectReturningItems(boundStatement2, await this.#duringTransaction(open, () => open.session.executeStatement(boundStatement2))));
|
|
5381
5381
|
}
|
|
5382
|
-
|
|
5382
|
+
const boundStatement = bindStatementParameters(statement, params);
|
|
5383
|
+
return externalizeExecuteResult(await this.#projectReturningItems(boundStatement, await this.runStatement(boundStatement)));
|
|
5383
5384
|
}
|
|
5384
5385
|
async #assertForeignKeysPresent(table, rowsByColumn, read, transaction) {
|
|
5385
5386
|
for (const key of table.foreignKeys ?? []) {
|
package/dist/engine/optimizer.js
CHANGED
|
@@ -1494,14 +1494,17 @@ function scalarOrderExpression(expression, rows) {
|
|
|
1494
1494
|
const matches = rows.select.filter((item) => item.alias === expression.reference);
|
|
1495
1495
|
return matches.length === 1 ? structuredClone(matches[0]?.expression ?? expression) : structuredClone(expression);
|
|
1496
1496
|
}
|
|
1497
|
-
function emptyScalarExpression(expression) {
|
|
1497
|
+
function emptyScalarExpression(expression, preservedColumns = /* @__PURE__ */ new Set()) {
|
|
1498
1498
|
if (isAggregateCall(expression)) {
|
|
1499
1499
|
return { kind: "literal", value: expression.name === "COUNT" ? 0 : null };
|
|
1500
1500
|
}
|
|
1501
|
-
if (expression.kind === "column"
|
|
1501
|
+
if (expression.kind === "column") {
|
|
1502
|
+
return preservedColumns.has(expression.reference) ? structuredClone(expression) : { kind: "literal", value: null };
|
|
1503
|
+
}
|
|
1504
|
+
if (expression.kind === "wildcard") {
|
|
1502
1505
|
return { kind: "literal", value: null };
|
|
1503
1506
|
}
|
|
1504
|
-
return mapChildExpressions(expression, emptyScalarExpression);
|
|
1507
|
+
return mapChildExpressions(expression, (child) => emptyScalarExpression(child, preservedColumns));
|
|
1505
1508
|
}
|
|
1506
1509
|
function decorrelateGeneralScalar(block, inner, scope, nextAlias) {
|
|
1507
1510
|
const shape = scalarShape(inner);
|
|
@@ -1512,14 +1515,44 @@ function decorrelateGeneralScalar(block, inner, scope, nextAlias) {
|
|
|
1512
1515
|
if (rows.limitWithTies === true && rows.orderBy.length === 0) {
|
|
1513
1516
|
throw new TypeError("A correlated scalar WITH TIES query requires ORDER BY");
|
|
1514
1517
|
}
|
|
1515
|
-
const
|
|
1516
|
-
|
|
1518
|
+
const expressionOutside = [];
|
|
1519
|
+
collectExpressionOutsideReferences(shape.expression, /* @__PURE__ */ new Set([rows.base.alias, ...rows.joins.map((join) => join.alias)]), expressionOutside);
|
|
1520
|
+
const probeLifted = expressionOutside.length > 0 || !canExtractCorrelation(rows, scope, "scalar", true);
|
|
1521
|
+
const references = probeLifted ? probeOuterReferences(rows, expressionOutside, scope, "scalar") : [];
|
|
1522
|
+
const keys = probeLifted ? takeCorrelationPredicates(rows, scope, true) : extractCorrelation(rows, scope, "scalar", true);
|
|
1523
|
+
const outerExpressions = probeLifted ? references.map((reference) => ({ kind: "column", reference })) : keys.map((key) => structuredClone(key.outer));
|
|
1524
|
+
const originalExpression = structuredClone(shape.expression);
|
|
1517
1525
|
const probes = outerProbeBlockForExpressions(block, outerExpressions, nextAlias.resolvedNames);
|
|
1518
1526
|
const probesAlias = nextAlias();
|
|
1519
1527
|
const probeReferences = outerExpressions.map((_, index) => ({
|
|
1520
1528
|
kind: "column",
|
|
1521
1529
|
reference: `${probesAlias}.${correlationProbeAlias(index)}`
|
|
1522
1530
|
}));
|
|
1531
|
+
if (probeLifted) {
|
|
1532
|
+
const replacements = new Map(references.map((reference, index) => [reference, probeReferences[index] ?? null]));
|
|
1533
|
+
replacePlanReferences(rows, replacements);
|
|
1534
|
+
shape.expression = replaceExpressionReferences(shape.expression, replacements);
|
|
1535
|
+
const source = { table: probesAlias, alias: probesAlias, derived: probes };
|
|
1536
|
+
const missingProbe = { kind: "literal", value: null };
|
|
1537
|
+
const keyProbes = keys.map((key) => {
|
|
1538
|
+
const reference = key.outer.kind === "column" ? key.outer.reference : "";
|
|
1539
|
+
return probeReferences[references.indexOf(reference)] ?? missingProbe;
|
|
1540
|
+
});
|
|
1541
|
+
const keysReadBase = keys.every((key) => {
|
|
1542
|
+
const parts = key.inner.kind === "column" ? key.inner.reference.split(".") : [];
|
|
1543
|
+
return parts.length === 1 || parts[0] === rows.base.alias;
|
|
1544
|
+
});
|
|
1545
|
+
if (keys.length > 0 && keysReadBase) {
|
|
1546
|
+
rows.joins.unshift(generalCorrelationJoin(probesAlias, probes, keys.map((key) => key.inner), keyProbes, keys.map((key) => key.operator)));
|
|
1547
|
+
} else {
|
|
1548
|
+
rows.joins.unshift(crossJoinPlan(source));
|
|
1549
|
+
rows.predicates.push(...keys.map((key, index) => ({
|
|
1550
|
+
left: key.inner,
|
|
1551
|
+
operator: key.operator,
|
|
1552
|
+
right: keyProbes[index] ?? missingProbe
|
|
1553
|
+
})));
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1523
1556
|
const finalRowsAlias = nextAlias();
|
|
1524
1557
|
const projected = [];
|
|
1525
1558
|
const project = (expression, alias) => {
|
|
@@ -1556,6 +1589,15 @@ function decorrelateGeneralScalar(block, inner, scope, nextAlias) {
|
|
|
1556
1589
|
return rewritten;
|
|
1557
1590
|
}
|
|
1558
1591
|
if (expression.kind === "column" || expression.kind === "wildcard") {
|
|
1592
|
+
if (probeLifted && expression.kind === "column") {
|
|
1593
|
+
const index = probeReferences.findIndex((reference) => reference.kind === "column" && reference.reference === expression.reference);
|
|
1594
|
+
if (index >= 0) {
|
|
1595
|
+
return {
|
|
1596
|
+
kind: "column",
|
|
1597
|
+
reference: `${finalRowsAlias}.${correlationKeyAlias(index)}`
|
|
1598
|
+
};
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1559
1601
|
throw new TypeError("A correlated scalar aggregate cannot select an ungrouped inner column");
|
|
1560
1602
|
}
|
|
1561
1603
|
if (expression.kind === "subquery" || expression.kind === "exists") {
|
|
@@ -1575,18 +1617,21 @@ function decorrelateGeneralScalar(block, inner, scope, nextAlias) {
|
|
|
1575
1617
|
base: rows.base,
|
|
1576
1618
|
joins: rows.joins,
|
|
1577
1619
|
select: [
|
|
1578
|
-
...keys.map((key, index) => ({
|
|
1579
|
-
expression
|
|
1620
|
+
...(probeLifted ? probeReferences : keys.map((key) => key.inner)).map((expression, index) => ({
|
|
1621
|
+
expression,
|
|
1580
1622
|
alias: correlationKeyAlias(index)
|
|
1581
1623
|
})),
|
|
1582
1624
|
...projected
|
|
1583
1625
|
],
|
|
1584
|
-
predicates: [
|
|
1626
|
+
predicates: [
|
|
1627
|
+
...rows.predicates,
|
|
1628
|
+
...probeLifted ? [] : mirrorPredicatesThroughKeys(probes.predicates, keys)
|
|
1629
|
+
],
|
|
1585
1630
|
groupBy: [],
|
|
1586
1631
|
having: [],
|
|
1587
1632
|
orderBy: []
|
|
1588
1633
|
};
|
|
1589
|
-
const matched = {
|
|
1634
|
+
const matched = probeLifted ? rawRows : {
|
|
1590
1635
|
sql: "(correlated scalar matched probes)",
|
|
1591
1636
|
base: { table: probesAlias, alias: probesAlias, derived: probes },
|
|
1592
1637
|
joins: [
|
|
@@ -1623,7 +1668,7 @@ function decorrelateGeneralScalar(block, inner, scope, nextAlias) {
|
|
|
1623
1668
|
{
|
|
1624
1669
|
alias: correlationRowNumberAlias,
|
|
1625
1670
|
name: rows.limitWithTies === true ? "RANK" : "ROW_NUMBER",
|
|
1626
|
-
partitionAliases:
|
|
1671
|
+
partitionAliases: outerExpressions.map((_, index) => correlationKeyAlias(index)),
|
|
1627
1672
|
orderAliases: rows.orderBy.map((order, index) => ({
|
|
1628
1673
|
alias: correlationOrderAlias(index),
|
|
1629
1674
|
direction: order.direction,
|
|
@@ -1659,7 +1704,7 @@ function decorrelateGeneralScalar(block, inner, scope, nextAlias) {
|
|
|
1659
1704
|
base: ranked,
|
|
1660
1705
|
joins: [],
|
|
1661
1706
|
select: [
|
|
1662
|
-
...
|
|
1707
|
+
...outerExpressions.map((_, index) => ({
|
|
1663
1708
|
expression: {
|
|
1664
1709
|
kind: "column",
|
|
1665
1710
|
reference: `${rankedAlias}.${correlationKeyAlias(index)}`
|
|
@@ -1679,7 +1724,7 @@ function decorrelateGeneralScalar(block, inner, scope, nextAlias) {
|
|
|
1679
1724
|
...rows.offsetParameter === void 0 ? {} : { offsetValidationParameters: [rows.offsetParameter] }
|
|
1680
1725
|
};
|
|
1681
1726
|
}
|
|
1682
|
-
const finalProbeReferences =
|
|
1727
|
+
const finalProbeReferences = outerExpressions.map((_, index) => ({
|
|
1683
1728
|
kind: "column",
|
|
1684
1729
|
reference: `${finalRowsAlias}.${correlationKeyAlias(index)}`
|
|
1685
1730
|
}));
|
|
@@ -1716,7 +1761,7 @@ function decorrelateGeneralScalar(block, inner, scope, nextAlias) {
|
|
|
1716
1761
|
left: marker,
|
|
1717
1762
|
right: { kind: "literal", value: null }
|
|
1718
1763
|
},
|
|
1719
|
-
then: grouped ? emptyScalarExpression(
|
|
1764
|
+
then: grouped ? emptyScalarExpression(originalExpression, new Set(references)) : { kind: "literal", value: null }
|
|
1720
1765
|
}
|
|
1721
1766
|
],
|
|
1722
1767
|
otherwise: {
|
|
@@ -1880,19 +1925,7 @@ function decorrelateExistsExpression(block, exists, scope, nextAlias) {
|
|
|
1880
1925
|
}
|
|
1881
1926
|
function decorrelateExistsWithProbes(block, exists, scope, nextAlias) {
|
|
1882
1927
|
const inner = exists.block;
|
|
1883
|
-
const
|
|
1884
|
-
collectOutsideReferences(inner, /* @__PURE__ */ new Set(), outside);
|
|
1885
|
-
const references = [...new Set(outside)];
|
|
1886
|
-
if (references.length === 0) {
|
|
1887
|
-
throw new TypeError("Correlated EXISTS subquery has no usable outer reference");
|
|
1888
|
-
}
|
|
1889
|
-
for (const reference of references) {
|
|
1890
|
-
const parts = reference.split(".");
|
|
1891
|
-
const alias = parts.length === 2 ? parts[0] : void 0;
|
|
1892
|
-
if (alias === void 0 || !scope.has(alias)) {
|
|
1893
|
-
throw new TypeError(`Correlated EXISTS references an unavailable outer source: ${reference}`);
|
|
1894
|
-
}
|
|
1895
|
-
}
|
|
1928
|
+
const references = probeOuterReferences(inner, [], scope, "EXISTS");
|
|
1896
1929
|
const outerExpressions = references.map((reference) => ({
|
|
1897
1930
|
kind: "column",
|
|
1898
1931
|
reference
|
|
@@ -1959,27 +1992,30 @@ function decorrelateExistsWithProbes(block, exists, scope, nextAlias) {
|
|
|
1959
1992
|
right: { kind: "literal", value: null }
|
|
1960
1993
|
};
|
|
1961
1994
|
}
|
|
1962
|
-
function
|
|
1963
|
-
const rewrite = (
|
|
1964
|
-
if (
|
|
1965
|
-
const replacement = replacements.get(
|
|
1966
|
-
return replacement == null ?
|
|
1995
|
+
function replaceExpressionReferences(expression, replacements) {
|
|
1996
|
+
const rewrite = (expression2) => {
|
|
1997
|
+
if (expression2.kind === "column") {
|
|
1998
|
+
const replacement = replacements.get(expression2.reference);
|
|
1999
|
+
return replacement == null ? expression2 : structuredClone(replacement);
|
|
1967
2000
|
}
|
|
1968
|
-
if (
|
|
1969
|
-
replacePlanReferences(
|
|
1970
|
-
return
|
|
2001
|
+
if (expression2.kind === "subquery" || expression2.kind === "exists") {
|
|
2002
|
+
replacePlanReferences(expression2.block, replacements);
|
|
2003
|
+
return expression2;
|
|
1971
2004
|
}
|
|
1972
|
-
if (
|
|
1973
|
-
|
|
1974
|
-
for (const order of
|
|
2005
|
+
if (expression2.kind === "window") {
|
|
2006
|
+
expression2.partitionBy = expression2.partitionBy.map(rewrite);
|
|
2007
|
+
for (const order of expression2.orderBy)
|
|
1975
2008
|
order.expression = rewrite(order.expression);
|
|
1976
|
-
if (
|
|
1977
|
-
|
|
1978
|
-
return
|
|
2009
|
+
if (expression2.argument !== void 0)
|
|
2010
|
+
expression2.argument = rewrite(expression2.argument);
|
|
2011
|
+
return expression2;
|
|
1979
2012
|
}
|
|
1980
|
-
return mapChildExpressions(
|
|
2013
|
+
return mapChildExpressions(expression2, rewrite);
|
|
1981
2014
|
};
|
|
1982
|
-
|
|
2015
|
+
return rewrite(expression);
|
|
2016
|
+
}
|
|
2017
|
+
function replacePlanReferences(block, replacements) {
|
|
2018
|
+
mapBlockExpressions(block, (expression) => replaceExpressionReferences(expression, replacements));
|
|
1983
2019
|
forEachNestedBlock(block, (nested) => replacePlanReferences(nested, replacements));
|
|
1984
2020
|
}
|
|
1985
2021
|
function outerProbeBlock(block, keys, resolvedNames) {
|
|
@@ -2166,30 +2202,62 @@ function blockReferencesOutside(block) {
|
|
|
2166
2202
|
collectOutsideReferences(block, /* @__PURE__ */ new Set(), refs);
|
|
2167
2203
|
return refs.length > 0;
|
|
2168
2204
|
}
|
|
2169
|
-
function
|
|
2170
|
-
const
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
const parts = expression.reference.split(".");
|
|
2205
|
+
function collectExpressionOutsideReferences(expression, scope, refs) {
|
|
2206
|
+
const visit = (expression2) => {
|
|
2207
|
+
if (expression2.kind === "column") {
|
|
2208
|
+
const parts = expression2.reference.split(".");
|
|
2174
2209
|
const alias = parts[0];
|
|
2175
2210
|
if (parts.length === 2 && alias !== void 0 && !scope.has(alias)) {
|
|
2176
|
-
refs.push(
|
|
2211
|
+
refs.push(expression2.reference);
|
|
2177
2212
|
}
|
|
2178
2213
|
return;
|
|
2179
2214
|
}
|
|
2180
|
-
if (
|
|
2181
|
-
collectOutsideReferences(
|
|
2215
|
+
if (expression2.kind === "subquery" || expression2.kind === "exists") {
|
|
2216
|
+
collectOutsideReferences(expression2.block, scope, refs);
|
|
2182
2217
|
return;
|
|
2183
2218
|
}
|
|
2184
|
-
for (const child of childExpressions(
|
|
2219
|
+
for (const child of childExpressions(expression2))
|
|
2185
2220
|
visit(child);
|
|
2186
2221
|
};
|
|
2187
|
-
|
|
2222
|
+
visit(expression);
|
|
2223
|
+
}
|
|
2224
|
+
function collectOutsideReferences(block, outer, refs) {
|
|
2225
|
+
const scope = /* @__PURE__ */ new Set([...outer, block.base.alias, ...block.joins.map((join) => join.alias)]);
|
|
2226
|
+
forEachBlockExpression(block, (expression) => collectExpressionOutsideReferences(expression, scope, refs));
|
|
2188
2227
|
forEachNestedBlock(block, (nested) => {
|
|
2189
2228
|
collectOutsideReferences(nested, scope, refs);
|
|
2190
2229
|
});
|
|
2191
2230
|
}
|
|
2231
|
+
function probeOuterReferences(block, additional, scope, label) {
|
|
2232
|
+
const outside = [];
|
|
2233
|
+
collectOutsideReferences(block, /* @__PURE__ */ new Set(), outside);
|
|
2234
|
+
const references = [.../* @__PURE__ */ new Set([...outside, ...additional])];
|
|
2235
|
+
if (references.length === 0) {
|
|
2236
|
+
throw new TypeError(`Correlated ${label} subquery has no usable outer reference`);
|
|
2237
|
+
}
|
|
2238
|
+
for (const reference of references) {
|
|
2239
|
+
const parts = reference.split(".");
|
|
2240
|
+
const alias = parts.length === 2 ? parts[0] : void 0;
|
|
2241
|
+
if (alias === void 0 || !scope.has(alias)) {
|
|
2242
|
+
throw new TypeError(`Correlated ${label} references an unavailable outer source: ${reference}`);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
return references;
|
|
2246
|
+
}
|
|
2192
2247
|
function extractCorrelation(inner, outerScope, label, comparisons = false) {
|
|
2248
|
+
const keys = takeCorrelationPredicates(inner, outerScope, comparisons);
|
|
2249
|
+
const leftover = [];
|
|
2250
|
+
collectOutsideReferences(inner, /* @__PURE__ */ new Set(), leftover);
|
|
2251
|
+
if (leftover.length > 0) {
|
|
2252
|
+
const supported = comparisons ? "comparison" : "equality";
|
|
2253
|
+
throw new TypeError(`Correlated ${label} subqueries support only ${supported} conditions between one inner and one outer qualified column (unsupported reference: ${leftover[0] ?? ""})`);
|
|
2254
|
+
}
|
|
2255
|
+
if (keys.length === 0) {
|
|
2256
|
+
throw new TypeError(`Correlated ${label} subquery has no usable correlation condition`);
|
|
2257
|
+
}
|
|
2258
|
+
return keys;
|
|
2259
|
+
}
|
|
2260
|
+
function takeCorrelationPredicates(inner, outerScope, comparisons) {
|
|
2193
2261
|
const innerScope = /* @__PURE__ */ new Set([inner.base.alias, ...inner.joins.map((join) => join.alias)]);
|
|
2194
2262
|
const keys = [];
|
|
2195
2263
|
const kept = [];
|
|
@@ -2201,15 +2269,6 @@ function extractCorrelation(inner, outerScope, label, comparisons = false) {
|
|
|
2201
2269
|
keys.push(key);
|
|
2202
2270
|
}
|
|
2203
2271
|
inner.predicates = kept;
|
|
2204
|
-
const leftover = [];
|
|
2205
|
-
collectOutsideReferences(inner, /* @__PURE__ */ new Set(), leftover);
|
|
2206
|
-
if (leftover.length > 0) {
|
|
2207
|
-
const supported = comparisons ? "comparison" : "equality";
|
|
2208
|
-
throw new TypeError(`Correlated ${label} subqueries support only ${supported} conditions between one inner and one outer qualified column (unsupported reference: ${leftover[0] ?? ""})`);
|
|
2209
|
-
}
|
|
2210
|
-
if (keys.length === 0) {
|
|
2211
|
-
throw new TypeError(`Correlated ${label} subquery has no usable correlation condition`);
|
|
2212
|
-
}
|
|
2213
2272
|
return keys;
|
|
2214
2273
|
}
|
|
2215
2274
|
function canExtractCorrelation(inner, outerScope, label, comparisons) {
|
package/dist/engine/query.js
CHANGED
|
@@ -1608,6 +1608,7 @@ function bindStatementParameters(statement, params) {
|
|
|
1608
1608
|
if (clone.onConflict?.where !== void 0) {
|
|
1609
1609
|
clone.onConflict.where = bindExpression(clone.onConflict.where, values);
|
|
1610
1610
|
}
|
|
1611
|
+
bindReturningItems(clone.returningItems, values);
|
|
1611
1612
|
return clone;
|
|
1612
1613
|
}
|
|
1613
1614
|
if (clone.kind === "drop-table" || clone.kind === "create-view" || clone.kind === "drop-view" || clone.kind === "transaction") {
|
|
@@ -1643,8 +1644,15 @@ function bindStatementParameters(statement, params) {
|
|
|
1643
1644
|
predicate.left = bindExpression(predicate.left, values);
|
|
1644
1645
|
predicate.right = bindExpression(predicate.right, values);
|
|
1645
1646
|
}
|
|
1647
|
+
bindReturningItems(clone.returningItems, values);
|
|
1646
1648
|
return clone;
|
|
1647
1649
|
}
|
|
1650
|
+
function bindReturningItems(items, values) {
|
|
1651
|
+
if (items === void 0)
|
|
1652
|
+
return;
|
|
1653
|
+
for (const item of items)
|
|
1654
|
+
item.expression = bindExpression(item.expression, values);
|
|
1655
|
+
}
|
|
1648
1656
|
function inferBlockSchema(plan, schemas) {
|
|
1649
1657
|
const sources = [plan.base, ...plan.joins];
|
|
1650
1658
|
const multipleSources = sources.filter((source) => {
|
|
@@ -3333,7 +3333,7 @@ class IndexedDbBlockStore {
|
|
|
3333
3333
|
const indexKey = ftsChunkIndexKey(ftsEntry.tableId, column.columnId);
|
|
3334
3334
|
const rawChunkIndex = await requestResult(catalog.get(indexKey));
|
|
3335
3335
|
const chunkIndex = decodeFtsDeltaIndex(rawChunkIndex);
|
|
3336
|
-
if (rawChunkIndex !== void 0 && chunkIndex === void 0 || (chunkIndex?.versions.length ?? 0) >= MAX_FTS_DELTA_CHUNKS) {
|
|
3336
|
+
if (rawChunkIndex !== void 0 && chunkIndex === void 0 || postings.length > 0 && (chunkIndex?.versions.length ?? 0) >= MAX_FTS_DELTA_CHUNKS) {
|
|
3337
3337
|
for (const version of chunkIndex?.versions ?? []) {
|
|
3338
3338
|
catalog.delete(ftsChunkKey(ftsEntry.tableId, column.columnId, version));
|
|
3339
3339
|
}
|
|
@@ -3356,6 +3356,14 @@ class IndexedDbBlockStore {
|
|
|
3356
3356
|
});
|
|
3357
3357
|
continue;
|
|
3358
3358
|
}
|
|
3359
|
+
if (postings.length === 0) {
|
|
3360
|
+
ftsDeltaCounts.push({
|
|
3361
|
+
tableId: ftsEntry.tableId,
|
|
3362
|
+
columnId: column.columnId,
|
|
3363
|
+
count: chunkIndex?.versions.length ?? 0
|
|
3364
|
+
});
|
|
3365
|
+
continue;
|
|
3366
|
+
}
|
|
3359
3367
|
catalog.put(structuredClone({
|
|
3360
3368
|
postings,
|
|
3361
3369
|
totalTokens: column.totalTokens
|
|
@@ -1655,6 +1655,8 @@ class RecordCore {
|
|
|
1655
1655
|
const active = activePostingStorageColumnIds(currentTable);
|
|
1656
1656
|
if (!active.has(column.columnId))
|
|
1657
1657
|
continue;
|
|
1658
|
+
if (column.postings.length === 0)
|
|
1659
|
+
continue;
|
|
1658
1660
|
const key = `${changes.tableId}/${column.columnId}`;
|
|
1659
1661
|
const deltas = this.#ftsDeltas.get(key) ?? /* @__PURE__ */ new Map();
|
|
1660
1662
|
if (!deltas.has(version) && deltas.size >= MAX_FTS_DELTA_CHUNKS) {
|
|
@@ -4330,8 +4332,11 @@ class RecordCore {
|
|
|
4330
4332
|
this.#nextAutoIncrement.set(key, next);
|
|
4331
4333
|
for (const [key, base] of cloned.ftsBases)
|
|
4332
4334
|
this.#ftsBases.set(key, base);
|
|
4333
|
-
for (const [key, deltas] of cloned.ftsDeltas)
|
|
4334
|
-
|
|
4335
|
+
for (const [key, deltas] of cloned.ftsDeltas) {
|
|
4336
|
+
const retained = deltas.filter(([, delta]) => delta.postings.length > 0);
|
|
4337
|
+
if (retained.length > 0)
|
|
4338
|
+
this.#ftsDeltas.set(key, new Map(retained));
|
|
4339
|
+
}
|
|
4335
4340
|
for (const [tableId, tokens] of cloned.uniqueKeys) {
|
|
4336
4341
|
this.#uniqueKeys.set(tableId, new OrderedStringSet(tokens));
|
|
4337
4342
|
}
|
|
@@ -5425,7 +5430,14 @@ function validateRecordCoreState(state, physical) {
|
|
|
5425
5430
|
throw new TypeError(`Full-text delta ${key} repeats a version`);
|
|
5426
5431
|
versions.add(version);
|
|
5427
5432
|
whole(delta.totalTokens, `Full-text delta ${key} token count`);
|
|
5428
|
-
if (
|
|
5433
|
+
if (!Array.isArray(delta.postings)) {
|
|
5434
|
+
throw new TypeError(`Full-text delta ${key} postings must be an array`);
|
|
5435
|
+
}
|
|
5436
|
+
if (delta.postings.length === 0) {
|
|
5437
|
+
if (delta.totalTokens !== 0) {
|
|
5438
|
+
throw new TypeError(`Empty full-text delta ${key} must have a zero token total`);
|
|
5439
|
+
}
|
|
5440
|
+
} else if (validateFtsPostingChunks([delta.postings], `Full-text delta ${key}`) !== delta.totalTokens) {
|
|
5429
5441
|
throw new TypeError(`Full-text delta ${key} token total does not match its postings`);
|
|
5430
5442
|
}
|
|
5431
5443
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minnowdb/core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "A columnar SQL database for the browser: PostgreSQL-style SQL over durable IndexedDB or OPFS data, with no server or WebAssembly module.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Eric Wilhite",
|
package/sql-feature-matrix.json
CHANGED
|
@@ -420,8 +420,8 @@
|
|
|
420
420
|
{
|
|
421
421
|
"id": "subquery.correlated-select",
|
|
422
422
|
"status": "supported",
|
|
423
|
-
"example": "SELECT r.region, (SELECT
|
|
424
|
-
"notes": "Correlated scalar aggregates and single-row projections decorrelate in the select list. In a grouped query,
|
|
423
|
+
"example": "SELECT r.region, (SELECT MAX(q.amount + r.amount) FROM rows q WHERE q.region = r.region) AS regional FROM rows r",
|
|
424
|
+
"notes": "Correlated scalar aggregates and single-row projections decorrelate in the select list. Every qualified outer column used by the inner predicates or projection becomes part of the distinct probe tuple. In a grouped query, outer references must be GROUP BY columns and the scalar cannot sit inside an outer aggregate."
|
|
425
425
|
},
|
|
426
426
|
{
|
|
427
427
|
"id": "subquery.correlated-select-limit",
|