/ Check-in [f9dddd00]
Login

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

Overview
Comment:In the expression passed to sqlite3BtreeCursorHint() for the inner loops of joins, replace any TK_COLUMN references to columns in the outer loops with TK_REGISTER expressions (Expr.iTable indicates the specific register containing the value). There are no automated tests for this yet.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | cursor-hints
Files: files | file ages | folders
SHA1: f9dddd008c6ef7940a1d66363fbb456cff7207c1
User & Date: dan 2014-07-14 19:04:29
Original Comment: In the expression passed to sqlite3BtreeCursorHint() for the inner loops of joins, replace any TK_COLUMN references to columns in the outer loops with TK_REGISTER expressions (Expr.iTable indicates the specific register containing the value).
Context
2014-07-15
11:59
Add simple tests for new sqlite3BtreeCursorHint() functionality. check-in: 1efa6ed5 user: dan tags: cursor-hints
2014-07-14
19:04
In the expression passed to sqlite3BtreeCursorHint() for the inner loops of joins, replace any TK_COLUMN references to columns in the outer loops with TK_REGISTER expressions (Expr.iTable indicates the specific register containing the value). There are no automated tests for this yet. check-in: f9dddd00 user: dan tags: cursor-hints
2013-12-07
23:35
Do not allow cursor hints to use expressions containing subqueries. This change fixes the problem seen in the previous check-in. check-in: bfefc575 user: drh tags: cursor-hints
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/where.c.

2712
2713
2714
2715
2716
2717
2718



































2719
2720
2721
2722
2723
2724
2725
....
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745

2746
2747
2748
2749
2750
2751
2752
2753







2754
2755
2756
2757
2758
2759
2760
2761
2762
  }
}
#else
# define explainOneScan(u,v,w,x,y,z)
#endif /* SQLITE_OMIT_EXPLAIN */

#ifdef SQLITE_ENABLE_CURSOR_HINTS



































/*
** Insert an OP_CursorHint instruction if it is appropriate to do so.
*/
static void codeCursorHint(
  WhereInfo *pWInfo,
  int iLevel
){
................................................................................
  WhereLoop *pWLoop;
  int i, j;

  if( OptimizationDisabled(db, SQLITE_CursorHints) ) return;
  pLevel = &pWInfo->a[iLevel];
  pWLoop = pLevel->pWLoop;
  iCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor;
  msk = ~getMask(&pWInfo->sMaskSet, iCur);
  pWC = &pWInfo->sWC;
  for(i=0; i<pWC->nTerm; i++){
    pTerm = &pWC->a[i];

    if( pTerm->prereqAll & msk ) continue;
    if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
    if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue;
    for(j=0; j<pWLoop->nLTerm && pWLoop->aLTerm[j]!=pTerm; j++){}
    if( j<pWLoop->nLTerm ) continue;
    pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0));
  } 
  if( pExpr!=0 ){







    sqlite3VdbeAddOp4(v, OP_CursorHint, pLevel->iTabCur, iCur, 0,
                      (const char*)pExpr, P4_EXPR);
  }
}
#else
# define codeCursorHint(A,B)  /* No-op */
#endif /* SQLITE_ENABLE_CURSOR_HINTS */









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







 







<



>
|





|

>
>
>
>
>
>
>
|
<







2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
....
2770
2771
2772
2773
2774
2775
2776

2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796

2797
2798
2799
2800
2801
2802
2803
  }
}
#else
# define explainOneScan(u,v,w,x,y,z)
#endif /* SQLITE_OMIT_EXPLAIN */

#ifdef SQLITE_ENABLE_CURSOR_HINTS

/*
** This function is called on every node of an expression tree used as an
** argument to the OP_CursorHint instruction. If the node is a TK_COLUMN
** that accesses any cursor other than (pWalker->u.i), do the following:
**
**   1) allocate a register and code an OP_Column instruction to read 
**      the specified column into the new register, and
**
**   2) transform the expression node to a TK_REGISTER node that reads 
**      from the newly populated register.
*/
static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
  int rc = WRC_Continue;
  if( pExpr->op==TK_COLUMN && pExpr->iTable!=pWalker->u.i ){
    Vdbe *v = pWalker->pParse->pVdbe;
    int reg = ++pWalker->pParse->nMem;   /* Register for column value */
    sqlite3ExprCodeGetColumnOfTable(
        v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg
    );
    pExpr->op = TK_REGISTER;
    pExpr->iTable = reg;
  }else if( pExpr->op==TK_AGG_FUNCTION ){
    /* An aggregate function in the WHERE clause of a query means this must
    ** be a correlated sub-query, and expression pExpr is an aggregate from
    ** the parent context. Do not walk the function arguments in this case.
    **
    ** todo: It should be possible to replace this node with a TK_REGISTER
    ** expression, as the result of the expression must be stored in a 
    ** register at this point. The same holds for TK_AGG_COLUMN nodes. */
    rc = WRC_Prune;
  }
  return rc;
}

/*
** Insert an OP_CursorHint instruction if it is appropriate to do so.
*/
static void codeCursorHint(
  WhereInfo *pWInfo,
  int iLevel
){
................................................................................
  WhereLoop *pWLoop;
  int i, j;

  if( OptimizationDisabled(db, SQLITE_CursorHints) ) return;
  pLevel = &pWInfo->a[iLevel];
  pWLoop = pLevel->pWLoop;
  iCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor;

  pWC = &pWInfo->sWC;
  for(i=0; i<pWC->nTerm; i++){
    pTerm = &pWC->a[i];
    if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
    if( pTerm->prereqAll & pLevel->notReady ) continue;
    if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
    if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue;
    for(j=0; j<pWLoop->nLTerm && pWLoop->aLTerm[j]!=pTerm; j++){}
    if( j<pWLoop->nLTerm ) continue;
    pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0));
  }
  if( pExpr!=0 ){
    const char *a = (const char*)pExpr;
    Walker sWalker;
    memset(&sWalker, 0, sizeof(sWalker));
    sWalker.xExprCallback = codeCursorHintFixExpr;
    sWalker.pParse = pParse;
    sWalker.u.i = pLevel->iTabCur;
    sqlite3WalkExpr(&sWalker, pExpr);
    sqlite3VdbeAddOp4(v, OP_CursorHint, pLevel->iTabCur, iCur, 0, a, P4_EXPR);

  }
}
#else
# define codeCursorHint(A,B)  /* No-op */
#endif /* SQLITE_ENABLE_CURSOR_HINTS */