SQLite

Check-in [e5aff09ac6]
Login

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

Overview
Comment:Initial test cases and bug fixes in the CSE logic. (CVS 4946)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e5aff09ac693946dc7ebb2f245b6434995b12155
User & Date: drh 2008-04-01 01:42:41.000
Context
2008-04-01
02:45
Add a configure option for using gcov (makes things easier for versions of GCC that fail to build otherwise) (CVS 4947) (check-in: 7d1e797162 user: mlcreech tags: trunk)
01:42
Initial test cases and bug fixes in the CSE logic. (CVS 4946) (check-in: e5aff09ac6 user: drh tags: trunk)
00:36
Break up the implementation of OP_Move, OP_Copy, and OP_SCopy to reduce the number of branch instructions. (CVS 4945) (check-in: 53e533d3a7 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.359 2008/03/31 23:48:04 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.360 2008/04/01 01:42:41 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Return the 'affinity' of the expression pExpr if any.
**
2011
2012
2013
2014
2015
2016
2017



































2018
2019
2020
2021
2022
2023
2024
  sqlite3VdbeAddOp2(pParse->pVdbe, OP_Move, iFrom, iTo);
  for(i=0; i<pParse->nColCache; i++){
    if( pParse->aColCache[i].iReg==iFrom ){
      pParse->aColCache[i].iReg = iTo;
    }
  }
}




































/*
** Generate code into the current Vdbe to evaluate the given
** expression.  Attempt to store the results in register "target".
** Return the register where results are stored.
**
** With this routine, there is no guaranteed that results will







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







2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
  sqlite3VdbeAddOp2(pParse->pVdbe, OP_Move, iFrom, iTo);
  for(i=0; i<pParse->nColCache; i++){
    if( pParse->aColCache[i].iReg==iFrom ){
      pParse->aColCache[i].iReg = iTo;
    }
  }
}

/*
** Return true if any register in the range iFrom..iTo (inclusive)
** is used as part of the column cache.
*/
static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
  int i;
  for(i=0; i<pParse->nColCache; i++){
    int r = pParse->aColCache[i].iReg;
    if( r>=iFrom && r<=iTo ) return 1;
  }
  return 0;
}

/*
** Theres is a value in register iCurrent.  We ultimately want
** the value to be in register iTarget.  It might be that
** iCurrent and iTarget are the same register.
**
** We are going to modify the value, so we need to make sure it
** is not a cached register.  If iCurrent is a cached register,
** then try to move the value over to iTarget.  If iTarget is a
** cached register, then clear the corresponding cache line.
**
** Return the register that the value ends up in.
*/
int sqlite3ExprWritableRegister(Parse *pParse, int iCurrent, int iTarget){
  assert( pParse->pVdbe!=0 );
  if( !usedAsColumnCache(pParse, iCurrent, iCurrent) ){
    return iCurrent;
  }
  sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, iCurrent, iTarget);
  sqlite3ExprExpireColumnCacheLines(pParse, iTarget, iTarget);
  return iTarget;
}

/*
** Generate code into the current Vdbe to evaluate the given
** expression.  Attempt to store the results in register "target".
** Return the register where results are stored.
**
** With this routine, there is no guaranteed that results will
2197
2198
2199
2200
2201
2202
2203

2204
2205
2206
2207
2208
2209
2210
      break;
    }
    case TK_BITNOT:
    case TK_NOT: {
      assert( TK_BITNOT==OP_BitNot );
      assert( TK_NOT==OP_Not );
      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);

      sqlite3VdbeAddOp1(v, op, inReg);
      break;
    }
    case TK_ISNULL:
    case TK_NOTNULL: {
      int addr;
      assert( TK_ISNULL==OP_IsNull );







>







2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
      break;
    }
    case TK_BITNOT:
    case TK_NOT: {
      assert( TK_BITNOT==OP_BitNot );
      assert( TK_NOT==OP_Not );
      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
      inReg = sqlite3ExprWritableRegister(pParse, inReg, target);
      sqlite3VdbeAddOp1(v, op, inReg);
      break;
    }
    case TK_ISNULL:
    case TK_NOTNULL: {
      int addr;
      assert( TK_ISNULL==OP_IsNull );
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429

2430
2431
2432
2433
2434
2435
2436
      assert(pExpr->pList);
      assert((pExpr->pList->nExpr % 2) == 0);
      assert(pExpr->pList->nExpr > 0);
      pEList = pExpr->pList;
      aListelem = pEList->a;
      nExpr = pEList->nExpr;
      endLabel = sqlite3VdbeMakeLabel(v);
      sqlite3ExprColumnCacheDisable(pParse, 1);
      if( (pX = pExpr->pLeft)!=0 ){
        cacheX = *pX;
        cacheX.iTable = sqlite3ExprCodeTemp(pParse, pX, &regFree1);
        cacheX.op = TK_REGISTER;
        cacheX.iColumn = 0;
        opCompare.op = TK_EQ;
        opCompare.pLeft = &cacheX;
        pTest = &opCompare;
      }

      for(i=0; i<nExpr; i=i+2){
        if( pX ){
          opCompare.pRight = aListelem[i].pExpr;
        }else{
          pTest = aListelem[i].pExpr;
        }
        nextCase = sqlite3VdbeMakeLabel(v);







<









>







2449
2450
2451
2452
2453
2454
2455

2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
      assert(pExpr->pList);
      assert((pExpr->pList->nExpr % 2) == 0);
      assert(pExpr->pList->nExpr > 0);
      pEList = pExpr->pList;
      aListelem = pEList->a;
      nExpr = pEList->nExpr;
      endLabel = sqlite3VdbeMakeLabel(v);

      if( (pX = pExpr->pLeft)!=0 ){
        cacheX = *pX;
        cacheX.iTable = sqlite3ExprCodeTemp(pParse, pX, &regFree1);
        cacheX.op = TK_REGISTER;
        cacheX.iColumn = 0;
        opCompare.op = TK_EQ;
        opCompare.pLeft = &cacheX;
        pTest = &opCompare;
      }
      sqlite3ExprColumnCacheDisable(pParse, 1);
      for(i=0; i<nExpr; i=i+2){
        if( pX ){
          opCompare.pRight = aListelem[i].pExpr;
        }else{
          pTest = aListelem[i].pExpr;
        }
        nextCase = sqlite3VdbeMakeLabel(v);
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
  if( pList ){
    for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
      sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr);
    }
  }
}

/*
** Return true if any register in the range iFrom..iTo (inclusive)
** is used as part of the column cache.
*/
static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
  int i;
  for(i=0; i<pParse->nColCache; i++){
    int r = pParse->aColCache[i].iReg;
    if( r>=iFrom && r<=iTo ) return 1;
  }
  return 0;
}

/*
** Allocate or deallocate temporary use registers during code generation.
*/
int sqlite3GetTempReg(Parse *pParse){
  int i, r;
  if( pParse->nTempReg==0 ){
    return ++pParse->nMem;







<
<
<
<
<
<
<
<
<
<
<
<
<







3118
3119
3120
3121
3122
3123
3124













3125
3126
3127
3128
3129
3130
3131
  if( pList ){
    for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
      sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr);
    }
  }
}














/*
** Allocate or deallocate temporary use registers during code generation.
*/
int sqlite3GetTempReg(Parse *pParse){
  int i, r;
  if( pParse->nTempReg==0 ){
    return ++pParse->nMem;
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.683 2008/03/31 23:48:05 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.684 2008/04/01 01:42:41 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).
1838
1839
1840
1841
1842
1843
1844

1845
1846
1847
1848
1849
1850
1851
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);
void sqlite3WhereEnd(WhereInfo*);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int);
void sqlite3ExprClearColumnCache(Parse*, int);
void sqlite3ExprColumnCacheDisable(Parse*, int);
void sqlite3ExprExpireColumnCacheLines(Parse*, int, int);

int sqlite3ExprCode(Parse*, Expr*, int);
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
int sqlite3ExprCodeAndCache(Parse*, Expr*, int);
void sqlite3ExprCodeConstants(Parse*, Expr*);
int sqlite3ExprCodeExprList(Parse*, ExprList*, int);
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);







>







1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);
void sqlite3WhereEnd(WhereInfo*);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int);
void sqlite3ExprClearColumnCache(Parse*, int);
void sqlite3ExprColumnCacheDisable(Parse*, int);
void sqlite3ExprExpireColumnCacheLines(Parse*, int, int);
int sqlite3ExprWritableRegister(Parse*,int,int);
int sqlite3ExprCode(Parse*, Expr*, int);
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
int sqlite3ExprCodeAndCache(Parse*, Expr*, int);
void sqlite3ExprCodeConstants(Parse*, Expr*);
int sqlite3ExprCodeExprList(Parse*, ExprList*, int);
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
Added test/cse.test.










































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
# 2008 April 1
#
# 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.
#
#***********************************************************************
#
# 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.1 2008/04/01 01:42:41 drh Exp $
#

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

do_test cse-1.1 {
  execsql {
    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d, e, f);
    INSERT INTO t1 VALUES(1,11,12,13,14,15);
    INSERT INTO t1 VALUES(2,21,22,23,24,25);
  }
  execsql {
    SELECT b, -b, ~b, NOT b, NOT NOT b, b-b, b+b, b*b, b/b, b FROM t1
  }
} {11 -11 -12 0 1 0 22 121 1 11 21 -21 -22 0 1 0 42 441 1 21}
do_test cse-1.2 {
  execsql {
    SELECT b, b%b, b==b, b!=b, b<b, b<=b, b IS NULL, b NOT NULL, b FROM t1
  }
} {11 0 1 0 0 1 0 1 11 21 0 1 0 0 1 0 1 21}
do_test cse-1.3 {
  execsql {
    SELECT b, abs(b), coalesce(b,-b,NOT b,c,NOT c), c, -c FROM t1;
  }
} {11 11 11 12 -12 21 21 21 22 -22}
do_test cse-1.4 {
  execsql {
    SELECT CASE WHEN a==1 THEN b ELSE c END, b, c FROM t1
  }
} {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 {
    SELECT a, a%a, a==a, a!=a, a<a, a<=a, a IS NULL, a NOT NULL, a FROM t1
  }
} {1 0 1 0 0 1 0 1 1 2 0 1 0 0 1 0 1 2}


finish_test