SQLite

Check-in [898bfa1a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:When translating arguments of aggregate functions into references to expression indexes, make sure to only translate them for the current aggregate when there are nested aggregates. Forum post 409ebc7368.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 898bfa1afd8260eaaf2aa6db94e74d99ebf4e8a6dc02cf21d20cd981393609a5
User & Date: drh 2023-04-03 23:49:00
Original Comment: When translating arguments of aggregate functions into references to expression indexes, make sure to only translate them for the current aggregate when there are nested aggregates. [forum/forumpost/409ebc7368|Forum post 409ebc7368].
Context
2023-04-04
08:49
Omit shell call to sqlite3_dbdata_init() when it is omitted. (check-in: 0421cc03 user: larrybr tags: trunk)
2023-04-03
23:55
When translating arguments of aggregate functions into references to expression indexes, make sure to only translate them for the current aggregate when there are nested aggregates. (check-in: 7ea98aba user: drh tags: branch-3.41)
23:49
When translating arguments of aggregate functions into references to expression indexes, make sure to only translate them for the current aggregate when there are nested aggregates. Forum post 409ebc7368. (check-in: 898bfa1a user: drh tags: trunk)
20:11
Improved diagnostic output from PRAGMA vdbe_addoptrace. (check-in: 050958c1 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/expr.c.
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
  ){
    AggInfo *pAggInfo = pExpr->pAggInfo;
    int iAgg = pExpr->iAgg;
    Parse *pParse = pWalker->pParse;
    sqlite3 *db = pParse->db;
    assert( iAgg>=0 );
    if( pExpr->op!=TK_AGG_FUNCTION ){
      if( iAgg<pAggInfo->nColumn
       && pAggInfo->aCol[iAgg].pCExpr==pExpr
      ){
        pExpr = sqlite3ExprDup(db, pExpr, 0);
        if( pExpr ){
          pAggInfo->aCol[iAgg].pCExpr = pExpr;
          sqlite3ExprDeferredDelete(pParse, pExpr);
        }







|







6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
  ){
    AggInfo *pAggInfo = pExpr->pAggInfo;
    int iAgg = pExpr->iAgg;
    Parse *pParse = pWalker->pParse;
    sqlite3 *db = pParse->db;
    assert( iAgg>=0 );
    if( pExpr->op!=TK_AGG_FUNCTION ){
      if( ALWAYS(iAgg<pAggInfo->nColumn)
       && pAggInfo->aCol[iAgg].pCExpr==pExpr
      ){
        pExpr = sqlite3ExprDup(db, pExpr, 0);
        if( pExpr ){
          pAggInfo->aCol[iAgg].pCExpr = pExpr;
          sqlite3ExprDeferredDelete(pParse, pExpr);
        }
6437
6438
6439
6440
6441
6442
6443

6444
6445
6446
6447
6448
6449
6450
6451
6452
6453




6454
6455
6456
6457
6458
6459
6460
6461

  assert( pNC->ncFlags & NC_UAggInfo );
  assert( pAggInfo->iFirstReg==0 );
  switch( pExpr->op ){
    default: {
      IndexedExpr *pIEpr;
      Expr tmp;

      assert( pParse->iSelfTab==0 );
      if( (pNC->ncFlags & NC_InAggFunc)==0 ) break;
      if( pParse->pIdxEpr==0 ) break;
      for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){
        int iDataCur = pIEpr->iDataCur;
        if( iDataCur<0 ) continue;
        if( sqlite3ExprCompare(0, pExpr, pIEpr->pExpr, iDataCur)==0 ) break;
      }
      if( pIEpr==0 ) break;
      if( NEVER(!ExprUseYTab(pExpr)) ) break;




      if( pExpr->pAggInfo!=0 ) break; /* Already resolved by outer context */
      if( pParse->nErr ){ return WRC_Abort; }

      /* If we reach this point, it means that expression pExpr can be
      ** translated into a reference to an index column as described by
      ** pIEpr.
      */
      memset(&tmp, 0, sizeof(tmp));







>










>
>
>
>
|







6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
6462
6463
6464
6465
6466

  assert( pNC->ncFlags & NC_UAggInfo );
  assert( pAggInfo->iFirstReg==0 );
  switch( pExpr->op ){
    default: {
      IndexedExpr *pIEpr;
      Expr tmp;
      int i;
      assert( pParse->iSelfTab==0 );
      if( (pNC->ncFlags & NC_InAggFunc)==0 ) break;
      if( pParse->pIdxEpr==0 ) break;
      for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){
        int iDataCur = pIEpr->iDataCur;
        if( iDataCur<0 ) continue;
        if( sqlite3ExprCompare(0, pExpr, pIEpr->pExpr, iDataCur)==0 ) break;
      }
      if( pIEpr==0 ) break;
      if( NEVER(!ExprUseYTab(pExpr)) ) break;
      for(i=0; i<pSrcList->nSrc; i++){
         if( pSrcList->a[0].iCursor==pIEpr->iDataCur ) break;
      }
      if( i>=pSrcList->nSrc ) break;
      if( NEVER(pExpr->pAggInfo!=0) ) break; /* Resolved by outer context */
      if( pParse->nErr ){ return WRC_Abort; }

      /* If we reach this point, it means that expression pExpr can be
      ** translated into a reference to an index column as described by
      ** pIEpr.
      */
      memset(&tmp, 0, sizeof(tmp));
Changes to src/select.c.
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
  struct AggInfo_col *pCol;
  UNUSED_PARAMETER(pWalker);
  if( pExpr->pAggInfo==0 ) return WRC_Continue;
  if( pExpr->op==TK_AGG_COLUMN ) return WRC_Continue;
  if( pExpr->op==TK_AGG_FUNCTION ) return WRC_Continue;
  if( pExpr->op==TK_IF_NULL_ROW ) return WRC_Continue;
  pAggInfo = pExpr->pAggInfo;
  if( pExpr->iAgg>=pAggInfo->nColumn ) return WRC_Continue;
  assert( pExpr->iAgg>=0 );
  pCol = &pAggInfo->aCol[pExpr->iAgg];
  pExpr->op = TK_AGG_COLUMN;
  pExpr->iTable = pCol->iTable;
  pExpr->iColumn = pCol->iColumn;
  ExprClearProperty(pExpr, EP_Skip|EP_Collate);
  return WRC_Prune;







|







6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
  struct AggInfo_col *pCol;
  UNUSED_PARAMETER(pWalker);
  if( pExpr->pAggInfo==0 ) return WRC_Continue;
  if( pExpr->op==TK_AGG_COLUMN ) return WRC_Continue;
  if( pExpr->op==TK_AGG_FUNCTION ) return WRC_Continue;
  if( pExpr->op==TK_IF_NULL_ROW ) return WRC_Continue;
  pAggInfo = pExpr->pAggInfo;
  if( NEVER(pExpr->iAgg>=pAggInfo->nColumn) ) return WRC_Continue;
  assert( pExpr->iAgg>=0 );
  pCol = &pAggInfo->aCol[pExpr->iAgg];
  pExpr->op = TK_AGG_COLUMN;
  pExpr->iTable = pCol->iTable;
  pExpr->iColumn = pCol->iColumn;
  ExprClearProperty(pExpr, EP_Skip|EP_Collate);
  return WRC_Prune;
Changes to test/indexexpr2.test.
405
406
407
408
409
410
411















412
413
  CREATE TABLE t2(a TEXT);
  INSERT INTO t2 VALUES('alice'),('bob'),('cindy'),('david');
  CREATE INDEX t2x ON t2 (+a COLLATE NOCASE);
  SELECT count(+a COLLATE NOCASE IN (SELECT 1)) AS x
    FROM t2
   GROUP BY SUBSTR(0,0);
} 4
















finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
  CREATE TABLE t2(a TEXT);
  INSERT INTO t2 VALUES('alice'),('bob'),('cindy'),('david');
  CREATE INDEX t2x ON t2 (+a COLLATE NOCASE);
  SELECT count(+a COLLATE NOCASE IN (SELECT 1)) AS x
    FROM t2
   GROUP BY SUBSTR(0,0);
} 4

# 2023-04-03 https://sqlite.org/forum/forumpost/409ebc7368
# When a generated column appears in both an outer and an inner loop
# (that is to say, the same table is used in both loops) and the
# generated column is indexed and it is used inside an aggregate function,
# make sure that the terms resolve to the correct aggregate.
#
do_execsql_test 11.0 {
  CREATE TABLE t3 (a INT, b AS (-a));
  CREATE INDEX t3x ON t3(b, a);
  INSERT INTO t3(a) VALUES(44);
  SELECT * FROM t3 AS a0
   WHERE (SELECT sum(-a0.a=b) FROM t3 GROUP BY b)
   GROUP BY b;
} {44 -44}

finish_test