sqlmath 2026.7.30 → 2026.9.29

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/test.mjs CHANGED
@@ -20,11 +20,6 @@
20
20
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  // SOFTWARE.
22
22
 
23
- /*
24
- * example usage:
25
- npm_config_mode_test_save2=1 npm test
26
- */
27
-
28
23
  /*jslint beta, node*/
29
24
  import moduleChildProcess from "child_process";
30
25
  import modulePath from "path";
@@ -140,9 +135,9 @@ jstestDescribe((
140
135
  moduleChildProcess.execFile
141
136
  )(
142
137
  (
143
- process.cwd()
144
- + modulePath.sep
145
- + SQLMATH_EXE
138
+ process.cwd() +
139
+ modulePath.sep +
140
+ SQLMATH_EXE
146
141
  ),
147
142
  [
148
143
  ":memory:",
@@ -208,10 +203,10 @@ jstestDescribe((
208
203
  valExpect, valExpect, 0
209
204
  ],
210
205
  (
211
- "SELECT 0;"
212
- + " SELECT ? AS c1, ? AS c2, ? AS c3, ? AS c4"
213
- + " UNION ALL SELECT ?1, ?2, ?3, ?4"
214
- + " UNION ALL SELECT ?1, ?2, ?3, ?4"
206
+ "SELECT 0;" +
207
+ " SELECT ? AS c1, ? AS c2, ? AS c3, ? AS c4" +
208
+ " UNION ALL SELECT ?1, ?2, ?3, ?4" +
209
+ " UNION ALL SELECT ?1, ?2, ?3, ?4"
215
210
  )
216
211
  ],
217
212
  [
@@ -221,10 +216,10 @@ jstestDescribe((
221
216
  k3: 0
222
217
  },
223
218
  (
224
- "SELECT 0;"
225
- + " SELECT $k1 AS c1, $k2 AS c2, $k3 AS c3, $k4 AS c4"
226
- + " UNION ALL SELECT :k1, :k2, :k3, :k4"
227
- + " UNION ALL SELECT @k1, @k2, @k3, @k4"
219
+ "SELECT 0;" +
220
+ " SELECT $k1 AS c1, $k2 AS c2, $k3 AS c3, $k4 AS c4" +
221
+ " UNION ALL SELECT :k1, :k2, :k3, :k4" +
222
+ " UNION ALL SELECT @k1, @k2, @k3, @k4"
228
223
  )
229
224
  ]
230
225
  ].map(async function ([
@@ -314,8 +309,8 @@ jstestDescribe((
314
309
  break;
315
310
  }
316
311
  if (
317
- valIn?.constructor === ArrayBuffer
318
- || ArrayBuffer.isView(valIn)
312
+ valIn?.constructor === ArrayBuffer ||
313
+ ArrayBuffer.isView(valIn)
319
314
  ) {
320
315
  bufExpect = new TextDecoder().decode(valIn);
321
316
  break;
@@ -703,7 +698,7 @@ SELECT 401 AS c401, 402 AS c402, 403 AS c403
703
698
  UNION ALL
704
699
  VALUES
705
700
  (501, 502.0123, 5030123456789),
706
- (601, '602', '603_\"\x01\x08\x09\x0a\x0b\x0c\x0d\x0e'),
701
+ (601, '602', '603_"\u0001\u0008\u0009\u000a\u000b\u000c\u000d\u000e'),
707
702
  (?1, ?2, ?3),
708
703
  (CAST(?1 AS TEXT), CAST(?2 AS TEXT), CAST(?3 AS TEXT)),
709
704
  (
@@ -1434,8 +1429,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1434
1429
  return arg - (arg % 1_00);
1435
1430
  }
1436
1431
  if (
1437
- (/^IDATEYMDFROM|'ITEXTYMD'/).test(sqlFunc)
1438
- || ((/_YMD$/).test(sqlFunc) && !(/IDATEFROM/).test(sqlFunc))
1432
+ (/^IDATEYMDFROM|'ITEXTYMD'/).test(sqlFunc) ||
1433
+ ((/_YMD$/).test(sqlFunc) && !(/IDATEFROM/).test(sqlFunc))
1439
1434
  ) {
1440
1435
  return idateArgYmdTruncate(arg);
1441
1436
  }
@@ -1845,8 +1840,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1845
1840
  "CASTTEXTOREMPTY": "",
1846
1841
  "COPYBLOB": "",
1847
1842
  "SHA256": (
1848
- "E3B0C44298FC1C149AFBF4C8996FB924"
1849
- + "27AE41E4649B934CA495991B7852B855"
1843
+ "E3B0C44298FC1C149AFBF4C8996FB924" +
1844
+ "27AE41E4649B934CA495991B7852B855"
1850
1845
  )
1851
1846
  },
1852
1847
  "'-0.5'": {
@@ -1855,8 +1850,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1855
1850
  "CASTTEXTOREMPTY": "-0.5",
1856
1851
  "COPYBLOB": "-0.5",
1857
1852
  "SHA256": (
1858
- "1B07B0CFFA0B3F596B5E048B01151688"
1859
- + "86CC5183DD518655B5515EE5DDDAC6D1"
1853
+ "1B07B0CFFA0B3F596B5E048B01151688" +
1854
+ "86CC5183DD518655B5515EE5DDDAC6D1"
1860
1855
  )
1861
1856
  },
1862
1857
  "'-1'": {
@@ -1867,8 +1862,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1867
1862
  "COT": -0.642092615934331,
1868
1863
  "COTH": -1.31303528549933,
1869
1864
  "SHA256": (
1870
- "1BAD6B8CF97131FCEAB8543E81F77571"
1871
- + "95FBB1D36B376EE994AD1CF17699C464"
1865
+ "1BAD6B8CF97131FCEAB8543E81F77571" +
1866
+ "95FBB1D36B376EE994AD1CF17699C464"
1872
1867
  ),
1873
1868
  "SIGN": -1,
1874
1869
  "SQRTWITHSIGN": -1
@@ -1881,8 +1876,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1881
1876
  "COT": null,
1882
1877
  "COTH": null,
1883
1878
  "SHA256": (
1884
- "5FECEB66FFC86F38D952786C6D696C79"
1885
- + "C2DBC239DD4E91B46729D73A27FB57E9"
1879
+ "5FECEB66FFC86F38D952786C6D696C79" +
1880
+ "C2DBC239DD4E91B46729D73A27FB57E9"
1886
1881
  ),
1887
1882
  "SIGN": 0,
1888
1883
  "SQRTWITHSIGN": 0
@@ -1893,8 +1888,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1893
1888
  "CASTTEXTOREMPTY": "0.5",
1894
1889
  "COPYBLOB": "0.5",
1895
1890
  "SHA256": (
1896
- "D2CBAD71FF333DE67D07EC676E352AB7"
1897
- + "F38248EB69C942950157220607C55E84"
1891
+ "D2CBAD71FF333DE67D07EC676E352AB7" +
1892
+ "F38248EB69C942950157220607C55E84"
1898
1893
  )
1899
1894
  },
1900
1895
  "'1'": {
@@ -1905,8 +1900,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1905
1900
  "COT": 0.642092615934331,
1906
1901
  "COTH": 1.31303528549933,
1907
1902
  "SHA256": (
1908
- "6B86B273FF34FCE19D6B804EFF5A3F57"
1909
- + "47ADA4EAA22F1D49C01E52DDB7875B4B"
1903
+ "6B86B273FF34FCE19D6B804EFF5A3F57" +
1904
+ "47ADA4EAA22F1D49C01E52DDB7875B4B"
1910
1905
  ),
1911
1906
  "SIGN": 1,
1912
1907
  "SQRTWITHSIGN": 1
@@ -1917,20 +1912,20 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1917
1912
  "CASTTEXTOREMPTY": "aa",
1918
1913
  "COPYBLOB": "aa",
1919
1914
  "SHA256": (
1920
- "961B6DD3EDE3CB8ECBAACBD68DE040CD"
1921
- + "78EB2ED5889130CCEB4C49268EA4D506"
1915
+ "961B6DD3EDE3CB8ECBAACBD68DE040CD" +
1916
+ "78EB2ED5889130CCEB4C49268EA4D506"
1922
1917
  )
1923
1918
  },
1924
1919
  "'abc'": {
1925
1920
  "SHA256": (
1926
- "BA7816BF8F01CFEA414140DE5DAE2223"
1927
- + "B00361A396177A9CB410FF61F20015AD"
1921
+ "BA7816BF8F01CFEA414140DE5DAE2223" +
1922
+ "B00361A396177A9CB410FF61F20015AD"
1928
1923
  )
1929
1924
  },
1930
1925
  "'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'": {
1931
1926
  "SHA256": (
1932
- "248D6A61D20638B8E5C026930C3E6039"
1933
- + "A33CE45964FF2167F6ECEDD419DB06C1"
1927
+ "248D6A61D20638B8E5C026930C3E6039" +
1928
+ "A33CE45964FF2167F6ECEDD419DB06C1"
1934
1929
  )
1935
1930
  },
1936
1931
  "'hello'": {
@@ -1939,8 +1934,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1939
1934
  "CASTTEXTOREMPTY": "hello",
1940
1935
  "COPYBLOB": "hello",
1941
1936
  "SHA256": (
1942
- "2CF24DBA5FB0A30E26E83B2AC5B9E29E"
1943
- + "1B161E5C1FA7425E73043362938B9824"
1937
+ "2CF24DBA5FB0A30E26E83B2AC5B9E29E" +
1938
+ "1B161E5C1FA7425E73043362938B9824"
1944
1939
  )
1945
1940
  },
1946
1941
  "-0.5": {
@@ -1949,16 +1944,16 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1949
1944
  "CASTTEXTOREMPTY": "-0.5",
1950
1945
  "COPYBLOB": -0.5,
1951
1946
  "SHA256": (
1952
- "1B07B0CFFA0B3F596B5E048B01151688"
1953
- + "86CC5183DD518655B5515EE5DDDAC6D1"
1947
+ "1B07B0CFFA0B3F596B5E048B01151688" +
1948
+ "86CC5183DD518655B5515EE5DDDAC6D1"
1954
1949
  )
1955
1950
  },
1956
1951
  "-0x7fffffffffffffff": {
1957
1952
  "COT": -0.0118008981305845,
1958
1953
  "COTH": -1,
1959
1954
  "SHA256": ( // '-9223372036854775807'
1960
- "B7AE81320053F61245ED2D36E72E1D05"
1961
- + "AD4235D8C784E60285F1EB1F06DA7845"
1955
+ "B7AE81320053F61245ED2D36E72E1D05" +
1956
+ "AD4235D8C784E60285F1EB1F06DA7845"
1962
1957
  ),
1963
1958
  "SIGN": -1,
1964
1959
  "SQRTWITHSIGN": -3037000499.97605
@@ -1971,8 +1966,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1971
1966
  "COT": -0.642092615934331,
1972
1967
  "COTH": -1.31303528549933,
1973
1968
  "SHA256": (
1974
- "1BAD6B8CF97131FCEAB8543E81F77571"
1975
- + "95FBB1D36B376EE994AD1CF17699C464"
1969
+ "1BAD6B8CF97131FCEAB8543E81F77571" +
1970
+ "95FBB1D36B376EE994AD1CF17699C464"
1976
1971
  ),
1977
1972
  "SIGN": -1,
1978
1973
  "SQRTWITHSIGN": -1
@@ -1981,8 +1976,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1981
1976
  "COT": null,
1982
1977
  "COTH": -1,
1983
1978
  "SHA256": ( // '-Inf'
1984
- "8C1FB05600CEB1FF74474E66DDD603F5"
1985
- + "FE8C839B03598A124E2AACB6A08C8837"
1979
+ "8C1FB05600CEB1FF74474E66DDD603F5" +
1980
+ "FE8C839B03598A124E2AACB6A08C8837"
1986
1981
  ),
1987
1982
  "SIGN": -1,
1988
1983
  "SQRTWITHSIGN": null
@@ -1995,8 +1990,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1995
1990
  "COT": null,
1996
1991
  "COTH": null,
1997
1992
  "SHA256": (
1998
- "5FECEB66FFC86F38D952786C6D696C79"
1999
- + "C2DBC239DD4E91B46729D73A27FB57E9"
1993
+ "5FECEB66FFC86F38D952786C6D696C79" +
1994
+ "C2DBC239DD4E91B46729D73A27FB57E9"
2000
1995
  ),
2001
1996
  "SIGN": 0,
2002
1997
  "SQRTWITHSIGN": 0
@@ -2007,8 +2002,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2007
2002
  "CASTTEXTOREMPTY": "0.5",
2008
2003
  "COPYBLOB": 0.5,
2009
2004
  "SHA256": (
2010
- "D2CBAD71FF333DE67D07EC676E352AB7"
2011
- + "F38248EB69C942950157220607C55E84"
2005
+ "D2CBAD71FF333DE67D07EC676E352AB7" +
2006
+ "F38248EB69C942950157220607C55E84"
2012
2007
  )
2013
2008
  },
2014
2009
  "0.5, 0.5": {
@@ -2024,8 +2019,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2024
2019
  "COT": 0.0118008981305845,
2025
2020
  "COTH": 1,
2026
2021
  "SHA256": ( // '9223372036854775807'
2027
- "B34A1C30A715F6BF8B7243AFA7FAB883"
2028
- + "CE3612B7231716BDCBBDC1982E1AED29"
2022
+ "B34A1C30A715F6BF8B7243AFA7FAB883" +
2023
+ "CE3612B7231716BDCBBDC1982E1AED29"
2029
2024
  ),
2030
2025
  "SIGN": 1,
2031
2026
  "SQRTWITHSIGN": 3037000499.97605
@@ -2034,8 +2029,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2034
2029
  "COT": -0.0118008981305845,
2035
2030
  "COTH": -1,
2036
2031
  "SHA256": ( // '-9223372036854775808'
2037
- "85386477F3AF47E4A0B308EE3B3A688D"
2038
- + "F16E8B2228105DD7D4DCD42A9807CB78"
2032
+ "85386477F3AF47E4A0B308EE3B3A688D" +
2033
+ "F16E8B2228105DD7D4DCD42A9807CB78"
2039
2034
  ),
2040
2035
  "SIGN": -1,
2041
2036
  "SQRTWITHSIGN": -3037000499.97605
@@ -2044,8 +2039,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2044
2039
  "COT": -0.642092615934331,
2045
2040
  "COTH": -1.31303528549933,
2046
2041
  "SHA256": ( // '-1'
2047
- "1BAD6B8CF97131FCEAB8543E81F77571"
2048
- + "95FBB1D36B376EE994AD1CF17699C464"
2042
+ "1BAD6B8CF97131FCEAB8543E81F77571" +
2043
+ "95FBB1D36B376EE994AD1CF17699C464"
2049
2044
  ),
2050
2045
  "SIGN": -1,
2051
2046
  "SQRTWITHSIGN": -1
@@ -2058,8 +2053,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2058
2053
  "COT": 0.642092615934331,
2059
2054
  "COTH": 1.31303528549933,
2060
2055
  "SHA256": (
2061
- "6B86B273FF34FCE19D6B804EFF5A3F57"
2062
- + "47ADA4EAA22F1D49C01E52DDB7875B4B"
2056
+ "6B86B273FF34FCE19D6B804EFF5A3F57" +
2057
+ "47ADA4EAA22F1D49C01E52DDB7875B4B"
2063
2058
  ),
2064
2059
  "SIGN": 1,
2065
2060
  "SQRTWITHSIGN": 1
@@ -2070,8 +2065,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2070
2065
  "COT": null,
2071
2066
  "COTH": 1,
2072
2067
  "SHA256": ( // 'Inf'
2073
- "1DAEC9C71EE2A842CDEE6977AD8C562E"
2074
- + "D4AA4FB1338BECD25D79A104B473D9D8"
2068
+ "1DAEC9C71EE2A842CDEE6977AD8C562E" +
2069
+ "D4AA4FB1338BECD25D79A104B473D9D8"
2075
2070
  ),
2076
2071
  "SIGN": 1,
2077
2072
  "SQRTWITHSIGN": null
@@ -2102,8 +2097,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2102
2097
  "CASTTEXTOREMPTY": "",
2103
2098
  "COPYBLOB": null,
2104
2099
  "SHA256": (
2105
- "E3B0C44298FC1C149AFBF4C8996FB924"
2106
- + "27AE41E4649B934CA495991B7852B855"
2100
+ "E3B0C44298FC1C149AFBF4C8996FB924" +
2101
+ "27AE41E4649B934CA495991B7852B855"
2107
2102
  )
2108
2103
  },
2109
2104
  "ZEROBLOB(1)": {
@@ -2112,8 +2107,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2112
2107
  "CASTTEXTOREMPTY": "",
2113
2108
  "COPYBLOB": null,
2114
2109
  "SHA256": (
2115
- "6E340B9CFFB37A989CA544E6BB780A2C"
2116
- + "78901D3FB33738768511A30617AFA01D"
2110
+ "6E340B9CFFB37A989CA544E6BB780A2C" +
2111
+ "78901D3FB33738768511A30617AFA01D"
2117
2112
  )
2118
2113
  }
2119
2114
  }).forEach(function ([
@@ -2155,15 +2150,13 @@ DROP TABLE IF EXISTS __tmp1;
2155
2150
  CREATE TEMP TABLE __tmp1 (val REAL);
2156
2151
  SELECT
2157
2152
  1 AS id,
2158
- MEDIAN2(val) AS mdn,
2159
- QUANTILE(val, 0.5) AS qnt,
2160
2153
  STDEV(val) AS std
2161
2154
  FROM __tmp1;
2162
2155
  `)
2163
2156
  });
2164
2157
  assertJsonEqual(
2165
2158
  valActual,
2166
- [{id: 1, mdn: null, qnt: null, std: null}]
2159
+ [{id: 1, std: null}]
2167
2160
  );
2168
2161
  }());
2169
2162
  await Promise.all([
@@ -2226,20 +2219,12 @@ SELECT
2226
2219
  ]) {
2227
2220
  let avg = 0;
2228
2221
  let data2;
2229
- let valExpectMdn;
2230
2222
  let valExpectStd = 0;
2231
2223
  data2 = data.map(function (elem) {
2232
2224
  return Number(elem);
2233
2225
  }).filter(function (elem) {
2234
2226
  return Number.isFinite(elem);
2235
2227
  }).sort();
2236
- valExpectMdn = (
2237
- data2.length % 2 === 0
2238
- ? 0.5 * (
2239
- data2[0.5 * data2.length - 1] + data2[0.5 * data2.length]
2240
- )
2241
- : data2[0.5 * (data2.length - 1)]
2242
- );
2243
2228
  data2.forEach(function (elem) {
2244
2229
  avg += elem;
2245
2230
  });
@@ -2267,12 +2252,8 @@ SELECT
2267
2252
  },
2268
2253
  db,
2269
2254
  sql: (`
2270
- -- test null-case handling-behavior
2271
- SELECT QUANTILE(value, ${qq}) AS qnt FROM JSON_EACH($tmp1) WHERE 0;
2272
2255
  -- test last-row handling-behavior
2273
2256
  SELECT
2274
- MEDIAN2(value) AS mdn,
2275
- QUANTILE(value, ${qq}) AS qnt,
2276
2257
  ROUND(stdev(value), 8) AS std
2277
2258
  FROM JSON_EACH($tmp1);
2278
2259
  `)
@@ -2280,8 +2261,6 @@ SELECT
2280
2261
  assertJsonEqual(
2281
2262
  valActual,
2282
2263
  {
2283
- mdn: valExpectMdn,
2284
- qnt: valExpect ?? null,
2285
2264
  std: valExpectStd
2286
2265
  },
2287
2266
  {
@@ -2289,7 +2268,6 @@ SELECT
2289
2268
  qq,
2290
2269
  valActual,
2291
2270
  valExpect,
2292
- valExpectMdn,
2293
2271
  valExpectStd
2294
2272
  }
2295
2273
  );
@@ -2474,6 +2452,201 @@ SELECT DOUBLEARRAY_JSONTO(WIN_AVG2(1, 2, 3)) FROM __tmp1;
2474
2452
  })
2475
2453
  ]);
2476
2454
  });
2455
+ jstestIt((
2456
+ "test sqlite-extension-win_coinflip2 handling-behavior"
2457
+ ), async function test_sqlite_extension_win_coinflip2() {
2458
+ // win_coinflip2 reads ONE value per column, and key biasba50 needs a
2459
+ // second bit per row - was the flip called correctly - so it reads the
2460
+ // 4-state code SIGN(outcome) * (1 + hit) documented at struct
2461
+ // WinCoinflip, sqlmath_base.c:
2462
+ // +2 head-hit +1 head-miss 0 excluded -1 tail-miss -2 tail-hit
2463
+ // Sign is the OUTCOME class, so nhead and ntail are the two denominators
2464
+ // balanced-accuracy divides by, and biashead reads the CLASS BALANCE
2465
+ // under this code, not the hit-rate.
2466
+ let db = await dbOpenAsync({});
2467
+ async function test_coinflip_extract({
2468
+ sqlBetween,
2469
+ valExpect,
2470
+ valIn
2471
+ }) {
2472
+ let valActual = await dbExecAndReturnLastRow({
2473
+ bindList: {
2474
+ valIn: JSON.stringify(valIn)
2475
+ },
2476
+ db,
2477
+ sql: (`
2478
+ SELECT
2479
+ COINFLIP_EXTRACT(__wcf, 0, 'nflip') AS nflip,
2480
+ COINFLIP_EXTRACT(__wcf, 0, 'nhead') AS nhead,
2481
+ COINFLIP_EXTRACT(__wcf, 0, 'nhithead') AS nhithead,
2482
+ COINFLIP_EXTRACT(__wcf, 0, 'nhittail') AS nhittail,
2483
+ COINFLIP_EXTRACT(__wcf, 0, 'ntail') AS ntail,
2484
+ ROUND(COINFLIP_EXTRACT(__wcf, 0, 'biasba50'), 6) AS biasba50,
2485
+ ROUND(COINFLIP_EXTRACT(__wcf, 0, 'biashead'), 6) AS biashead
2486
+ FROM (
2487
+ SELECT
2488
+ WIN_COINFLIP2(value) OVER (
2489
+ ORDER BY key ASC
2490
+ ${sqlBetween}
2491
+ ) AS __wcf
2492
+ FROM JSON_EACH($valIn)
2493
+ );
2494
+ `)
2495
+ });
2496
+ assertJsonEqual(valActual, valExpect);
2497
+ }
2498
+ await Promise.all([
2499
+ // test biasba50-unbalanced-panel handling-behavior
2500
+ // 8 up-days with 7 called right, 2 down-days with 0 called
2501
+ // right - a 70% RAW hit-rate that balanced-accuracy scores
2502
+ // BELOW chance, which is the whole reason for the key.
2503
+ test_coinflip_extract({
2504
+ sqlBetween: "",
2505
+ valExpect: {
2506
+ biasba50: -0.0625,
2507
+ biashead: 0.3,
2508
+ nflip: 10,
2509
+ nhead: 8,
2510
+ nhithead: 7,
2511
+ nhittail: 0,
2512
+ ntail: 2
2513
+ },
2514
+ valIn: [2, 2, 2, 2, 2, 2, 2, 1, -1, -1]
2515
+ }),
2516
+ // test biasba50-parrot-null handling-behavior
2517
+ // an always-up caller hits every up-day and misses every
2518
+ // down-day, and MUST score exactly 0.
2519
+ test_coinflip_extract({
2520
+ sqlBetween: "",
2521
+ valExpect: {
2522
+ biasba50: 0,
2523
+ biashead: 0.2,
2524
+ nflip: 10,
2525
+ nhead: 7,
2526
+ nhithead: 7,
2527
+ nhittail: 0,
2528
+ ntail: 3
2529
+ },
2530
+ valIn: [2, 2, 2, 2, 2, 2, 2, -1, -1, -1]
2531
+ }),
2532
+ // test biasba50-range handling-behavior
2533
+ test_coinflip_extract({
2534
+ sqlBetween: "",
2535
+ valExpect: {
2536
+ biasba50: 0.5,
2537
+ biashead: 0.1,
2538
+ nflip: 5,
2539
+ nhead: 3,
2540
+ nhithead: 3,
2541
+ nhittail: 2,
2542
+ ntail: 2
2543
+ },
2544
+ valIn: [2, 2, 2, -2, -2]
2545
+ }),
2546
+ test_coinflip_extract({
2547
+ sqlBetween: "",
2548
+ valExpect: {
2549
+ biasba50: -0.5,
2550
+ biashead: 0.1,
2551
+ nflip: 5,
2552
+ nhead: 3,
2553
+ nhithead: 0,
2554
+ nhittail: 0,
2555
+ ntail: 2
2556
+ },
2557
+ valIn: [1, 1, 1, -1, -1]
2558
+ }),
2559
+ // test biasba50-one-sided-panel handling-behavior
2560
+ // no down-days means no balanced-accuracy - 0.0/0.0 is NaN,
2561
+ // which sqlite3_result_double_or_null maps to NULL.
2562
+ test_coinflip_extract({
2563
+ sqlBetween: "",
2564
+ valExpect: {
2565
+ biasba50: null,
2566
+ biashead: 0.5,
2567
+ nflip: 3,
2568
+ nhead: 3,
2569
+ nhithead: 2,
2570
+ nhittail: 0,
2571
+ ntail: 0
2572
+ },
2573
+ valIn: [2, 2, 1]
2574
+ }),
2575
+ // test biasba50-legacy-column handling-behavior
2576
+ // a plain 0/1 column carries no hit-bit, so the pre-existing
2577
+ // keys are unchanged and the two hit-counters stay 0.
2578
+ test_coinflip_extract({
2579
+ sqlBetween: "",
2580
+ valExpect: {
2581
+ biasba50: null,
2582
+ biashead: 0.166667,
2583
+ nflip: 6,
2584
+ nhead: 4,
2585
+ nhithead: 0,
2586
+ nhittail: 0,
2587
+ ntail: 0
2588
+ },
2589
+ valIn: [1, 1, 0, 1, 0, 1]
2590
+ }),
2591
+ // test biasba50-sliding-window handling-behavior
2592
+ // a bounded frame forces xInverse - the 6 leading rows are
2593
+ // all HITS, so an inverse that failed to decrement the two
2594
+ // hit-counters would inflate biasba50 here.
2595
+ test_coinflip_extract({
2596
+ sqlBetween: "ROWS BETWEEN 3 PRECEDING AND CURRENT ROW",
2597
+ valExpect: {
2598
+ biasba50: 0.25,
2599
+ biashead: 0,
2600
+ nflip: 4,
2601
+ nhead: 2,
2602
+ nhithead: 2,
2603
+ nhittail: 1,
2604
+ ntail: 2
2605
+ },
2606
+ valIn: [2, 2, 2, -2, -2, -2, 2, -1, -2, 2]
2607
+ })
2608
+ ]);
2609
+ // test win_coinflip2-multi-column handling-behavior
2610
+ assertJsonEqual(await dbExecAndReturnLastRow({
2611
+ db,
2612
+ sql: (`
2613
+ SELECT
2614
+ COINFLIP_EXTRACT(__wcf, 0, 'biasba50') AS aa,
2615
+ COINFLIP_EXTRACT(__wcf, 1, 'biasba50') AS bb,
2616
+ COINFLIP_EXTRACT(__wcf, 1, 'nstreak') AS cc
2617
+ FROM (
2618
+ SELECT
2619
+ WIN_COINFLIP2(aa, bb) OVER (ORDER BY id ASC) AS __wcf
2620
+ FROM (
2621
+ SELECT 1 AS id, 2 AS aa, 1 AS bb
2622
+ UNION ALL SELECT 2, 2, -1
2623
+ UNION ALL SELECT 3, -2, -1
2624
+ UNION ALL SELECT 4, -1, -1
2625
+ )
2626
+ );
2627
+ `)
2628
+ }), {
2629
+ aa: 0.25,
2630
+ bb: -0.5,
2631
+ cc: -3
2632
+ });
2633
+ // test coinflip_extract-error handling-behavior
2634
+ await assertErrorThrownAsync(
2635
+ dbExecAsync.bind(undefined, {
2636
+ db,
2637
+ sql: (`
2638
+ SELECT
2639
+ COINFLIP_EXTRACT(__wcf, 0, 'biasba49')
2640
+ FROM (
2641
+ SELECT
2642
+ WIN_COINFLIP2(value) OVER (ORDER BY key ASC) AS __wcf
2643
+ FROM JSON_EACH('[2,-2]')
2644
+ );
2645
+ `)
2646
+ }),
2647
+ "invalid key"
2648
+ );
2649
+ });
2477
2650
  jstestIt((
2478
2651
  "test sqlite-extension-win_emax handling-behavior"
2479
2652
  ), async function test_sqlite_extension_win_emax() {
@@ -3269,7 +3442,7 @@ SELECT
3269
3442
  "id2": 3,
3270
3443
  "laa": -4.5,
3271
3444
  "lbb": 2.5,
3272
- "lee": 0.40824829,
3445
+ "lee": 0.70710678,
3273
3446
  "lxy": 0.94491118,
3274
3447
  "lyy": 3,
3275
3448
  "mee": 1.52752523,
@@ -3289,7 +3462,7 @@ SELECT
3289
3462
  "id2": 4,
3290
3463
  "laa": -3,
3291
3464
  "lbb": 1.81818182,
3292
- "lee": 0.47673129,
3465
+ "lee": 0.67419986,
3293
3466
  "lxy": 0.95346259,
3294
3467
  "lyy": 4.27272727,
3295
3468
  "mee": 1.82574186,
@@ -3309,7 +3482,7 @@ SELECT
3309
3482
  "id2": 5,
3310
3483
  "laa": -2.29411765,
3311
3484
  "lbb": 1.52941176,
3312
- "lee": 0.50874702,
3485
+ "lee": 0.65678958,
3313
3486
  "lxy": 0.96164474,
3314
3487
  "lyy": 5.35294118,
3315
3488
  "mee": 2.07364414,
@@ -3329,7 +3502,7 @@ SELECT
3329
3502
  "id2": 6,
3330
3503
  "laa": -2.54385965,
3331
3504
  "lbb": 1.63157895,
3332
- "lee": 0.50725727,
3505
+ "lee": 0.62126074,
3333
3506
  "lxy": 0.97080629,
3334
3507
  "lyy": 5.61403509,
3335
3508
  "mee": 2.31660671,
@@ -3349,7 +3522,7 @@ SELECT
3349
3522
  "id2": 7,
3350
3523
  "laa": -2.65,
3351
3524
  "lbb": 1.675,
3352
- "lee": 0.48550416,
3525
+ "lee": 0.57445626,
3353
3526
  "lxy": 0.9752227,
3354
3527
  "lyy": 5.725,
3355
3528
  "mee": 2.37045304,
@@ -3369,7 +3542,7 @@ SELECT
3369
3542
  "id2": 8,
3370
3543
  "laa": -2.5,
3371
3544
  "lbb": 1.625,
3372
- "lee": 0.46770717,
3545
+ "lee": 0.54006172,
3373
3546
  "lxy": 0.97991187,
3374
3547
  "lyy": 7.25,
3375
3548
  "mee": 2.50713268,
@@ -3389,7 +3562,7 @@ SELECT
3389
3562
  "id2": 9,
3390
3563
  "laa": 0.75,
3391
3564
  "lbb": 0.85,
3392
- "lee": 0.94207218,
3565
+ "lee": 1.08781126,
3393
3566
  "lxy": 0.89597867,
3394
3567
  "lyy": 9.25,
3395
3568
  "mee": 2.26778684,
@@ -3409,7 +3582,7 @@ SELECT
3409
3582
  "id2": 10,
3410
3583
  "laa": 2.75,
3411
3584
  "lbb": 0.55,
3412
- "lee": 0.8587782,
3585
+ "lee": 0.99163165,
3413
3586
  "lxy": 0.81989159,
3414
3587
  "lyy": 3.85,
3415
3588
  "mee": 1.60356745,
@@ -3451,6 +3624,15 @@ SELECT WIN_SINEFIT2(1, 2, 3) FROM (SELECT 1);
3451
3624
  `)
3452
3625
  });
3453
3626
  }, "wrong number of arguments");
3627
+ // test win_sinefit2-modeSnr-bitmask-overflow handling-behavior
3628
+ await assertErrorThrownAsync(function () {
3629
+ return dbExecAsync({
3630
+ db,
3631
+ sql: (`
3632
+ SELECT WIN_SINEFIT2(1, 2${", 3, 4".repeat(31)}) FROM (SELECT 1);
3633
+ `)
3634
+ });
3635
+ }, "too many columns");
3454
3636
  // test win_sinefit2-null-case handling-behavior
3455
3637
  valActual = await dbExecAndReturnLastTable({
3456
3638
  db,
@@ -3465,6 +3647,323 @@ SELECT DOUBLEARRAY_JSONTO(WIN_SINEFIT2(1, 2, 3, 4)) FROM __tmp1;
3465
3647
  });
3466
3648
  assertJsonEqual(valActual, [null]);
3467
3649
  }()),
3650
+ (async function () {
3651
+ let valActual;
3652
+ let valSine = JSON.stringify(Array.from({
3653
+ length: 64
3654
+ }, function (ignore, ii) {
3655
+ return [ii + 1, Math.sin(0.5 * (ii + 1)) + 0.1 * ii];
3656
+ }));
3657
+ // test win_sinefit2-modeSnr-bitmask handling-behavior
3658
+ // Mask 0b110 is inverted on purpose - column 0 must NOT be
3659
+ // sine-fit. A build that re-hardcodes column 0, or that
3660
+ // treats modeSnr as an all-or-nothing flag, fails here.
3661
+ valActual = await dbExecAndReturnLastTable({
3662
+ bindList: {
3663
+ valSine
3664
+ },
3665
+ db,
3666
+ sql: (`
3667
+ SELECT
3668
+ SINEFIT_EXTRACT(__wsf, 0, 'sww', 0) = 0 AS sww0_off,
3669
+ SINEFIT_EXTRACT(__wsf, 1, 'sww', 0) > 0 AS sww1_on,
3670
+ SINEFIT_EXTRACT(__wsf, 2, 'sww', 0) > 0 AS sww2_on,
3671
+ SINEFIT_EXTRACT(__wsf, 0, 'rrb', 0) IS NOT NULL AS lnr0_on
3672
+ FROM (
3673
+ SELECT
3674
+ key,
3675
+ WIN_SINEFIT2(
3676
+ 6, NULL,
3677
+ value->>0, value->>1,
3678
+ value->>0, value->>1,
3679
+ value->>0, value->>1
3680
+ ) OVER (
3681
+ ORDER BY key ASC
3682
+ ROWS BETWEEN 31 PRECEDING AND 0 FOLLOWING
3683
+ ) AS __wsf
3684
+ FROM JSON_EACH($valSine)
3685
+ )
3686
+ WHERE key = 63;
3687
+ `)
3688
+ });
3689
+ valActual = valActual.map(function (elem) {
3690
+ return [
3691
+ elem.sww0_off,
3692
+ elem.sww1_on,
3693
+ elem.sww2_on,
3694
+ elem.lnr0_on
3695
+ ];
3696
+ });
3697
+ assertJsonEqual(valActual, [[1, 1, 1, 1]]);
3698
+ }()),
3699
+ (async function () {
3700
+ let valActual;
3701
+ let valSine = JSON.stringify(Array.from({
3702
+ length: 64
3703
+ }, function (ignore, ii) {
3704
+ return [ii + 1, Math.sin(0.5 * (ii + 1)) + 0.1 * ii];
3705
+ }));
3706
+ // test sinefit_extract-dof handling-behavior
3707
+ // lee divides by nnn-2 (laa, lbb) and see by nnn-5 (those
3708
+ // plus saa, spp, sww). Pin the divisors by comparing a
3709
+ // 32-row window against an 8-row one - the ratio of the
3710
+ // two is free of the unknown residual sum-of-squares only
3711
+ // if we instead check the small-window NULL boundaries,
3712
+ // which is what this does: lee goes NULL at nnn <= 2 and
3713
+ // see at nnn <= 5, and both are finite one row later.
3714
+ valActual = await dbExecAndReturnLastTable({
3715
+ bindList: {
3716
+ valSine
3717
+ },
3718
+ db,
3719
+ sql: (`
3720
+ SELECT
3721
+ SINEFIT_EXTRACT(__wsf02, 0, 'lee', 0) IS NULL AS lee_null_at_2,
3722
+ SINEFIT_EXTRACT(__wsf03, 0, 'lee', 0) > 0 AS lee_ok_at_3,
3723
+ SINEFIT_EXTRACT(__wsf05, 0, 'see', 0) IS NULL AS see_null_at_5,
3724
+ SINEFIT_EXTRACT(__wsf06, 0, 'see', 0) >= 0 AS see_ok_at_6
3725
+ FROM (
3726
+ SELECT
3727
+ key,
3728
+ WIN_SINEFIT2(1, NULL, value->>0, value->>1) OVER (
3729
+ ORDER BY key ASC ROWS BETWEEN 1 PRECEDING AND 0 FOLLOWING
3730
+ ) AS __wsf02,
3731
+ WIN_SINEFIT2(1, NULL, value->>0, value->>1) OVER (
3732
+ ORDER BY key ASC ROWS BETWEEN 2 PRECEDING AND 0 FOLLOWING
3733
+ ) AS __wsf03,
3734
+ WIN_SINEFIT2(1, NULL, value->>0, value->>1) OVER (
3735
+ ORDER BY key ASC ROWS BETWEEN 4 PRECEDING AND 0 FOLLOWING
3736
+ ) AS __wsf05,
3737
+ WIN_SINEFIT2(1, NULL, value->>0, value->>1) OVER (
3738
+ ORDER BY key ASC ROWS BETWEEN 5 PRECEDING AND 0 FOLLOWING
3739
+ ) AS __wsf06
3740
+ FROM JSON_EACH($valSine)
3741
+ )
3742
+ WHERE key = 63;
3743
+ `)
3744
+ });
3745
+ valActual = valActual.map(function (elem) {
3746
+ return [
3747
+ elem.lee_null_at_2,
3748
+ elem.lee_ok_at_3,
3749
+ elem.see_null_at_5,
3750
+ elem.see_ok_at_6
3751
+ ];
3752
+ });
3753
+ assertJsonEqual(valActual, [[1, 1, 1, 1]]);
3754
+ }()),
3755
+ // test win_sinefit2-empty-frame handling-behavior
3756
+ (async function () {
3757
+ // WIN_SINEFIT_N = 23 doubles = 184 bytes per column
3758
+ const nhead = 23 * 8;
3759
+ // Frame "5 PRECEDING AND 3 PRECEDING" is empty for rows 1-3, so
3760
+ // sqlite calls xValue before the first xStep. Regression-test that
3761
+ // xValue does not allocate an aggregate-context with nhead=0, which
3762
+ // would pin nhead=0 for the life of the aggregate and alias
3763
+ // doublewinHead() onto doublewinBody(). ncol=2 additionally
3764
+ // overflows the 304-byte nhead=0 allocation, needing 2*184+48 = 416
3765
+ // bytes of head.
3766
+ assertJsonEqual(
3767
+ noop(
3768
+ await dbExecAsync({
3769
+ db,
3770
+ sql: (`
3771
+ CREATE TABLE testWinSinefit2Emptyframe AS
3772
+ SELECT 1 AS xx, 1 AS yy
3773
+ --
3774
+ UNION ALL VALUES
3775
+ (2, 2),
3776
+ (3, 3),
3777
+ (4, 4),
3778
+ (5, 5),
3779
+ (6, 6),
3780
+ (7, 7),
3781
+ (8, 8);
3782
+
3783
+ -- empty-window-frame
3784
+ SELECT
3785
+ LENGTH(WIN_SINEFIT2(0, NULL, xx, yy) OVER (
3786
+ ORDER BY xx
3787
+ ROWS BETWEEN 5 PRECEDING AND 3 PRECEDING
3788
+ )) AS nhead
3789
+ FROM testWinSinefit2Emptyframe;
3790
+
3791
+ -- empty-window-frame multi-column
3792
+ SELECT
3793
+ LENGTH(WIN_SINEFIT2(0, NULL, xx, yy, xx, yy * 2) OVER (
3794
+ ORDER BY xx
3795
+ ROWS BETWEEN 5 PRECEDING AND 3 PRECEDING
3796
+ )) AS nhead
3797
+ FROM testWinSinefit2Emptyframe;
3798
+ -- non-empty-window-frame control
3799
+ SELECT
3800
+ LENGTH(WIN_SINEFIT2(0, NULL, xx, yy) OVER (
3801
+ ORDER BY xx
3802
+ ROWS BETWEEN 5 PRECEDING AND CURRENT ROW
3803
+ )) AS nhead
3804
+ FROM testWinSinefit2Emptyframe;
3805
+
3806
+ -- sinefit-object is well-formed
3807
+ -- row 8 frame = rows 3-5, so nnn = 3
3808
+ WITH tmp1 AS (
3809
+ SELECT
3810
+ xx,
3811
+ win_sinefit2(0, NULL, xx, yy, xx, yy * 2) OVER (
3812
+ ORDER BY xx
3813
+ ROWS BETWEEN 5 PRECEDING AND 3 PRECEDING
3814
+ ) AS wsf
3815
+ FROM testWinSinefit2Emptyframe
3816
+ )
3817
+ SELECT
3818
+ SINEFIT_EXTRACT(wsf, 0, 'nnn', 0) AS nnn0,
3819
+ SINEFIT_EXTRACT(wsf, 1, 'nnn', 0) AS nnn1,
3820
+ SINEFIT_EXTRACT(wsf, 0, 'lbb', 0) AS lbb0,
3821
+ SINEFIT_EXTRACT(wsf, 1, 'lbb', 0) AS lbb1
3822
+ FROM tmp1
3823
+ WHERE xx = 8;
3824
+ -- empty-table xFinal
3825
+ SELECT LENGTH(WIN_SINEFIT2(0, NULL, xx, yy)) AS nhead
3826
+ FROM testWinSinefit2Emptyframe
3827
+ WHERE 0;
3828
+ `)
3829
+ })
3830
+ ),
3831
+ [
3832
+ [
3833
+ {nhead: 0},
3834
+ {nhead: 0},
3835
+ {nhead: 0},
3836
+ {nhead},
3837
+ {nhead},
3838
+ {nhead},
3839
+ {nhead},
3840
+ {nhead}
3841
+ ],
3842
+ [
3843
+ {nhead: 0},
3844
+ {nhead: 0},
3845
+ {nhead: 0},
3846
+ {nhead: 2 * nhead},
3847
+ {nhead: 2 * nhead},
3848
+ {nhead: 2 * nhead},
3849
+ {nhead: 2 * nhead},
3850
+ {nhead: 2 * nhead}
3851
+ ],
3852
+ [
3853
+ {nhead},
3854
+ {nhead},
3855
+ {nhead},
3856
+ {nhead},
3857
+ {nhead},
3858
+ {nhead},
3859
+ {nhead},
3860
+ {nhead}
3861
+ ],
3862
+ [
3863
+ {lbb0: 1, lbb1: 2, nnn0: 3, nnn1: 3}
3864
+ ],
3865
+ [
3866
+ {nhead: 0}
3867
+ ]
3868
+ ]
3869
+ );
3870
+ }()),
3871
+ // test sinefit_refitlast malformed-blob handling-behavior
3872
+ (async function () {
3873
+ // WinSinefit field-offsets, in bytes
3874
+ let offsetNnn = 5 * 8;
3875
+ let offsetWbb = 16 * 8;
3876
+ function blobMalformed(nnn, wbb) {
3877
+ // ncol=1 header = WIN_SINEFIT_N * 8 = 184 bytes
3878
+ let buf = new ArrayBuffer(184);
3879
+ let dv = new DataView(buf);
3880
+ dv.setFloat64(offsetNnn, nnn, true);
3881
+ dv.setFloat64(offsetWbb, wbb, true);
3882
+ return new Uint8Array(buf);
3883
+ }
3884
+ // test malformed-nnn handling-behavior
3885
+ await Promise.all([
3886
+ 0 / 0, // nan
3887
+ 1 / 0, // inf
3888
+ -1 / 0, // -inf
3889
+ 1e300, // overflows (int)
3890
+ -1, // negative
3891
+ 0, // empty
3892
+ 1.5 // non-integral
3893
+ ].map(function (nnn) {
3894
+ return assertErrorThrownAsync(function () {
3895
+ return dbExecAsync({
3896
+ bindList: [blobMalformed(nnn, 0)],
3897
+ db,
3898
+ sql: "SELECT sinefit_refitlast(?1, 0, 0)"
3899
+ });
3900
+ }, "sinefit_refitlast");
3901
+ }));
3902
+ // test malformed-wbb handling-behavior
3903
+ // nnn=1 implies nbody = 3, so any wbb but 0 is invalid.
3904
+ await Promise.all([
3905
+ 0 / 0, 1 / 0, 1e300, -1, 1, 2, 3, 1.5
3906
+ ].map(function (wbb) {
3907
+ return assertErrorThrownAsync(function () {
3908
+ return dbExecAsync({
3909
+ bindList: [blobMalformed(1, wbb)],
3910
+ db,
3911
+ sql: "SELECT sinefit_refitlast(?1, 0, 0)"
3912
+ });
3913
+ }, "sinefit_refitlast");
3914
+ }));
3915
+ // test truncated-blob handling-behavior
3916
+ await assertErrorThrownAsync(function () {
3917
+ return dbExecAsync({
3918
+ bindList: [new Uint8Array(100)],
3919
+ db,
3920
+ sql: "SELECT sinefit_refitlast(?1, 0, 0)"
3921
+ });
3922
+ }, "sinefit_refitlast");
3923
+ // test wrong-argc handling-behavior
3924
+ await assertErrorThrownAsync(function () {
3925
+ return dbExecAsync({
3926
+ bindList: [blobMalformed(1, 0)],
3927
+ db,
3928
+ sql: "SELECT sinefit_refitlast(?1, 0)"
3929
+ });
3930
+ }, "sinefit_refitlast");
3931
+ }()),
3932
+ // test sinefit_extract non-blob 1st-argument handling-behavior
3933
+ (async function () {
3934
+ await Promise.all([
3935
+ "'hello'",
3936
+ "123",
3937
+ "1.5",
3938
+ "NULL",
3939
+ "zeroblob(0)"
3940
+ ].map(function (arg) {
3941
+ return assertErrorThrownAsync(function () {
3942
+ return dbExecAsync({
3943
+ db,
3944
+ sql: `SELECT sinefit_extract(${arg}, 0, 'nnn', 0)`
3945
+ });
3946
+ }, "sinefit_extract");
3947
+ }));
3948
+ }()),
3949
+ // test win_sinefit2-aggregate-normal handling-behavior
3950
+ (async function () {
3951
+ // test non-blob 1st-argument handling-behavior
3952
+ await Promise.all([
3953
+ "'hello'",
3954
+ "123",
3955
+ "1.5",
3956
+ "NULL",
3957
+ "zeroblob(0)"
3958
+ ].map(function (arg) {
3959
+ return assertErrorThrownAsync(function () {
3960
+ return dbExecAsync({
3961
+ db,
3962
+ sql: `SELECT sinefit_extract(${arg}, 0, 'nnn', 0)`
3963
+ });
3964
+ }, "sinefit_extract");
3965
+ }));
3966
+ }()),
3468
3967
  // test win_sinefit2-aggregate-normal handling-behavior
3469
3968
  (async function () {
3470
3969
  let valActual;
@@ -3494,7 +3993,7 @@ SELECT
3494
3993
  "gyy": 0.19611614,
3495
3994
  "laa": 0.77941176,
3496
3995
  "lbb": 0.84558824,
3497
- "lee": 1.40010504,
3996
+ "lee": 1.56536502,
3498
3997
  "lxy": 0.81541829,
3499
3998
  "lyy": 2.47058824,
3500
3999
  "mee": 2.54950976,
@@ -3520,7 +4019,7 @@ SELECT
3520
4019
  "gyy": -1.02062073,
3521
4020
  "laa": -0.82025678,
3522
4021
  "lbb": 0.14621969,
3523
- "lee": 2.23885734,
4022
+ "lee": 2.74202904,
3524
4023
  "lxy": 0.865665,
3525
4024
  "lyy": 6.63694722,
3526
4025
  "mee": 4.89897949,
@@ -3566,7 +4065,7 @@ SELECT
3566
4065
  "id2": id3,
3567
4066
  "laa": 5.25,
3568
4067
  "lbb": -0.275,
3569
- "lee": 2.49624718,
4068
+ "lee": 2.88241797,
3570
4069
  "lxy": -0.23918696,
3571
4070
  "lyy": 2.5,
3572
4071
  "mee": 2.74837614,
@@ -3586,7 +4085,7 @@ SELECT
3586
4085
  "id2": id4,
3587
4086
  "laa": 7.25,
3588
4087
  "lbb": -0.575,
3589
- "lee": 1.95735791,
4088
+ "lee": 2.26016224,
3590
4089
  "lxy": -0.5490214,
3591
4090
  "lyy": 6.1,
3592
4091
  "mee": 2.50356888,
@@ -3918,7 +4417,7 @@ SELECT
3918
4417
  FROM __sinefit_csv
3919
4418
  JOIN (
3920
4419
  SELECT
3921
- MEDIAN2(rr) AS rr_avg,
4420
+ MEDIAN(rr) AS rr_avg,
3922
4421
  STDEV(rr) AS rr_err
3923
4422
  FROM __sinefit_csv
3924
4423
  )