Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From fdef2a921d451c66 To c43dd23fb00f7e0b
2018-07-07
| ||
20:13 | Fix an LSM problem caused by using the same cursor for equality and range scans. (check-in: f05bead371 user: dan tags: trunk) | |
19:47 | Add ALWAYS() macros on results of sqlite3_aggregate_context() calls in xInverse() implements, since they can never fail. (check-in: fdef2a921d user: drh tags: trunk) | |
19:36 | Add an assert() to help verify that OP_AggInverse is never called on an accumulator that has not previously been processed by OP_AggStep. (check-in: 4213889103 user: drh tags: trunk) | |
2018-07-05
| ||
21:22 | Use separate opcodes, OP_AggValue and OP_AggInverse, for the new callbacks associated with Window Functions, for improved readability of EXPLAIN output. (check-in: fa65380509 user: drh tags: trunk) | |
20:33 | Update the recipe for resetting a database using SQLITE_DBCONFIG_RESET_DATABASE. (check-in: c43dd23fb0 user: dan tags: trunk) | |
20:05 | Get the json_group_array() and json_group_object() SQL functions working as window functions. (check-in: 916cdc83f5 user: drh tags: trunk) | |
Changes to ext/misc/json1.c.
︙ | |||
1844 1845 1846 1847 1848 1849 1850 | 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 | - - - + | sqlite3_value **argv ){ int i; int inStr = 0; char *z; JsonString *pStr; pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); |
︙ |
Changes to src/func.c.
︙ | |||
1517 1518 1519 1520 1521 1522 1523 | 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 | - - - + | static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){ SumCtx *p; int type; assert( argc==1 ); UNUSED_PARAMETER(argc); p = sqlite3_aggregate_context(context, sizeof(*p)); type = sqlite3_value_numeric_type(argv[0]); |
︙ | |||
1603 1604 1605 1606 1607 1608 1609 | 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 | - - + | p = sqlite3_aggregate_context(context, 0); sqlite3_result_int64(context, p ? p->n : 0); } #ifndef SQLITE_OMIT_WINDOWFUNC static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){ CountCtx *p; p = sqlite3_aggregate_context(ctx, sizeof(*p)); |
︙ | |||
1723 1724 1725 1726 1727 1728 1729 | 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 | - - - + | sqlite3_value **argv ){ int n; assert( argc==1 || argc==2 ); StrAccum *pAccum; if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); |
︙ |
Changes to src/parse.y.
︙ | |||
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 | 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 | + - | over_opt(Z) %endif . { if( Y && Y->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X); } A = sqlite3ExprFunction(pParse, Y, &X); sqlite3WindowAttach(pParse, A, Z); if( D==SF_Distinct && A ){ A->flags |= EP_Distinct; } |
︙ | |||
1637 1638 1639 1640 1641 1642 1643 | 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 | - - - - | %type filter_opt {Expr*} %destructor filter_opt {sqlite3ExprDelete(pParse->db, $$);} %type range_or_rows {int} %type frame_bound {struct FrameBound} %destructor frame_bound {sqlite3ExprDelete(pParse->db, $$.pExpr);} |
︙ | |||
1664 1665 1666 1667 1668 1669 1670 | 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 | - + - + - - - + - - - + | part_opt(A) ::= PARTITION BY exprlist(X). { A = X; } part_opt(A) ::= . { A = 0; } frame_opt(A) ::= . { A = sqlite3WindowAlloc(pParse, TK_RANGE, TK_UNBOUNDED, 0, TK_CURRENT, 0); } |
︙ |
Changes to src/select.c.
︙ | |||
5183 5184 5185 5186 5187 5188 5189 | 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 | - + | } if( !pColl ){ pColl = pParse->db->pDfltColl; } if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); } |
︙ |
Changes to src/vdbe.c.
︙ | |||
1151 1152 1153 1154 1155 1156 1157 | 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 | - - - | int cnt; u16 nullFlag; pOut = out2Prerelease(p, pOp); cnt = pOp->p3-pOp->p2; assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; pOut->n = 0; |
︙ | |||
6287 6288 6289 6290 6291 6292 6293 | 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 | - + - - + + - - - - - - - - - - - - + - - + | if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--; VdbeBranchTaken(pIn1->u.i==0, 2); if( pIn1->u.i==0 ) goto jump_to_p2; break; } |
︙ | |||
6350 6351 6352 6353 6354 6355 6356 | 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 | - - - - - + - + - - - - - - - - - - - | pCtx->iOp = (int)(pOp - aOp); pCtx->pVdbe = p; pCtx->skipFlag = 0; pCtx->isError = 0; pCtx->argc = n; pOp->p4type = P4_FUNCCTX; pOp->p4.pCtx = pCtx; |
︙ | |||
6425 6426 6427 6428 6429 6430 6431 | 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 | - + - - + + + - - - - - - - - - - - - - - - - + - | if( rc ) goto abort_due_to_error; } assert( pCtx->pOut->flags==MEM_Null ); assert( pCtx->skipFlag==0 ); break; } |
︙ |
Changes to src/vdbe.h.
︙ | |||
239 240 241 242 243 244 245 246 247 248 249 250 251 252 | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | + | void sqlite3VdbeResolveLabel(Vdbe*, int); #ifdef SQLITE_COVERAGE_TEST int sqlite3VdbeLabelHasBeenResolved(Vdbe*,int); #endif int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG int sqlite3VdbeAssertMayAbort(Vdbe *, int); int sqlite3VdbeAssertAggContext(sqlite3_context*); #endif void sqlite3VdbeResetStepResult(Vdbe*); void sqlite3VdbeRewind(Vdbe*); int sqlite3VdbeReset(Vdbe*); void sqlite3VdbeSetNumCols(Vdbe*,int); int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*)); void sqlite3VdbeCountChanges(Vdbe*); |
︙ |
Changes to src/vdbeapi.c.
︙ | |||
820 821 822 823 824 825 826 827 828 829 830 831 832 833 | 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 | + + + + + + + + + + + + | if( (p->pMem->flags & MEM_Agg)==0 ){ return createAggContext(p, nByte); }else{ return (void*)p->pMem->z; } } /* ** This function is only used within assert() statements to check that the ** aggregate context has already been allocated. i.e.: ** ** assert( sqlite3VdbeAssertAggContext(p) ); */ #ifdef SQLITE_DEBUG int sqlite3VdbeAssertAggContext(sqlite3_context *p){ return ((p->pMem->flags & MEM_Agg)!=0); } #endif /* SQLITE_DEBUG */ /* ** Return the auxiliary data pointer, if any, for the iArg'th argument to ** the user-function defined by pCtx. ** ** The left-most argument is 0. ** ** Undocumented behavior: If iArg is negative then access a cache of |
︙ |
Changes to src/vdbemem.c.
︙ | |||
431 432 433 434 435 436 437 | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | - | assert( pFunc->xValue!=0 ); assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef ); assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) ); memset(&ctx, 0, sizeof(ctx)); memset(&t, 0, sizeof(t)); t.flags = MEM_Null; t.db = pAccum->db; |
︙ |
Changes to src/window.c.
︙ | |||
251 252 253 254 255 256 257 258 | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | + - + | sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; assert( nArg==1 ); assert( sqlite3VdbeAssertAggContext(pCtx) ); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); |
︙ | |||
296 297 298 299 300 301 302 303 | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | + - + | sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ struct CallCount *p; assert( nArg==1 ); assert( sqlite3VdbeAssertAggContext(pCtx) ); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); |
︙ | |||
823 824 825 826 827 828 829 | 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 | - - - - - - - - - - - - - - - - + - - + + - - + - - + - - - - - - - - - - - - - - - + + - - - + - - - - - - - - - - - - - - - - - + - - + + - - - - - - - + + + + + + + - - + - - - - + + + + + - - - + + - - - - - | Window *pNext = p->pNextWin; sqlite3WindowDelete(db, p); p = pNext; } } /* |
︙ | |||
1000 1001 1002 1003 1004 1005 1006 | 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 | - + - | /* ** A "PRECEDING <expr>" (bEnd==0) or "FOLLOWING <expr>" (bEnd==1) has just ** been evaluated and the result left in register reg. This function generates ** VM code to check that the value is a non-negative integer and throws ** an exception if it is not. */ |
︙ | |||
1037 1038 1039 1040 1041 1042 1043 | 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 | - + | ** that do not use the standard function API, generate the required ** inline VM code. ** ** If argument csr is greater than or equal to 0, then argument reg is ** the first register in an array of registers guaranteed to be large ** enough to hold the array of arguments for each function. In this case ** the arguments are extracted from the current row of csr into the |
︙ | |||
1082 1083 1084 1085 1086 1087 1088 | 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 | - - - | assert( !(flags & SQLITE_FUNC_WINDOW_SIZE) ); regArg = reg + pWin->iArgCol; } if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->eStart!=TK_UNBOUNDED ){ |
︙ | |||
1128 1129 1130 1131 1132 1133 1134 | 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 | - - + | } } if( pWin->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl; pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr); sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ); } |
︙ | |||
1161 1162 1163 1164 1165 1166 1167 | 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 | - - - + + + + + + - - + - | sqlite3VdbeAddOp3(v, OP_Column, pWin->csrApp, 0, pWin->regResult); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); if( bFinal ){ sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); } }else if( pWin->regApp ){ }else{ |
︙ | |||
1325 1326 1327 1328 1329 1330 1331 | 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 | - + | ** from the Window.iEphCsr temp table. This routine generates VM code ** similar to: ** ** while( regCtr>0 ){ ** regCtr--; ** windowReturnOneRow() ** if( bInverse ){ |
︙ | |||
1419 1420 1421 1422 1423 1424 1425 | 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 | - + | ** Next(csrEnd) // if EOF skip Aggstep ** Aggstep (csrEnd) ** if( (regEnd--)<=0 ){ ** AggFinal (xValue) ** Gosub addrGosub ** Next(csr) // if EOF goto flush_partition_done ** if( (regStart--)<=0 ){ |
︙ | |||
1447 1448 1449 1450 1451 1452 1453 | 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 | - + | ** Aggstep (csrEnd) ** } ** while( 1 ){ ** AggFinal (xValue) ** Gosub addrGosub ** Next(csr) // if EOF goto flush_partition_done ** if( (regStart--)<=0 ){ |
︙ | |||
1470 1471 1472 1473 1474 1475 1476 | 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 | - + - + - + | ** while( 1 ){ ** regPeer++ ** Gosub addrGosub ** Next(csr) // if EOF goto flush_partition_done ** if( new peer ) break; ** } ** while( (regPeer--)>0 ){ |
︙ | |||
1567 1568 1569 1570 1571 1572 1573 | 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 | - + - + | sqlite3VdbeAddOp2(v, OP_OpenDup, csrStart, pMWin->iEphCsr); sqlite3VdbeAddOp2(v, OP_OpenDup, csrEnd, pMWin->iEphCsr); /* If either regStart or regEnd are not non-negative integers, throw ** an exception. */ if( pMWin->pStart ){ sqlite3ExprCode(pParse, pMWin->pStart, regStart); |
︙ | |||
1734 1735 1736 1737 1738 1739 1740 | 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 | - + | ** ** RANGE BETWEEN CURRENT ROW AND CURRENT ROW ** ** As above, except that each of the for() loops becomes: ** ** for(i=0; i<ctr; i++){ ** Gosub addrGosub |
︙ | |||
1767 1768 1769 1770 1771 1772 1773 | 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 | - + | ** Rewind (csrLead) ** Integer ctr 0 ** foreach row (csrLead){ ** if( new peer ){ ** AggFinal (xValue) ** for(i=0; i<ctr; i++){ ** Gosub addrGosub |
︙ |
Changes to test/window4.tcl.
︙ | |||
327 328 329 330 331 332 333 | 327 328 329 330 331 332 333 334 335 336 | - - - - - - - - - - - - - - - - - - - - | execsql_test 9.4 { SELECT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2 } execsql_test 9.5 { SELECT DISTINCT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2 } |
Changes to test/window4.test.
︙ | |||
1229 1230 1231 1232 1233 1234 1235 | 1229 1230 1231 1232 1233 1234 1235 1236 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - | SELECT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2 } {1 1 1 1 1 1 4 4 4 4 6 6 7 7} do_execsql_test 9.5 { SELECT DISTINCT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2 } {1 1 4 4 6 6 7 7} |
Changes to test/window6.test.
︙ | |||
217 218 219 220 221 222 223 | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | - - + - - + - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | } { 1 1 2 1,2 3 1,2,3 4 2,3,4 5 3,4,5 } do_catchsql_test 9.1 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) SELECT x, group_concat(x) OVER (ORDER BY x RANGE 2 PRECEDING) FROM c; |
Changes to test/windowfault.test.
︙ | |||
125 126 127 128 129 130 131 | 125 126 127 128 129 130 131 132 133 | - - - - - - - - - - | WINDOW win1 AS (ORDER BY a ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING), win2 AS (ORDER BY a) } } -test { faultsim_test_result {0 {5 1 9 5 9 9}} } |