/ Check-in [263a8ca4]
Login

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

Overview
Comment:Replace the atoi() library routine with a faster home-grown version in the VDBE. This gives a dramatic speed improvement for some kinds of queries. (CVS 784)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:263a8ca40f7ff66fbdcb43bf9032391d5b1e68bd
User & Date: drh 2002-11-11 00:05:43
Context
2002-11-11
01:04
Back out the changes in the pager that sorted pages prior to writing them to the database. Additional measurements showed no performance gains. (CVS 785) check-in: 745d6639 user: drh tags: trunk
00:05
Replace the atoi() library routine with a faster home-grown version in the VDBE. This gives a dramatic speed improvement for some kinds of queries. (CVS 784) check-in: 263a8ca4 user: drh tags: trunk
2002-11-10
23:32
Two optimizations to the pager: (1) Write dirty pages back to the database file in order and (2) Keep a separate list of in-memory pages that are in the checkpoint journal in order to speed a checkpoint commit. (CVS 783) check-in: a6ef6657 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
...
829
830
831
832
833
834
835



























836
837
838
839
840
841
842
...
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
...
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
....
2105
2106
2107
2108
2109
2110
2111

2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
....
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
....
2263
2264
2265
2266
2267
2268
2269
2270
2271


2272
2273
2274


2275
2276
2277
2278
2279
2280
2281
....
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.183 2002/11/01 01:55:38 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The makefile scans this source file and creates the following
** array of string constants which are the names of all VDBE opcodes.
................................................................................
*/
#define Release(P,I)  if((P)->aStack[I].flags&STK_Dyn){ hardRelease(P,I); }
static void hardRelease(Vdbe *p, int i){
  sqliteFree(p->zStack[i]);
  p->zStack[i] = 0;
  p->aStack[i].flags &= ~(STK_Str|STK_Dyn|STK_Static|STK_Ephem);
}




























/*
** Convert the given stack entity into a integer if it isn't one
** already.
**
** Any prior string or real representation is invalidated.  
** NULLs are converted into 0.
................................................................................
#define Integerify(P,I) \
    if(((P)->aStack[(I)].flags&STK_Int)==0){ hardIntegerify(P,I); }
static void hardIntegerify(Vdbe *p, int i){
  if( p->aStack[i].flags & STK_Real ){
    p->aStack[i].i = (int)p->aStack[i].r;
    Release(p, i);
  }else if( p->aStack[i].flags & STK_Str ){
    p->aStack[i].i = atoi(p->zStack[i]);
    Release(p, i);
  }else{
    p->aStack[i].i = 0;
  }
  p->aStack[i].flags = STK_Int;
}

................................................................................
  zNum++;
  if( *zNum=='-' || *zNum=='+' ) zNum++;
  if( !isdigit(*zNum) ) return 0;
  while( isdigit(*zNum) ) zNum++;
  return *zNum==0;
}

/*
** Return TRUE if zNum is an integer.
*/
static int isInteger(const char *zNum){
  if( *zNum=='-' || *zNum=='+' ) zNum++;
  while( isdigit(*zNum) ) zNum++;
  return *zNum==0;
}

/*
** Delete a keylist
*/
static void KeylistFree(Keylist *p){
  while( p ){
    Keylist *pNext = p->pNext;
    sqliteFree(p);
................................................................................
    int i = aStack[tos].r;
    double r = i;
    if( r!=aStack[tos].r ){
      goto mismatch;
    }
    aStack[tos].i = i;
  }else if( aStack[tos].flags & STK_Str ){

    if( !isInteger(zStack[tos]) ){
      goto mismatch;
    }
    p->aStack[tos].i = atoi(p->zStack[tos]);
  }else{
    goto mismatch;
  }
  Release(p, tos);
  p->aStack[tos].flags = STK_Int;
  break;

................................................................................
case OP_Ne:
case OP_Lt:
case OP_Le:
case OP_Gt:
case OP_Ge: {
  int tos = p->tos;
  int nos = tos - 1;
  int c;
  int ft, fn;
  VERIFY( if( nos<0 ) goto not_enough_stack; )
  ft = aStack[tos].flags;
  fn = aStack[nos].flags;
  if( (ft | fn) & STK_Null ){
    POPSTACK;
    POPSTACK;
................................................................................
    }else{
      p->tos++;
      aStack[nos].flags = STK_Null;
    }
    break;
  }else if( (ft & fn & STK_Int)==STK_Int ){
    c = aStack[nos].i - aStack[tos].i;
  }else if( (ft & STK_Int)!=0 && (fn & STK_Str)!=0 && isInteger(zStack[nos]) ){
    Integerify(p, nos);


    c = aStack[nos].i - aStack[tos].i;
  }else if( (fn & STK_Int)!=0 && (ft & STK_Str)!=0 && isInteger(zStack[tos]) ){
    Integerify(p, tos);


    c = aStack[nos].i - aStack[tos].i;
  }else{
    if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
    c = sqliteCompare(zStack[nos], zStack[tos]);
  }
  switch( pOp->opcode ){
    case OP_Eq:    c = c==0;     break;
................................................................................

  VERIFY( if( iSet<0 || iSet>=p->nSet ) goto bad_instruction; )
  VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
  pSet = &p->aSet[iSet];
  nRoot = sqliteHashCount(&pSet->hash);
  aRoot = sqliteMalloc( sizeof(int)*(nRoot+1) );
  for(j=0, i=sqliteHashFirst(&pSet->hash); i; i=sqliteHashNext(i), j++){
    aRoot[j] = atoi((char*)sqliteHashKey(i));
  }
  aRoot[j] = 0;
  z = sqliteBtreeIntegrityCheck(pOp->p2 ? db->pBeTemp : pBt, aRoot, nRoot);
  if( z==0 || z[0]==0 ){
    if( z ) sqliteFree(z);
    zStack[tos] = "ok";
    aStack[tos].n = 3;







|







 







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







 







|







 







<
<
<
<
<
<
<
<
<







 







>
|


|







 







|







 







|
|
>
>

|
|
>
>







 







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
...
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
...
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
...
990
991
992
993
994
995
996









997
998
999
1000
1001
1002
1003
....
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
....
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
....
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
....
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.184 2002/11/11 00:05:43 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The makefile scans this source file and creates the following
** array of string constants which are the names of all VDBE opcodes.
................................................................................
*/
#define Release(P,I)  if((P)->aStack[I].flags&STK_Dyn){ hardRelease(P,I); }
static void hardRelease(Vdbe *p, int i){
  sqliteFree(p->zStack[i]);
  p->zStack[i] = 0;
  p->aStack[i].flags &= ~(STK_Str|STK_Dyn|STK_Static|STK_Ephem);
}

/*
** Return TRUE if zNum is an integer and write
** the value of the integer into *pNum.
**
** Under Linux (RedHat 7.2) this routine is much faster than atoi()
** for converting strings into integers.
*/
static int toInt(const char *zNum, int *pNum){
  int v = 0;
  int neg;
  if( *zNum=='-' ){
    neg = 1;
    zNum++;
  }else if( *zNum=='+' ){
    neg = 0;
    zNum++;
  }else{
    neg = 0;
  }
  while( isdigit(*zNum) ){
    v = v*10 + *zNum - '0';
    zNum++;
  }
  *pNum = neg ? -v : v;
  return *zNum==0;
}

/*
** Convert the given stack entity into a integer if it isn't one
** already.
**
** Any prior string or real representation is invalidated.  
** NULLs are converted into 0.
................................................................................
#define Integerify(P,I) \
    if(((P)->aStack[(I)].flags&STK_Int)==0){ hardIntegerify(P,I); }
static void hardIntegerify(Vdbe *p, int i){
  if( p->aStack[i].flags & STK_Real ){
    p->aStack[i].i = (int)p->aStack[i].r;
    Release(p, i);
  }else if( p->aStack[i].flags & STK_Str ){
    toInt(p->zStack[i], &p->aStack[i].i);
    Release(p, i);
  }else{
    p->aStack[i].i = 0;
  }
  p->aStack[i].flags = STK_Int;
}

................................................................................
  zNum++;
  if( *zNum=='-' || *zNum=='+' ) zNum++;
  if( !isdigit(*zNum) ) return 0;
  while( isdigit(*zNum) ) zNum++;
  return *zNum==0;
}










/*
** Delete a keylist
*/
static void KeylistFree(Keylist *p){
  while( p ){
    Keylist *pNext = p->pNext;
    sqliteFree(p);
................................................................................
    int i = aStack[tos].r;
    double r = i;
    if( r!=aStack[tos].r ){
      goto mismatch;
    }
    aStack[tos].i = i;
  }else if( aStack[tos].flags & STK_Str ){
    int v;
    if( !toInt(zStack[tos], &v) ){
      goto mismatch;
    }
    p->aStack[tos].i = v;
  }else{
    goto mismatch;
  }
  Release(p, tos);
  p->aStack[tos].flags = STK_Int;
  break;

................................................................................
case OP_Ne:
case OP_Lt:
case OP_Le:
case OP_Gt:
case OP_Ge: {
  int tos = p->tos;
  int nos = tos - 1;
  int c, v;
  int ft, fn;
  VERIFY( if( nos<0 ) goto not_enough_stack; )
  ft = aStack[tos].flags;
  fn = aStack[nos].flags;
  if( (ft | fn) & STK_Null ){
    POPSTACK;
    POPSTACK;
................................................................................
    }else{
      p->tos++;
      aStack[nos].flags = STK_Null;
    }
    break;
  }else if( (ft & fn & STK_Int)==STK_Int ){
    c = aStack[nos].i - aStack[tos].i;
  }else if( (ft & STK_Int)!=0 && (fn & STK_Str)!=0 && toInt(zStack[nos],&v) ){
    Release(p, nos);
    aStack[nos].i = v;
    aStack[nos].flags = STK_Int;
    c = aStack[nos].i - aStack[tos].i;
  }else if( (fn & STK_Int)!=0 && (ft & STK_Str)!=0 && toInt(zStack[tos],&v) ){
    Release(p, tos);
    aStack[tos].i = v;
    aStack[tos].flags = STK_Int;
    c = aStack[nos].i - aStack[tos].i;
  }else{
    if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
    c = sqliteCompare(zStack[nos], zStack[tos]);
  }
  switch( pOp->opcode ){
    case OP_Eq:    c = c==0;     break;
................................................................................

  VERIFY( if( iSet<0 || iSet>=p->nSet ) goto bad_instruction; )
  VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
  pSet = &p->aSet[iSet];
  nRoot = sqliteHashCount(&pSet->hash);
  aRoot = sqliteMalloc( sizeof(int)*(nRoot+1) );
  for(j=0, i=sqliteHashFirst(&pSet->hash); i; i=sqliteHashNext(i), j++){
    toInt((char*)sqliteHashKey(i), &aRoot[j]);
  }
  aRoot[j] = 0;
  z = sqliteBtreeIntegrityCheck(pOp->p2 ? db->pBeTemp : pBt, aRoot, nRoot);
  if( z==0 || z[0]==0 ){
    if( z ) sqliteFree(z);
    zStack[tos] = "ok";
    aStack[tos].n = 3;