SQLite

Check-in [e84ff57b62]
Login

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

Overview
Comment:Avoid factoring single-instruction constants that end up getting replaced by an SCopy instruction. (CVS 4952)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e84ff57b6217afa84d60547dcc3a270b5e116818
User & Date: drh 2008-04-01 18:04:11.000
Context
2008-04-02
04:23
Set flags = MEM_Null on allocation failure in sqlite3VdbeMemGrow (CVS 4953) (check-in: 846f9739d3 user: mlcreech tags: trunk)
2008-04-01
18:04
Avoid factoring single-instruction constants that end up getting replaced by an SCopy instruction. (CVS 4952) (check-in: e84ff57b62 user: drh tags: trunk)
15:06
Add the testcase() macro. Additional CSE test coverage. (CVS 4951) (check-in: 492490f9c8 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/expr.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.364 2008/04/01 15:06:34 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Return the 'affinity' of the expression pExpr if any.
**







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.365 2008/04/01 18:04:11 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Return the 'affinity' of the expression pExpr if any.
**
2678
2679
2680
2681
2682
2683
2684



























































2685

2686
2687
2688
2689
2690
2691

2692
2693


















2694
2695
2696
2697
2698
2699
2700
2701
    pExpr->iColumn = pExpr->op;
    pExpr->op = TK_REGISTER;
  }
  return inReg;
}

/*



























































** If pExpr is a constant expression, then evaluate the expression

** into a register and convert the expression into a TK_REGISTER
** expression.
*/
static int evalConstExpr(void *pArg, Expr *pExpr){
  Parse *pParse = (Parse*)pArg;
  if( pExpr->op==TK_REGISTER ){

    return 1;
  }


















  if( sqlite3ExprIsConstantNotJoin(pExpr) ){
    int r1 = ++pParse->nMem;
    int r2;
    r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
    if( r1!=r2 ) sqlite3ReleaseTempReg(pParse, r1);
    pExpr->iColumn = pExpr->op;
    pExpr->op = TK_REGISTER;
    pExpr->iTable = r2;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>





|
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|







2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
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
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
    pExpr->iColumn = pExpr->op;
    pExpr->op = TK_REGISTER;
  }
  return inReg;
}

/*
** Return TRUE if pExpr is an constant expression that is appropriate
** for factoring out of a loop.  Appropriate expressions are:
**
**    *  Any expression that evaluates to two or more opcodes.
**
**    *  Any OP_Integer, OP_Real, OP_String, OP_Blob, OP_Null, 
**       or OP_Variable that does not need to be placed in a 
**       specific register.
**
** There is no point in factoring out single-instruction constant
** expressions that need to be placed in a particular register.  
** We could factor them out, but then we would end up adding an
** OP_SCopy instruction to move the value into the correct register
** later.  We might as well just use the original instruction and
** avoid the OP_SCopy.
*/
static int isAppropriateForFactoring(Expr *p){
  if( !sqlite3ExprIsConstantNotJoin(p) ){
    return 0;  /* Only constant expressions are appropriate for factoring */
  }
  if( (p->flags & EP_FixedDest)==0 ){
    return 1;  /* Any constant without a fixed destination is appropriate */
  }
  while( p->op==TK_UPLUS ) p = p->pLeft;
  switch( p->op ){
#ifndef SQLITE_OMIT_BLOB_LITERAL
    case TK_BLOB:
#endif
    case TK_VARIABLE:
    case TK_INTEGER:
    case TK_FLOAT:
    case TK_NULL:
    case TK_STRING: {
      testcase( p->op==TK_BLOB );
      testcase( p->op==TK_VARIABLE );
      testcase( p->op==TK_INTEGER );
      testcase( p->op==TK_FLOAT );
      testcase( p->op==TK_NULL );
      testcase( p->op==TK_STRING );
      /* Single-instruction constants with a fixed destination are
      ** better done in-line.  If we factor them, they will just end
      ** up generating an OP_SCopy to move the value to the destination
      ** register. */
      return 0;
    }
    case TK_UMINUS: {
       if( p->pLeft->op==TK_FLOAT || p->pLeft->op==TK_INTEGER ){
         return 0;
       }
       break;
    }
    default: {
      break;
    }
  }
  return 1;
}

/*
** If pExpr is a constant expression that is appropriate for
** factoring out of a loop, then evaluate the expression
** into a register and convert the expression into a TK_REGISTER
** expression.
*/
static int evalConstExpr(void *pArg, Expr *pExpr){
  Parse *pParse = (Parse*)pArg;
  switch( pExpr->op ){
    case TK_REGISTER: {
      return 1;
    }
    case TK_FUNCTION:
    case TK_AGG_FUNCTION:
    case TK_CONST_FUNC: {
      /* The arguments to a function have a fixed destination.
      ** Mark them this way to avoid generated unneeded OP_SCopy
      ** instructions. 
      */
      ExprList *pList = pExpr->pList;
      if( pList ){
        int i = pList->nExpr;
        struct ExprList_item *pItem = pList->a;
        for(; i>0; i--, pItem++){
          if( pItem->pExpr ) pItem->pExpr->flags |= EP_FixedDest;
        }
      }
      break;
    }
  }
  if( isAppropriateForFactoring(pExpr) ){
    int r1 = ++pParse->nMem;
    int r2;
    r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
    if( r1!=r2 ) sqlite3ReleaseTempReg(pParse, r1);
    pExpr->iColumn = pExpr->op;
    pExpr->op = TK_REGISTER;
    pExpr->iTable = r2;
Changes to src/sqliteInt.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.687 2008/04/01 15:06:34 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if it was run
** (otherwise we get an empty default).













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.688 2008/04/01 18:04:11 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if it was run
** (otherwise we get an empty default).
1150
1151
1152
1153
1154
1155
1156

1157
1158
1159
1160
1161
1162
1163
#define EP_Error      0x0008  /* Expression contains one or more errors */
#define EP_Distinct   0x0010  /* Aggregate function with DISTINCT keyword */
#define EP_VarSelect  0x0020  /* pSelect is correlated, not constant */
#define EP_Dequoted   0x0040  /* True if the string has been dequoted */
#define EP_InfixFunc  0x0080  /* True for an infix function: LIKE, GLOB, etc */
#define EP_ExpCollate 0x0100  /* Collating sequence specified explicitly */
#define EP_AnyAff     0x0200  /* Can take a cached column of any affinity */


/*
** These macros can be used to test, set, or clear bits in the 
** Expr.flags field.
*/
#define ExprHasProperty(E,P)     (((E)->flags&(P))==(P))
#define ExprHasAnyProperty(E,P)  (((E)->flags&(P))!=0)







>







1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
#define EP_Error      0x0008  /* Expression contains one or more errors */
#define EP_Distinct   0x0010  /* Aggregate function with DISTINCT keyword */
#define EP_VarSelect  0x0020  /* pSelect is correlated, not constant */
#define EP_Dequoted   0x0040  /* True if the string has been dequoted */
#define EP_InfixFunc  0x0080  /* True for an infix function: LIKE, GLOB, etc */
#define EP_ExpCollate 0x0100  /* Collating sequence specified explicitly */
#define EP_AnyAff     0x0200  /* Can take a cached column of any affinity */
#define EP_FixedDest  0x0400  /* Result needed in a specific register */

/*
** These macros can be used to test, set, or clear bits in the 
** Expr.flags field.
*/
#define ExprHasProperty(E,P)     (((E)->flags&(P))==(P))
#define ExprHasAnyProperty(E,P)  (((E)->flags&(P))!=0)
Changes to test/cse.test.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
#***********************************************************************
#
# Test cases designed to exercise and verify the logic for
# factoring constant expressions out of loops and for
# common subexpression eliminations.
#
# $Id: cse.test,v 1.4 2008/04/01 15:06:34 drh Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test cse-1.1 {
  execsql {







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
#***********************************************************************
#
# Test cases designed to exercise and verify the logic for
# factoring constant expressions out of loops and for
# common subexpression eliminations.
#
# $Id: cse.test,v 1.5 2008/04/01 18:04:11 drh Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test cse-1.1 {
  execsql {
45
46
47
48
49
50
51
52
53
54
55
56




















57
58
59
60
61
62
63
  }
} {11 11 12 22 21 22}
do_test cse-1.5 {
  execsql {
    SELECT CASE a WHEN 1 THEN b WHEN 2 THEN c ELSE d END, b, c, d FROM t1
  }
} {11 11 12 13 22 21 22 23}
do_test cse-1.6 {
  execsql {
    SELECT CASE b WHEN 11 THEN -b WHEN 21 THEN -c ELSE -d END, b, c, d FROM t1
  }
} {-11 11 12 13 -22 21 22 23}




















do_test cse-1.7 {
  execsql {
    SELECT a, -a, ~a, NOT a, NOT NOT a, a-a, a+a, a*a, a/a, a FROM t1
  }
} {1 -1 -2 0 1 0 2 1 1 1 2 -2 -3 0 1 0 4 4 1 2}
do_test cse-1.8 {
  execsql {







|




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







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
  }
} {11 11 12 22 21 22}
do_test cse-1.5 {
  execsql {
    SELECT CASE a WHEN 1 THEN b WHEN 2 THEN c ELSE d END, b, c, d FROM t1
  }
} {11 11 12 13 22 21 22 23}
do_test cse-1.6.1 {
  execsql {
    SELECT CASE b WHEN 11 THEN -b WHEN 21 THEN -c ELSE -d END, b, c, d FROM t1
  }
} {-11 11 12 13 -22 21 22 23}
do_test cse-1.6.2 {
  execsql {
    SELECT CASE b+1 WHEN c THEN d WHEN e THEN f ELSE 999 END, b, c, d FROM t1
  }
} {13 11 12 13 23 21 22 23}
do_test cse-1.6.3 {
  execsql {
    SELECT CASE WHEN b THEN d WHEN e THEN f ELSE 999 END, b, c, d FROM t1
  }
} {13 11 12 13 23 21 22 23}
do_test cse-1.6.4 {
  execsql {
    SELECT b, c, d, CASE WHEN b THEN d WHEN e THEN f ELSE 999 END FROM t1
  }
} {11 12 13 13 21 22 23 23}
do_test cse-1.6.5 {
  execsql {
    SELECT b, c, d, CASE WHEN 0 THEN d WHEN e THEN f ELSE 999 END FROM t1
  }
} {11 12 13 15 21 22 23 25}
do_test cse-1.7 {
  execsql {
    SELECT a, -a, ~a, NOT a, NOT NOT a, a-a, a+a, a*a, a/a, a FROM t1
  }
} {1 -1 -2 0 1 0 2 1 1 1 2 -2 -3 0 1 0 4 4 1 2}
do_test cse-1.8 {
  execsql {
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  execsql {
    SELECT coalesce(b,c,d,e), a, b, c, d, e FROM t1 WHERE a=2
    UNION ALL
    SELECT coalesce(e,d,c,b), e, d, c, b, a FROM t1 WHERE a=1
  }
} {21 2 21 22 23 24 14 14 13 12 11 1}
do_test cse-1.13 {
  explain {
     SELECT upper(b), typeof(b), b FROM t1
  }
  execsql {
     SELECT upper(b), typeof(b), b FROM t1
  }
} {11 integer 11 21 integer 21}
do_test cse-1.14 {
  explain {
     SELECT b, typeof(b), upper(b), typeof(b), b FROM t1
  }
  execsql {
     SELECT b, typeof(b), upper(b), typeof(b), b FROM t1
  }
} {11 integer 11 integer 11 21 integer 21 integer 21}

# Overflow the column cache.  Create queries involving more and more
# columns until the cache overflows.  Verify correct operation throughout.







<
<
<





<
<
<







105
106
107
108
109
110
111



112
113
114
115
116



117
118
119
120
121
122
123
  execsql {
    SELECT coalesce(b,c,d,e), a, b, c, d, e FROM t1 WHERE a=2
    UNION ALL
    SELECT coalesce(e,d,c,b), e, d, c, b, a FROM t1 WHERE a=1
  }
} {21 2 21 22 23 24 14 14 13 12 11 1}
do_test cse-1.13 {



  execsql {
     SELECT upper(b), typeof(b), b FROM t1
  }
} {11 integer 11 21 integer 21}
do_test cse-1.14 {



  execsql {
     SELECT b, typeof(b), upper(b), typeof(b), b FROM t1
  }
} {11 integer 11 integer 11 21 integer 21 integer 21}

# Overflow the column cache.  Create queries involving more and more
# columns until the cache overflows.  Verify correct operation throughout.