SQLite

Check-in [e9ed5d2a36]
Login

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

Overview
Comment:added Agg opcodes to the vdbe (CVS 54)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e9ed5d2a3639161fb58856275ba9495f21d366bf
User & Date: drh 2000-06-05 21:39:49.000
Context
2000-06-06
01:50
:-) (CVS 55) (check-in: bd8b2645cc user: drh tags: trunk)
2000-06-05
21:39
added Agg opcodes to the vdbe (CVS 54) (check-in: e9ed5d2a36 user: drh tags: trunk)
18:56
:-) (CVS 53) (check-in: 3dbfa558ef user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/vdbe.c.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
** inplicit conversion from one type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.16 2000/06/05 18:54:47 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>

/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine.  Each instruction is an instance







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
** inplicit conversion from one type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.17 2000/06/05 21:39:49 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>

/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine.  Each instruction is an instance
102
103
104
105
106
107
108
























109
110
111
112
113
114
115
*/
struct Mem {
  Stack s;       /* All values of the memory cell besides string */
  char *z;       /* String value for this memory cell */
};
typedef struct Mem Mem;

























/*
** Allowed values for Stack.flags
*/
#define STK_Null      0x0001   /* Value is NULL */
#define STK_Str       0x0002   /* Value is a string */
#define STK_Int       0x0004   /* Value is an integer */
#define STK_Real      0x0008   /* Value is a real number */







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







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
*/
struct Mem {
  Stack s;       /* All values of the memory cell besides string */
  char *z;       /* String value for this memory cell */
};
typedef struct Mem Mem;

/*
** An Agg structure describes and Aggregator.  Each Agg consists of
** zero or more Aggregator elements (AggElem).  Each AggElem contains
** a key and one or more values.  The values are used in processing
** aggregate functions in a SELECT.  The key is used to implement
** the GROUP BY clause of a select.
*/
typedef struct Agg Agg;
typedef struct AggElem AggElem;
struct Agg {
  int nMem;              /* Number of values stored in each AggElem */
  AggElem *pCurrent;     /* The AggElem currently in focus */
  int nElem;             /* The number of AggElems */
  int nHash;             /* Number of slots in apHash[] */
  AggElem **apHash;      /* A hash table for looking up AggElems by zKey */
  AggElem *pFirst;       /* A list of all AggElems */
};
struct AggElem {
  char *zKey;            /* The key to this AggElem */
  AggElem *pHash;        /* Next AggElem with the same hash on zKey */
  AggElem *pNext;        /* Next AggElem in a list of them all */
  Mem aMem[1];           /* The values for this AggElem */
};

/*
** Allowed values for Stack.flags
*/
#define STK_Null      0x0001   /* Value is NULL */
#define STK_Str       0x0002   /* Value is a string */
#define STK_Int       0x0004   /* Value is an integer */
#define STK_Real      0x0008   /* Value is a real number */
141
142
143
144
145
146
147

148
149
150
151
152
153
154
  FILE *pFile;        /* At most one open file handler */
  int nField;         /* Number of file fields */
  char **azField;     /* Data for each file field */
  char *zLine;        /* A single line from the input file */
  int nLineAlloc;     /* Number of spaces allocated for zLine */
  int nMem;           /* Number of memory locations currently allocated */
  Mem *aMem;          /* The memory locations */

};

/*
** Create a new virtual database engine.
*/
Vdbe *sqliteVdbeCreate(Dbbe *pBe){
  Vdbe *p;







>







165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  FILE *pFile;        /* At most one open file handler */
  int nField;         /* Number of file fields */
  char **azField;     /* Data for each file field */
  char *zLine;        /* A single line from the input file */
  int nLineAlloc;     /* Number of spaces allocated for zLine */
  int nMem;           /* Number of memory locations currently allocated */
  Mem *aMem;          /* The memory locations */
  Agg agg;            /* Aggregate information */
};

/*
** Create a new virtual database engine.
*/
Vdbe *sqliteVdbeCreate(Dbbe *pBe){
  Vdbe *p;
322
323
324
325
326
327
328



















































































329
330
331
332
333
334
335
    p->nLabel = 0;
    p->nLabelAlloc = 0;
    return 0;
  }
  p->aLabel[i] = -1;
  return -1-i;
}




















































































/*
** Convert the given stack entity into a string if it isn't one
** already.  Return non-zero if we run out of memory.
**
** NULLs are converted into an empty string.
*/







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







347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
    p->nLabel = 0;
    p->nLabelAlloc = 0;
    return 0;
  }
  p->aLabel[i] = -1;
  return -1-i;
}

/*
** Reset an Agg structure.  Delete all its contents.
*/
static void AggReset(Agg *p){
  int i;
  while( p->pFirst ){
    AggElem *pElem = p->pFirst;
    p->pFirst = pElem->pNext;
    for(i=0; i<p->nMem; i++){
      if( pElem->aMem[i].s.flags & STK_Dyn ){
        sqliteFree(pElem->aMem[i].z);
      }
    }
    sqliteFree(pElem);
  }
  sqliteFree(p->apHash);
  memset(p, 0, sizeof(*p));
}

/*
** Add the given AggElem to the hash table
*/
static void AggEnhash(Agg *p, AggElem *pElem){
  int h = sqliteHashNoCase(pElem->zKey, 0) % p->nHash;
  pElem->pHash = p->apHash[h];
  p->apHash[h] = pElem;
}

/*
** Change the size of the hash table to the amount given.
*/
static void AggRehash(Agg *p, int nHash){
  int size;
  AggElem *pElem;
  if( p->nHash==nHash ) return;
  size = nHash * sizeof(AggElem*);
  p->apHash = sqliteRealloc(p->apHash, size );
  memset(p->apHash, 0, size);
  p->nHash = nHash;
  for(pElem=p->pFirst; pElem; pElem=pElem->pNext){
    AggEnhash(p, pElem);
  }
}

/*
** Insert a new element and make it the current element.  
**
** Return 0 on success and 1 if memory is exhausted.
*/
static int AggInsert(Agg *p, char *zKey){
  AggElem *pElem;
  if( p->nHash < p->nElem*2 ){
    AggRehash(p, p->nElem*2 + 103);
  }
  if( p->nHash==0 ) return 1;
  pElem = sqliteMalloc( sizeof(AggElem) + strlen(zKey) + 1 +
                        (p->nMem-1)*sizeof(pElem->aMem[0]) );
  if( pElem==0 ) return 1;
  pElem->zKey = (char*)&pElem->aMem[p->nMem];
  strcpy(pElem->zKey, zKey);
  AggEnhash(p, pElem);
  pElem->pNext = p->pFirst;
  p->pFirst = pElem;
  p->nElem++;
  p->pCurrent = pElem;
  return 0;
}

/*
** Get the AggElem currently in focus
*/
#define AggInFocus(P)   ((P).pCurrent ? (P).pCurrent : _AggInFocus(&(P)))
static AggElem *_AggInFocus(Agg *p){
  AggElem *pFocus = p->pFirst;
  if( pFocus ){
    p->pCurrent = pFocus;
  }else{
    AggInsert(p,"");
    pFocus = p->pCurrent;
  }
  return pFocus;
}

/*
** Convert the given stack entity into a string if it isn't one
** already.  Return non-zero if we run out of memory.
**
** NULLs are converted into an empty string.
*/
515
516
517
518
519
520
521

522
523
524
525
526
527
528
  }
  p->nField = 0;
  if( p->zLine ){
    sqliteFree(p->zLine);
    p->zLine = 0;
  }
  p->nLineAlloc = 0;

}

/*
** Delete an entire VDBE.
*/
void sqliteVdbeDelete(Vdbe *p){
  int i;







>







623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
  }
  p->nField = 0;
  if( p->zLine ){
    sqliteFree(p->zLine);
    p->zLine = 0;
  }
  p->nLineAlloc = 0;
  AggReset(&p->agg);
}

/*
** Delete an entire VDBE.
*/
void sqliteVdbeDelete(Vdbe *p){
  int i;
557
558
559
560
561
562
563


564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  "Key",            "Rewind",         "Next",           "Destroy",
  "Reorganize",     "ResetIdx",       "NextIdx",        "PutIdx",
  "DeleteIdx",      "MemLoad",        "MemStore",       "ListOpen",
  "ListWrite",      "ListRewind",     "ListRead",       "ListClose",
  "SortOpen",       "SortPut",        "SortMakeRec",    "SortMakeKey",
  "Sort",           "SortNext",       "SortKey",        "SortCallback",
  "SortClose",      "FileOpen",       "FileRead",       "FileField",


  "FileClose",      "MakeRecord",     "MakeKey",        "Goto",
  "If",             "Halt",           "ColumnCount",    "ColumnName",
  "Callback",       "Integer",        "String",         "Null",
  "Pop",            "Dup",            "Pull",           "Add",
  "AddImm",         "Subtract",       "Multiply",       "Divide",
  "Min",            "Max",            "Like",           "Glob",
  "Eq",             "Ne",             "Lt",             "Le",
  "Gt",             "Ge",             "IsNull",         "NotNull",
  "Negative",       "And",            "Or",             "Not",
  "Concat",         "Noop",         
};

/*
** Given the name of an opcode, return its number.  Return 0 if
** there is no match.
**
** This routine is used for testing and debugging.







>
>
|
|
|
|
|
|
|
|
<
|







666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682

683
684
685
686
687
688
689
690
  "Key",            "Rewind",         "Next",           "Destroy",
  "Reorganize",     "ResetIdx",       "NextIdx",        "PutIdx",
  "DeleteIdx",      "MemLoad",        "MemStore",       "ListOpen",
  "ListWrite",      "ListRewind",     "ListRead",       "ListClose",
  "SortOpen",       "SortPut",        "SortMakeRec",    "SortMakeKey",
  "Sort",           "SortNext",       "SortKey",        "SortCallback",
  "SortClose",      "FileOpen",       "FileRead",       "FileField",
  "FileClose",      "AggReset",       "AggFocus",       "AggIncr",
  "AggNext",        "AggSet",         "AggGet",         "MakeRecord",
  "MakeKey",        "Goto",           "If",             "Halt",
  "ColumnCount",    "ColumnName",     "Callback",       "Integer",
  "String",         "Null",           "Pop",            "Dup",
  "Pull",           "Add",            "AddImm",         "Subtract",
  "Multiply",       "Divide",         "Min",            "Max",
  "Like",           "Glob",           "Eq",             "Ne",
  "Lt",             "Le",             "Gt",             "Ge",
  "IsNull",         "NotNull",        "Negative",       "And",

  "Or",             "Not",            "Concat",         "Noop",
};

/*
** Given the name of an opcode, return its number.  Return 0 if
** there is no match.
**
** This routine is used for testing and debugging.
2476
2477
2478
2479
2480
2481
2482






























































































































































2483
2484
2485
2486
2487
2488
2489
            memcpy(z, p->aMem[i].z, p->aStack[tos].n);
            p->zStack[tos] = z;
            p->aStack[tos].flags |= STK_Dyn;
          }
        }
        break;
      }































































































































































      /* An other opcode is illegal...
      */
      default: {
        sprintf(zBuf,"%d",pOp->opcode);
        sqliteSetString(pzErrMsg, "unknown opcode ", zBuf, 0);
        rc = SQLITE_INTERNAL;







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







2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
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
            memcpy(z, p->aMem[i].z, p->aStack[tos].n);
            p->zStack[tos] = z;
            p->aStack[tos].flags |= STK_Dyn;
          }
        }
        break;
      }

      /* Opcode: AggReset * P2 *
      **
      ** Reset the aggregator so that it no longer contains any data.
      ** Future aggregator elements will contain P2 values each.
      */
      case OP_AggReset: {
        AggReset(&p->agg);
        p->agg.nMem = pOp->p2;
        break;
      }

      /* Opcode: AggFocus * P2 *
      **
      ** Pop the top of the stack and use that as an aggregator key.  If
      ** an aggregator with that same key already exists, then make the
      ** aggregator the current aggregator and jump to P2.  If no aggregator
      ** with the given key exists, create one and make it current but
      ** do not jump.
      **
      ** This opcode should not be executed after an AggNext but before
      ** the next AggReset.
      */
      case OP_AggFocus: {
        int tos = p->tos;
        AggElem *pElem;
        char *zKey;
        int nKey;

        if( tos<0 ) goto not_enough_stack;
        Stringify(p, tos);
        zKey = p->zStack[tos]; 
        nKey = p->aStack[tos].n;
        if( p->agg.nHash<=0 ){
          pElem = 0;
        }else{
          int h = sqliteHashNoCase(zKey, nKey-1) % p->agg.nHash;
          for(pElem=p->agg.apHash[h]; pElem; pElem=pElem->pHash){
            if( strcmp(pElem->zKey, zKey)==0 ) break;
          }
        }
        if( pElem ){
          p->agg.pCurrent = pElem;
          pc = pOp->p2 - 1;
        }else{
          AggInsert(&p->agg, zKey);
        }
        break; 
      }

      /* Opcode: AggIncr P1 P2 *
      **
      ** Increment the P2-th field of the aggregate element current
      ** in focus by an amount P1.
      */
      case OP_AggIncr: {
        AggElem *pFocus = AggInFocus(p->agg);
        int i = pOp->p2;
        if( pFocus==0 ) goto no_mem;
        if( i>=0 && i<p->agg.nMem ){
          Mem *pMem = &pFocus->aMem[i];
          if( pMem->s.flags!=STK_Int ){
            if( pMem->s.flags & STK_Int ){
              /* Do nothing */
            }else if( pMem->s.flags & STK_Real ){
              pMem->s.i = pMem->s.r;
            }else if( pMem->s.flags & STK_Str ){
              pMem->s.i = atoi(pMem->z);
            }else{
              pMem->s.i = 0;
            }
            if( pMem->s.flags & STK_Dyn ) sqliteFree(pMem->z);
            pMem->z = 0;
            pMem->s.flags = STK_Int;
          }
          pMem->s.i += pOp->p1;
        }
        break;
      }

      /* Opcode: AggSet * P2 *
      **
      ** Move the top of the stack into the P2-th field of the current
      ** aggregate.  String values are duplicated into new memory.
      */
      case OP_AggSet: {
        AggElem *pFocus = AggInFocus(p->agg);
        int i = pOp->p2;
        int tos = p->tos;
        if( tos<0 ) goto not_enough_stack;
        if( pFocus==0 ) goto no_mem;
        if( i>=0 && i<p->agg.nMem ){
          Mem *pMem = &pFocus->aMem[i];
          pMem->s = p->aStack[tos];
          if( pMem->s.flags & STK_Str ){
            pMem->z = sqliteMalloc( p->aStack[tos].n );
            if( pMem->z==0 ) goto no_mem;
            memcpy(pMem->z, p->zStack[tos], pMem->s.n);
            pMem->s.flags |= STK_Str|STK_Dyn;
          }
        }
        PopStack(p, 1);
        break;
      }

      /* Opcode: AggGet * P2 *
      **
      ** Push a new entry onto the stack which is a copy of the P2-th field
      ** of the current aggregate.  String are not duplicated so
      ** string values will be ephemeral.  
      */
      case OP_AggGet: {
        AggElem *pFocus = AggInFocus(p->agg);
        int i = pOp->p2;
        int tos = ++p->tos;
        if( NeedStack(p, tos) ) goto no_mem;
        if( pFocus==0 ) goto no_mem;
        if( i>=0 && i<p->agg.nMem ){
          Mem *pMem = &pFocus->aMem[i];
          p->aStack[tos] = pMem->s;
          p->zStack[tos] = pMem->z;
          p->aStack[tos].flags &= ~STK_Dyn;
        }
        break;
      }

      /* Opcode: AggNext * P2 *
      **
      ** Make the next aggregate value the current aggregate.  The prior
      ** aggregate is deleted.  If all aggregate values have been consumed,
      ** jump to P2.
      **
      ** Do not execute an AggFocus after this opcode until after the
      ** next AggReset.
      */
      case OP_AggNext: {
        if( p->agg.nHash ){
          p->agg.nHash = 0;
          sqliteFree(p->agg.apHash);
          p->agg.apHash = 0;
          p->agg.pCurrent = p->agg.pFirst;
        }else if( p->agg.pCurrent==p->agg.pFirst ){
          int i;
          AggElem *pElem = p->agg.pCurrent;
          for(i=0; i<p->agg.nMem; i++){
            if( pElem->aMem[i].s.flags & STK_Dyn ){
              sqliteFree(pElem->aMem[i].z);
            }
          }
          p->agg.pCurrent = p->agg.pFirst = pElem->pNext;
          sqliteFree(pElem);
          p->agg.nElem--;
        }
        if( p->agg.pCurrent==0 ){
          pc = pOp->p2-1;
        }
        break;
      }

      /* An other opcode is illegal...
      */
      default: {
        sprintf(zBuf,"%d",pOp->opcode);
        sqliteSetString(pzErrMsg, "unknown opcode ", zBuf, 0);
        rc = SQLITE_INTERNAL;
Changes to src/vdbe.h.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.6 2000/06/05 18:54:47 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.7 2000/06/05 21:39:49 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
111
112
113
114
115
116
117







118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#define OP_SortClose          33

#define OP_FileOpen           34
#define OP_FileRead           35
#define OP_FileField          36
#define OP_FileClose          37








#define OP_MakeRecord         38
#define OP_MakeKey            39

#define OP_Goto               40
#define OP_If                 41
#define OP_Halt               42

#define OP_ColumnCount        43
#define OP_ColumnName         44
#define OP_Callback           45

#define OP_Integer            46
#define OP_String             47
#define OP_Null               48
#define OP_Pop                49
#define OP_Dup                50
#define OP_Pull               51

#define OP_Add                52
#define OP_AddImm             53
#define OP_Subtract           54
#define OP_Multiply           55
#define OP_Divide             56
#define OP_Min                57
#define OP_Max                58
#define OP_Like               59
#define OP_Glob               60
#define OP_Eq                 61
#define OP_Ne                 62
#define OP_Lt                 63
#define OP_Le                 64
#define OP_Gt                 65
#define OP_Ge                 66
#define OP_IsNull             67
#define OP_NotNull            68
#define OP_Negative           69
#define OP_And                70
#define OP_Or                 71
#define OP_Not                72
#define OP_Concat             73
#define OP_Noop               74

#define OP_MAX                74

/*
** Prototypes for the VDBE interface.  See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqliteVdbeCreate(Dbbe*);
int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);







>
>
>
>
>
>
>
|
|

|
|
|

|
|
|

|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|







111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#define OP_SortClose          33

#define OP_FileOpen           34
#define OP_FileRead           35
#define OP_FileField          36
#define OP_FileClose          37

#define OP_AggReset           38
#define OP_AggFocus           39
#define OP_AggIncr            40
#define OP_AggNext            41
#define OP_AggSet             42
#define OP_AggGet             43

#define OP_MakeRecord         44
#define OP_MakeKey            45

#define OP_Goto               46
#define OP_If                 47
#define OP_Halt               48

#define OP_ColumnCount        49
#define OP_ColumnName         50
#define OP_Callback           51

#define OP_Integer            52
#define OP_String             53
#define OP_Null               54
#define OP_Pop                55
#define OP_Dup                56
#define OP_Pull               57

#define OP_Add                58
#define OP_AddImm             59
#define OP_Subtract           60
#define OP_Multiply           61
#define OP_Divide             62
#define OP_Min                63
#define OP_Max                64
#define OP_Like               65
#define OP_Glob               66
#define OP_Eq                 67
#define OP_Ne                 68
#define OP_Lt                 69
#define OP_Le                 70
#define OP_Gt                 71
#define OP_Ge                 72
#define OP_IsNull             73
#define OP_NotNull            74
#define OP_Negative           75
#define OP_And                76
#define OP_Or                 77
#define OP_Not                78
#define OP_Concat             79
#define OP_Noop               80

#define OP_MAX                80

/*
** Prototypes for the VDBE interface.  See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqliteVdbeCreate(Dbbe*);
int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);
Changes to test/subselect.test.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#   http://www.hwaci.com/drh/
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing SELECT statements that are part of
# expressions.
#
# $Id: subselect.test,v 1.2 2000/06/05 18:56:43 drh Exp $

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

# Basic sanity checking.  Try a simple subselect.
#
do_test subselect-1.1 {







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#   http://www.hwaci.com/drh/
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing SELECT statements that are part of
# expressions.
#
# $Id: subselect.test,v 1.3 2000/06/05 21:39:49 drh Exp $

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

# Basic sanity checking.  Try a simple subselect.
#
do_test subselect-1.1 {
82
83
84
85
86
87
88
89








90
    INSERT INTO t2 VALUES(4,16);
  }
  execsql {
    SELECT y from t2 
    WHERE x = (SELECT sum(b) FROM t1 where a notnull) - (SELECT sum(a) FROM t1)
  }
} {8}









finish_test








>
>
>
>
>
>
>
>

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    INSERT INTO t2 VALUES(4,16);
  }
  execsql {
    SELECT y from t2 
    WHERE x = (SELECT sum(b) FROM t1 where a notnull) - (SELECT sum(a) FROM t1)
  }
} {8}

# Try something useful.  Delete every entry from t2 where the
# x value is less than half of the maximum.
#
do_test subselect-1.6 {
  execsql {DELETE FROM t2 WHERE x < 0.5*(SELECT max(x) FROM t2)}
  execsql {SELECT x FROM t2 ORDER BY x}
} {2 3 4}

finish_test