summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/src/vdbe.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/vdbe.c')
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbe.c576
1 files changed, 144 insertions, 432 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/vdbe.c b/ext/pdo_sqlite/sqlite/src/vdbe.c
index ae33e39961..a3c3cd11f0 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbe.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbe.c
@@ -161,38 +161,6 @@ static void _storeTypeInfo(Mem *pMem){
}
/*
-** Insert a new aggregate element and make it the element that
-** has focus.
-**
-** Return 0 on success and 1 if memory is exhausted.
-*/
-static int AggInsert(Agg *p, char *zKey, int nKey){
- AggElem *pElem;
- int i;
- int rc;
- pElem = sqliteMalloc( sizeof(AggElem) + nKey +
- (p->nMem-1)*sizeof(pElem->aMem[0]) );
- if( pElem==0 ) return SQLITE_NOMEM;
- pElem->zKey = (char*)&pElem->aMem[p->nMem];
- memcpy(pElem->zKey, zKey, nKey);
- pElem->nKey = nKey;
-
- if( p->pCsr ){
- rc = sqlite3BtreeInsert(p->pCsr, zKey, nKey, &pElem, sizeof(AggElem*));
- if( rc!=SQLITE_OK ){
- sqliteFree(pElem);
- return rc;
- }
- }
-
- for(i=0; i<p->nMem; i++){
- pElem->aMem[i].flags = MEM_Null;
- }
- p->pCurrent = pElem;
- return 0;
-}
-
-/*
** Pop the stack N times.
*/
static void popStack(Mem **ppTos, int N){
@@ -206,39 +174,6 @@ static void popStack(Mem **ppTos, int N){
}
/*
-** The parameters are pointers to the head of two sorted lists
-** of Sorter structures. Merge these two lists together and return
-** a single sorted list. This routine forms the core of the merge-sort
-** algorithm.
-**
-** In the case of a tie, left sorts in front of right.
-*/
-static Sorter *Merge(Sorter *pLeft, Sorter *pRight, KeyInfo *pKeyInfo){
- Sorter sHead;
- Sorter *pTail;
- pTail = &sHead;
- pTail->pNext = 0;
- while( pLeft && pRight ){
- int c = sqlite3VdbeRecordCompare(pKeyInfo, pLeft->nKey, pLeft->zKey,
- pRight->nKey, pRight->zKey);
- if( c<=0 ){
- pTail->pNext = pLeft;
- pLeft = pLeft->pNext;
- }else{
- pTail->pNext = pRight;
- pRight = pRight->pNext;
- }
- pTail = pTail->pNext;
- }
- if( pLeft ){
- pTail->pNext = pLeft;
- }else if( pRight ){
- pTail->pNext = pRight;
- }
- return sHead.pNext;
-}
-
-/*
** Allocate cursor number iCur. Return a pointer to it. Return NULL
** if we run out of memory.
*/
@@ -635,7 +570,7 @@ case OP_Return: { /* no-push */
/* Opcode: Halt P1 P2 P3
**
-** Exit immediately. All open cursors, Lists, Sorts, etc are closed
+** Exit immediately. All open cursors, Fifos, etc are closed
** automatically.
**
** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(),
@@ -773,6 +708,7 @@ case OP_String: {
case OP_Null: {
pTos++;
pTos->flags = MEM_Null;
+ pTos->n = 0;
break;
}
@@ -1164,26 +1100,25 @@ case OP_CollSeq: { /* no-push */
/* Opcode: Function P1 P2 P3
**
** Invoke a user function (P3 is a pointer to a Function structure that
-** defines the function) with P1 arguments taken from the stack. Pop all
+** defines the function) with P2 arguments taken from the stack. Pop all
** arguments from the stack and push back the result.
**
-** P2 is a 32-bit bitmask indicating whether or not each argument to the
+** P1 is a 32-bit bitmask indicating whether or not each argument to the
** function was determined to be constant at compile time. If the first
-** argument was constant then bit 0 of P2 is set. This is used to determine
+** argument was constant then bit 0 of P1 is set. This is used to determine
** whether meta data associated with a user function argument using the
** sqlite3_set_auxdata() API may be safely retained until the next
** invocation of this opcode.
**
-** See also: AggFunc
+** See also: AggStep and AggFinal
*/
case OP_Function: {
int i;
Mem *pArg;
sqlite3_context ctx;
sqlite3_value **apVal;
- int n = pOp->p1;
+ int n = pOp->p2;
- n = pOp->p1;
apVal = p->apArg;
assert( apVal || n==0 );
@@ -1222,7 +1157,7 @@ case OP_Function: {
** immediately call the destructor for any non-static values.
*/
if( ctx.pVdbeFunc ){
- sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p2);
+ sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1);
pOp->p3 = (char *)ctx.pVdbeFunc;
pOp->p3type = P3_VDBEFUNC;
}
@@ -1476,9 +1411,16 @@ case OP_ToBlob: { /* no-push */
** jump to instruction P2. Otherwise, continue to the next instruction.
**
** If the 0x100 bit of P1 is true and either operand is NULL then take the
-** jump. If the 0x100 bit of P1 is false then fall thru if either operand
+** jump. If the 0x100 bit of P1 is clear then fall thru if either operand
** is NULL.
**
+** If the 0x200 bit of P1 is set and either operand is NULL then
+** both operands are converted to integers prior to comparison.
+** NULL operands are converted to zero and non-NULL operands are
+** converted to 1. Thus, for example, with 0x200 set, NULL==NULL is true
+** whereas it would normally be NULL. Similarly, NULL==123 is false when
+** 0x200 is set but is NULL when the 0x200 bit of P1 is clear.
+**
** The least significant byte of P1 (mask 0xff) must be an affinity character -
** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values
** according to the affinity before the comparison is made. If the byte is
@@ -1546,14 +1488,36 @@ case OP_Ge: { /* same as TK_GE, no-push */
** the stack.
*/
if( flags&MEM_Null ){
- popStack(&pTos, 2);
- if( pOp->p2 ){
- if( pOp->p1 & 0x100 ) pc = pOp->p2-1;
+ if( (pOp->p1 & 0x200)!=0 ){
+ /* The 0x200 bit of P1 means, roughly "do not treat NULL as the
+ ** magic SQL value it normally is - treat it as if it were another
+ ** integer".
+ **
+ ** With 0x200 set, if either operand is NULL then both operands
+ ** are converted to integers prior to being passed down into the
+ ** normal comparison logic below. NULL operands are converted to
+ ** zero and non-NULL operands are converted to 1. Thus, for example,
+ ** with 0x200 set, NULL==NULL is true whereas it would normally
+ ** be NULL. Similarly, NULL!=123 is true.
+ */
+ sqlite3VdbeMemSetInt64(pTos, (pTos->flags & MEM_Null)==0);
+ sqlite3VdbeMemSetInt64(pNos, (pNos->flags & MEM_Null)==0);
}else{
- pTos++;
- pTos->flags = MEM_Null;
+ /* If the 0x200 bit of P1 is clear and either operand is NULL then
+ ** the result is always NULL. The jump is taken if the 0x100 bit
+ ** of P1 is set.
+ */
+ popStack(&pTos, 2);
+ if( pOp->p2 ){
+ if( pOp->p1 & 0x100 ){
+ pc = pOp->p2-1;
+ }
+ }else{
+ pTos++;
+ pTos->flags = MEM_Null;
+ }
+ break;
}
- break;
}
affinity = pOp->p1 & 0xFF;
@@ -1710,6 +1674,13 @@ case OP_BitNot: { /* same as TK_BITNOT, no-push */
** Do nothing. This instruction is often useful as a jump
** destination.
*/
+/*
+** The magic Explain opcode are only inserted when explain==2 (which
+** is to say when the EXPLAIN QUERY PLAN syntax is used.)
+** This opcode records information from the optimizer. It is the
+** the same as a no-op. This opcodesnever appears in a real VM program.
+*/
+case OP_Explain:
case OP_Noop: { /* no-push */
break;
}
@@ -2020,7 +1991,7 @@ case OP_Column: {
** we are dealing with a malformed record.
*/
if( idx!=szHdr || offset!=payloadSize ){
- rc = SQLITE_CORRUPT;
+ rc = SQLITE_CORRUPT_BKPT;
goto op_column_out;
}
@@ -2574,7 +2545,7 @@ case OP_OpenWrite: { /* no-push */
** only mean that we are dealing with a corrupt database file
*/
if( (flags & 0xf0)!=0 || ((flags & 0x07)!=5 && (flags & 0x07)!=2) ){
- rc = SQLITE_CORRUPT;
+ rc = SQLITE_CORRUPT_BKPT;
goto abort_due_to_error;
}
pCur->isTable = (flags & BTREE_INTKEY)!=0;
@@ -2585,7 +2556,7 @@ case OP_OpenWrite: { /* no-push */
*/
if( (pCur->isTable && pOp->p3type==P3_KEYINFO)
|| (pCur->isIndex && pOp->p3type!=P3_KEYINFO) ){
- rc = SQLITE_CORRUPT;
+ rc = SQLITE_CORRUPT_BKPT;
goto abort_due_to_error;
}
break;
@@ -2603,13 +2574,14 @@ case OP_OpenWrite: { /* no-push */
break;
}
-/* Opcode: OpenVirtual P1 * P3
+/* Opcode: OpenVirtual P1 P2 P3
**
-** Open a new cursor to a transient or virtual table.
+** Open a new cursor P1 to a transient or virtual table.
** The cursor is always opened read/write even if
** the main database is read-only. The transient or virtual
** table is deleted automatically when the cursor is closed.
**
+** P2 is the number of columns in the virtual table.
** The cursor points to a BTree table if P3==0 and to a BTree index
** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure
** that defines the format of keys in the index.
@@ -2650,6 +2622,7 @@ case OP_OpenVirtual: { /* no-push */
pCx->pIncrKey = &pCx->bogusIncrKey;
}
}
+ pCx->nField = pOp->p2;
pCx->isIndex = !pCx->isTable;
break;
}
@@ -3035,6 +3008,24 @@ case OP_NotExists: { /* no-push */
break;
}
+/* Opcode: Sequence P1 * *
+**
+** Push an integer onto the stack which is the next available
+** sequence number for cursor P1. The sequence number on the
+** cursor is incremented after the push.
+*/
+case OP_Sequence: {
+ int i = pOp->p1;
+ assert( pTos>=p->aStack );
+ assert( i>=0 && i<p->nCursor );
+ assert( p->apCsr[i]!=0 );
+ pTos++;
+ pTos->i = p->apCsr[i]->seqCount++;
+ pTos->flags = MEM_Int;
+ break;
+}
+
+
/* Opcode: NewRowid P1 P2 *
**
** Get a new integer record number (a.k.a "rowid") used as the key to a table.
@@ -3094,7 +3085,7 @@ case OP_NewRowid: {
cnt = 0;
if( (sqlite3BtreeFlags(pC->pCursor)&(BTREE_INTKEY|BTREE_ZERODATA)) !=
BTREE_INTKEY ){
- rc = SQLITE_CORRUPT;
+ rc = SQLITE_CORRUPT_BKPT;
goto abort_due_to_error;
}
assert( (sqlite3BtreeFlags(pC->pCursor) & BTREE_INTKEY)!=0 );
@@ -3464,6 +3455,24 @@ case OP_Last: { /* no-push */
break;
}
+
+/* Opcode: Sort P1 P2 *
+**
+** This opcode does exactly the same thing as OP_Rewind except that
+** it increments an undocumented global variable used for testing.
+**
+** Sorting is accomplished by writing records into a sorting index,
+** then rewinding that index and playing it back from beginning to
+** end. We use the OP_Sort opcode instead of OP_Rewind to do the
+** rewinding so that the global variable will be incremented and
+** regression tests can determine whether or not the optimizer is
+** correctly optimizing out sorts.
+*/
+case OP_Sort: { /* no-push */
+ sqlite3_sort_count++;
+ sqlite3_search_count--;
+ /* Fall through into OP_Rewind */
+}
/* Opcode: Rewind P1 P2 *
**
** The next use of the Rowid or Column or Next instruction for P1
@@ -3685,13 +3694,12 @@ case OP_IdxLT: /* no-push */
case OP_IdxGT: /* no-push */
case OP_IdxGE: { /* no-push */
int i= pOp->p1;
- BtCursor *pCrsr;
Cursor *pC;
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
assert( pTos>=p->aStack );
- if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
+ if( (pC = p->apCsr[i])->pCursor!=0 ){
int res, rc;
assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */
@@ -4023,31 +4031,6 @@ case OP_FifoRead: {
break;
}
-#ifndef SQLITE_OMIT_SUBQUERY
-/* Opcode: AggContextPush * * *
-**
-** Save the state of the current aggregator. It is restored an
-** AggContextPop opcode.
-**
-*/
-case OP_AggContextPush: { /* no-push */
- p->pAgg++;
- assert( p->pAgg<&p->apAgg[p->nAgg] );
- break;
-}
-
-/* Opcode: AggContextPop * * *
-**
-** Restore the aggregator to the state it was in when AggContextPush
-** was last called. Any data in the current aggregator is deleted.
-*/
-case OP_AggContextPop: { /* no-push */
- p->pAgg--;
- assert( p->pAgg>=p->apAgg );
- break;
-}
-#endif
-
#ifndef SQLITE_OMIT_TRIGGER
/* Opcode: ContextPush * * *
**
@@ -4063,7 +4046,7 @@ case OP_ContextPush: { /* no-push */
/* FIX ME: This should be allocated as part of the vdbe at compile-time */
if( i>=p->contextStackDepth ){
p->contextStackDepth = i+1;
- p->contextStack = sqliteRealloc(p->contextStack, sizeof(Context)*(i+1));
+ sqlite3ReallocOrFree((void**)&p->contextStack, sizeof(Context)*(i+1));
if( p->contextStack==0 ) goto no_mem;
}
pContext = &p->contextStack[i];
@@ -4091,108 +4074,6 @@ case OP_ContextPop: { /* no-push */
}
#endif /* #ifndef SQLITE_OMIT_TRIGGER */
-/* Opcode: SortInsert * * *
-**
-** The TOS is the key and the NOS is the data. Pop both from the stack
-** and put them on the sorter. The key and data should have been
-** made using the MakeRecord opcode.
-*/
-case OP_SortInsert: { /* no-push */
- Mem *pNos = &pTos[-1];
- Sorter *pSorter;
- assert( pNos>=p->aStack );
- if( Dynamicify(pTos, db->enc) ) goto no_mem;
- pSorter = sqliteMallocRaw( sizeof(Sorter) );
- if( pSorter==0 ) goto no_mem;
- pSorter->pNext = 0;
- if( p->pSortTail ){
- p->pSortTail->pNext = pSorter;
- }else{
- p->pSort = pSorter;
- }
- p->pSortTail = pSorter;
- assert( pTos->flags & MEM_Dyn );
- pSorter->nKey = pTos->n;
- pSorter->zKey = pTos->z;
- pSorter->data.flags = MEM_Null;
- rc = sqlite3VdbeMemMove(&pSorter->data, pNos);
- pTos -= 2;
- break;
-}
-
-/* Opcode: Sort * * P3
-**
-** Sort all elements on the sorter. The algorithm is a
-** mergesort. The P3 argument is a pointer to a KeyInfo structure
-** that describes the keys to be sorted.
-*/
-case OP_Sort: { /* no-push */
- int i;
- KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3;
- Sorter *pElem;
- Sorter *apSorter[NSORT];
- sqlite3_sort_count++;
- pKeyInfo->enc = p->db->enc;
- for(i=0; i<NSORT; i++){
- apSorter[i] = 0;
- }
- while( p->pSort ){
- pElem = p->pSort;
- p->pSort = pElem->pNext;
- pElem->pNext = 0;
- for(i=0; i<NSORT-1; i++){
- if( apSorter[i]==0 ){
- apSorter[i] = pElem;
- break;
- }else{
- pElem = Merge(apSorter[i], pElem, pKeyInfo);
- apSorter[i] = 0;
- }
- }
- if( i>=NSORT-1 ){
- apSorter[NSORT-1] = Merge(apSorter[NSORT-1],pElem, pKeyInfo);
- }
- }
- pElem = 0;
- for(i=0; i<NSORT; i++){
- pElem = Merge(apSorter[i], pElem, pKeyInfo);
- }
- p->pSort = pElem;
- break;
-}
-
-/* Opcode: SortNext * P2 *
-**
-** Push the data for the topmost element in the sorter onto the
-** stack, then remove the element from the sorter. If the sorter
-** is empty, push nothing on the stack and instead jump immediately
-** to instruction P2.
-*/
-case OP_SortNext: {
- Sorter *pSorter = p->pSort;
- CHECK_FOR_INTERRUPT;
- if( pSorter!=0 ){
- p->pSort = pSorter->pNext;
- pTos++;
- pTos->flags = MEM_Null;
- rc = sqlite3VdbeMemMove(pTos, &pSorter->data);
- sqliteFree(pSorter->zKey);
- sqliteFree(pSorter);
- }else{
- pc = pOp->p2 - 1;
- }
- break;
-}
-
-/* Opcode: SortReset * * *
-**
-** Remove any elements that remain on the sorter.
-*/
-case OP_SortReset: { /* no-push */
- sqlite3VdbeSorterReset(p);
- break;
-}
-
/* Opcode: MemStore P1 P2 *
**
** Write the top of the stack into memory location P1.
@@ -4296,64 +4177,49 @@ case OP_IfMemPos: { /* no-push */
break;
}
-/* Opcode: AggReset P1 P2 P3
+/* Opcode: MemNull P1 * *
**
-** Reset the current aggregator context so that it no longer contains any
-** data. Future aggregator elements will contain P2 values each and be sorted
-** using the KeyInfo structure pointed to by P3.
-**
-** If P1 is non-zero, then only a single aggregator row is available (i.e.
-** there is no GROUP BY expression). In this case it is illegal to invoke
-** OP_AggFocus.
+** Store a NULL in memory cell P1
*/
-case OP_AggReset: { /* no-push */
- assert( !pOp->p3 || pOp->p3type==P3_KEYINFO );
- if( pOp->p1 ){
- rc = sqlite3VdbeAggReset(0, p->pAgg, (KeyInfo *)pOp->p3);
- p->pAgg->nMem = pOp->p2; /* Agg.nMem is used by AggInsert() */
- rc = AggInsert(p->pAgg, 0, 0);
- }else{
- rc = sqlite3VdbeAggReset(db, p->pAgg, (KeyInfo *)pOp->p3);
- p->pAgg->nMem = pOp->p2;
- }
- if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
- }
- p->pAgg->apFunc = sqliteMalloc( p->pAgg->nMem*sizeof(p->pAgg->apFunc[0]) );
- if( p->pAgg->apFunc==0 ) goto no_mem;
+case OP_MemNull: {
+ assert( pOp->p1>=0 && pOp->p1<p->nMem );
+ sqlite3VdbeMemSetNull(&p->aMem[pOp->p1]);
break;
}
-/* Opcode: AggInit P1 P2 P3
+/* Opcode: MemInt P1 P2 *
**
-** Initialize the function parameters for an aggregate function.
-** The aggregate will operate out of aggregate column P2.
-** P3 is a pointer to the FuncDef structure for the function.
+** Store the integer value P1 in memory cell P2.
+*/
+case OP_MemInt: {
+ assert( pOp->p2>=0 && pOp->p2<p->nMem );
+ sqlite3VdbeMemSetInt64(&p->aMem[pOp->p2], pOp->p1);
+ break;
+}
+
+/* Opcode: MemMove P1 P2 *
**
-** The P1 argument is not used by this opcode. However if the SSE
-** extension is compiled in, P1 is set to the number of arguments that
-** will be passed to the aggregate function, if any. This is used
-** by SSE to select the correct function when (de)serializing statements.
+** Move the content of memory cell P2 over to memory cell P1.
+** Any prior content of P1 is erased. Memory cell P2 is left
+** containing a NULL.
*/
-case OP_AggInit: { /* no-push */
- int i = pOp->p2;
- assert( i>=0 && i<p->pAgg->nMem );
- p->pAgg->apFunc[i] = (FuncDef*)pOp->p3;
+case OP_MemMove: {
+ assert( pOp->p1>=0 && pOp->p1<p->nMem );
+ assert( pOp->p2>=0 && pOp->p2<p->nMem );
+ rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], &p->aMem[pOp->p2]);
break;
}
-/* Opcode: AggFunc * P2 P3
+/* Opcode: AggStep P1 P2 P3
**
** Execute the step function for an aggregate. The
** function has P2 arguments. P3 is a pointer to the FuncDef
-** structure that specifies the function.
+** structure that specifies the function. Use memory location
+** P1 as the accumulator.
**
-** The top of the stack must be an integer which is the index of
-** the aggregate column that corresponds to this aggregate function.
-** Ideally, this index would be another parameter, but there are
-** no free parameters left. The integer is popped from the stack.
+** The P2 arguments are popped from the stack.
*/
-case OP_AggFunc: { /* no-push */
+case OP_AggStep: { /* no-push */
int n = pOp->p2;
int i;
Mem *pMem, *pRec;
@@ -4361,24 +4227,18 @@ case OP_AggFunc: { /* no-push */
sqlite3_value **apVal;
assert( n>=0 );
- assert( pTos->flags==MEM_Int );
- pRec = &pTos[-n];
+ pRec = &pTos[1-n];
assert( pRec>=p->aStack );
-
apVal = p->apArg;
assert( apVal || n==0 );
-
for(i=0; i<n; i++, pRec++){
apVal[i] = pRec;
storeTypeInfo(pRec, db->enc);
}
- i = pTos->i;
- assert( i>=0 && i<p->pAgg->nMem );
ctx.pFunc = (FuncDef*)pOp->p3;
- pMem = &p->pAgg->pCurrent->aMem[i];
- ctx.s.z = pMem->zShort; /* Space used for small aggregate contexts */
- ctx.pAgg = pMem->z;
- ctx.cnt = ++pMem->i;
+ assert( pOp->p1>=0 && pOp->p1<p->nMem );
+ ctx.pMem = pMem = &p->aMem[pOp->p1];
+ pMem->n++;
ctx.isError = 0;
ctx.pColl = 0;
if( ctx.pFunc->needCollSeq ){
@@ -4388,182 +4248,34 @@ case OP_AggFunc: { /* no-push */
ctx.pColl = (CollSeq *)pOp[-1].p3;
}
(ctx.pFunc->xStep)(&ctx, n, apVal);
- pMem->z = ctx.pAgg;
- pMem->flags = MEM_AggCtx;
- popStack(&pTos, n+1);
+ popStack(&pTos, n);
if( ctx.isError ){
rc = SQLITE_ERROR;
}
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.
+/* Opcode: AggFinal P1 P2 P3
**
-** The order of aggregator opcodes is important. The order is:
-** AggReset AggFocus AggNext. In other words, you must execute
-** AggReset first, then zero or more AggFocus operations, then
-** zero or more AggNext operations. You must not execute an AggFocus
-** in between an AggNext and an AggReset.
-*/
-case OP_AggFocus: { /* no-push */
- char *zKey;
- int nKey;
- int res;
- assert( pTos>=p->aStack );
- Stringify(pTos, db->enc);
- zKey = pTos->z;
- nKey = pTos->n;
- assert( p->pAgg->pBtree );
- assert( p->pAgg->pCsr );
- rc = sqlite3BtreeMoveto(p->pAgg->pCsr, zKey, nKey, &res);
- if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
- }
- if( res==0 ){
- rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
- (char *)&p->pAgg->pCurrent);
- pc = pOp->p2 - 1;
- }else{
- rc = AggInsert(p->pAgg, zKey, nKey);
- }
- if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
- }
- Release(pTos);
- pTos--;
- break;
-}
-
-/* Opcode: AggSet * P2 *
+** Execute the finalizer function for an aggregate. P1 is
+** the memory location that is the accumulator for the aggregate.
**
-** Move the top of the stack into the P2-th field of the current
-** aggregate. String values are duplicated into new memory.
+** P2 is the number of arguments that the step function takes and
+** P3 is a pointer to the FuncDef for this function. The P2
+** argument is not used by this opcode. It is only there to disambiguate
+** functions that can take varying numbers of arguments. The
+** P3 argument is only needed for the degenerate case where
+** the step function was not previously called.
*/
-case OP_AggSet: { /* no-push */
- AggElem *pFocus;
- int i = pOp->p2;
- pFocus = p->pAgg->pCurrent;
- assert( pTos>=p->aStack );
- if( pFocus==0 ) goto no_mem;
- assert( i>=0 && i<p->pAgg->nMem );
- rc = sqlite3VdbeMemMove(&pFocus->aMem[i], pTos);
- pTos--;
- break;
-}
-
-/* Opcode: AggGet P1 P2 *
-**
-** Push a new entry onto the stack which is a copy of the P2-th field
-** of the current aggregate. Strings are not duplicated so
-** string values will be ephemeral.
-**
-** If P1 is zero, then the value is pulled out of the current aggregate
-** in the current aggregate context. If P1 is greater than zero, then
-** the value is taken from the P1th outer aggregate context. (i.e. if
-** P1==1 then read from the aggregate context that will be restored
-** by the next OP_AggContextPop opcode).
-*/
-case OP_AggGet: {
- AggElem *pFocus;
- int i = pOp->p2;
- Agg *pAgg = &p->pAgg[-pOp->p1];
- assert( pAgg>=p->apAgg );
- pFocus = pAgg->pCurrent;
- if( pFocus==0 ){
- int res;
- if( sqlite3_malloc_failed ) goto no_mem;
- rc = sqlite3BtreeFirst(pAgg->pCsr, &res);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- if( res!=0 ){
- rc = AggInsert(pAgg, "", 1);
- pFocus = pAgg->pCurrent;
- }else{
- rc = sqlite3BtreeData(pAgg->pCsr, 0, 4, (char *)&pFocus);
- }
- }
- assert( i>=0 && i<pAgg->nMem );
- pTos++;
- sqlite3VdbeMemShallowCopy(pTos, &pFocus->aMem[i], MEM_Ephem);
- if( pTos->flags&MEM_Str ){
- sqlite3VdbeChangeEncoding(pTos, db->enc);
- }
+case OP_AggFinal: { /* no-push */
+ Mem *pMem;
+ assert( pOp->p1>=0 && pOp->p1<p->nMem );
+ pMem = &p->aMem[pOp->p1];
+ assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
+ sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3);
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.
-**
-** The order of aggregator opcodes is important. The order is:
-** AggReset AggFocus AggNext. In other words, you must execute
-** AggReset first, then zero or more AggFocus operations, then
-** zero or more AggNext operations. You must not execute an AggFocus
-** in between an AggNext and an AggReset.
-*/
-case OP_AggNext: { /* no-push */
- int res;
- assert( rc==SQLITE_OK );
- CHECK_FOR_INTERRUPT;
- if( p->pAgg->searching==0 ){
- p->pAgg->searching = 1;
- if( p->pAgg->pCsr ){
- rc = sqlite3BtreeFirst(p->pAgg->pCsr, &res);
- }else{
- res = 0;
- }
- }else{
- if( p->pAgg->pCsr ){
- rc = sqlite3BtreeNext(p->pAgg->pCsr, &res);
- }else{
- res = 1;
- }
- }
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
- if( res!=0 ){
- pc = pOp->p2 - 1;
- }else{
- int i;
- sqlite3_context ctx;
- Mem *aMem;
-
- if( p->pAgg->pCsr ){
- rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
- (char *)&p->pAgg->pCurrent);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
- }
- aMem = p->pAgg->pCurrent->aMem;
- for(i=0; i<p->pAgg->nMem; i++){
- FuncDef *pFunc = p->pAgg->apFunc[i];
- Mem *pMem = &aMem[i];
- if( pFunc==0 || pFunc->xFinalize==0 ) continue;
- ctx.s.flags = MEM_Null;
- ctx.s.z = pMem->zShort;
- ctx.pAgg = (void*)pMem->z;
- ctx.cnt = pMem->i;
- ctx.pFunc = pFunc;
- pFunc->xFinalize(&ctx);
- pMem->z = ctx.pAgg;
- if( pMem->z && pMem->z!=pMem->zShort ){
- sqliteFree( pMem->z );
- }
- *pMem = ctx.s;
- if( pMem->flags & MEM_Short ){
- pMem->z = pMem->zShort;
- }
- }
- }
- break;
-}
/* Opcode: Vacuum * * *
**