?? vdbe.c
字號:
pTos->i = ~pTos->i; pTos->flags = MEM_Int; break;}/* Opcode: Noop * * ***** Do nothing. This instruction is often useful as a jump** destination.*/case OP_Noop: { break;}/* Opcode: If P1 P2 ***** Pop a single boolean from the stack. If the boolean popped is** true, then jump to p2. Otherwise continue to the next instruction.** An integer is false if zero and true otherwise. A string is** false if it has zero length and true otherwise.**** If the value popped of the stack is NULL, then take the jump if P1** is true and fall through if P1 is false.*//* Opcode: IfNot P1 P2 ***** Pop a single boolean from the stack. If the boolean popped is** false, then jump to p2. Otherwise continue to the next instruction.** An integer is false if zero and true otherwise. A string is** false if it has zero length and true otherwise.**** If the value popped of the stack is NULL, then take the jump if P1** is true and fall through if P1 is false.*/case OP_If:case OP_IfNot: { int c; assert( pTos>=p->aStack ); if( pTos->flags & MEM_Null ){ c = pOp->p1; }else{ Integerify(pTos); c = pTos->i; if( pOp->opcode==OP_IfNot ) c = !c; } assert( (pTos->flags & MEM_Dyn)==0 ); pTos--; if( c ) pc = pOp->p2-1; break;}/* Opcode: IsNull P1 P2 ***** If any of the top abs(P1) values on the stack are NULL, then jump** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack** unchanged.*/case OP_IsNull: { int i, cnt; Mem *pTerm; cnt = pOp->p1; if( cnt<0 ) cnt = -cnt; pTerm = &pTos[1-cnt]; assert( pTerm>=p->aStack ); for(i=0; i<cnt; i++, pTerm++){ if( pTerm->flags & MEM_Null ){ pc = pOp->p2-1; break; } } if( pOp->p1>0 ) popStack(&pTos, cnt); break;}/* Opcode: NotNull P1 P2 ***** Jump to P2 if the top P1 values on the stack are all not NULL. Pop the** stack if P1 times if P1 is greater than zero. If P1 is less than** zero then leave the stack unchanged.*/case OP_NotNull: { int i, cnt; cnt = pOp->p1; if( cnt<0 ) cnt = -cnt; assert( &pTos[1-cnt] >= p->aStack ); for(i=0; i<cnt && (pTos[1+i-cnt].flags & MEM_Null)==0; i++){} if( i>=cnt ) pc = pOp->p2-1; if( pOp->p1>0 ) popStack(&pTos, cnt); break;}/* Opcode: MakeRecord P1 P2 ***** Convert the top P1 entries of the stack into a single entry** suitable for use as a data record in a database table. The** details of the format are irrelavant as long as the OP_Column** opcode can decode the record later. Refer to source code** comments for the details of the record format.**** If P2 is true (non-zero) and one or more of the P1 entries** that go into building the record is NULL, then add some extra** bytes to the record to make it distinct for other entries created** during the same run of the VDBE. The extra bytes added are a** counter that is reset with each run of the VDBE, so records** created this way will not necessarily be distinct across runs.** But they should be distinct for transient tables (created using** OP_OpenTemp) which is what they are intended for.**** (Later:) The P2==1 option was intended to make NULLs distinct** for the UNION operator. But I have since discovered that NULLs** are indistinct for UNION. So this option is never used.*/case OP_MakeRecord: { char *zNewRecord; int nByte; int nField; int i, j; int idxWidth; u32 addr; Mem *pRec; int addUnique = 0; /* True to cause bytes to be added to make the ** generated record distinct */ char zTemp[NBFS]; /* Temp space for small records */ /* Assuming the record contains N fields, the record format looks ** like this: ** ** ------------------------------------------------------------------- ** | idx0 | idx1 | ... | idx(N-1) | idx(N) | data0 | ... | data(N-1) | ** ------------------------------------------------------------------- ** ** All data fields are converted to strings before being stored and ** are stored with their null terminators. NULL entries omit the ** null terminator. Thus an empty string uses 1 byte and a NULL uses ** zero bytes. Data(0) is taken from the lowest element of the stack ** and data(N-1) is the top of the stack. ** ** Each of the idx() entries is either 1, 2, or 3 bytes depending on ** how big the total record is. Idx(0) contains the offset to the start ** of data(0). Idx(k) contains the offset to the start of data(k). ** Idx(N) contains the total number of bytes in the record. */ nField = pOp->p1; pRec = &pTos[1-nField]; assert( pRec>=p->aStack ); nByte = 0; for(i=0; i<nField; i++, pRec++){ if( pRec->flags & MEM_Null ){ addUnique = pOp->p2; }else{ Stringify(pRec); nByte += pRec->n; } } if( addUnique ) nByte += sizeof(p->uniqueCnt); if( nByte + nField + 1 < 256 ){ idxWidth = 1; }else if( nByte + 2*nField + 2 < 65536 ){ idxWidth = 2; }else{ idxWidth = 3; } nByte += idxWidth*(nField + 1); if( nByte>MAX_BYTES_PER_ROW ){ rc = SQLITE_TOOBIG; goto abort_due_to_error; } if( nByte<=NBFS ){ zNewRecord = zTemp; }else{ zNewRecord = sqliteMallocRaw( nByte ); if( zNewRecord==0 ) goto no_mem; } j = 0; addr = idxWidth*(nField+1) + addUnique*sizeof(p->uniqueCnt); for(i=0, pRec=&pTos[1-nField]; i<nField; i++, pRec++){ zNewRecord[j++] = addr & 0xff; if( idxWidth>1 ){ zNewRecord[j++] = (addr>>8)&0xff; if( idxWidth>2 ){ zNewRecord[j++] = (addr>>16)&0xff; } } if( (pRec->flags & MEM_Null)==0 ){ addr += pRec->n; } } zNewRecord[j++] = addr & 0xff; if( idxWidth>1 ){ zNewRecord[j++] = (addr>>8)&0xff; if( idxWidth>2 ){ zNewRecord[j++] = (addr>>16)&0xff; } } if( addUnique ){ memcpy(&zNewRecord[j], &p->uniqueCnt, sizeof(p->uniqueCnt)); p->uniqueCnt++; j += sizeof(p->uniqueCnt); } for(i=0, pRec=&pTos[1-nField]; i<nField; i++, pRec++){ if( (pRec->flags & MEM_Null)==0 ){ memcpy(&zNewRecord[j], pRec->z, pRec->n); j += pRec->n; } } popStack(&pTos, nField); pTos++; pTos->n = nByte; if( nByte<=NBFS ){ assert( zNewRecord==zTemp ); memcpy(pTos->zShort, zTemp, nByte); pTos->z = pTos->zShort; pTos->flags = MEM_Str | MEM_Short; }else{ assert( zNewRecord!=zTemp ); pTos->z = zNewRecord; pTos->flags = MEM_Str | MEM_Dyn; } break;}/* Opcode: MakeKey P1 P2 P3**** Convert the top P1 entries of the stack into a single entry suitable** for use as the key in an index. The top P1 records are** converted to strings and merged. The null-terminators ** are retained and used as separators.** The lowest entry in the stack is the first field and the top of the** stack becomes the last.**** If P2 is not zero, then the original entries remain on the stack** and the new key is pushed on top. If P2 is zero, the original** data is popped off the stack first then the new key is pushed** back in its place.**** P3 is a string that is P1 characters long. Each character is either** an 'n' or a 't' to indicates if the argument should be intepreted as** numeric or text type. The first character of P3 corresponds to the** lowest element on the stack. If P3 is NULL then all arguments are** assumed to be of the numeric type.**** The type makes a difference in that text-type fields may not be ** introduced by 'b' (as described in the next paragraph). The** first character of a text-type field must be either 'a' (if it is NULL)** or 'c'. Numeric fields will be introduced by 'b' if their content** looks like a well-formed number. Otherwise the 'a' or 'c' will be** used.**** The key is a concatenation of fields. Each field is terminated by** a single 0x00 character. A NULL field is introduced by an 'a' and** is followed immediately by its 0x00 terminator. A numeric field is** introduced by a single character 'b' and is followed by a sequence** of characters that represent the number such that a comparison of** the character string using memcpy() sorts the numbers in numerical** order. The character strings for numbers are generated using the** sqliteRealToSortable() function. A text field is introduced by a** 'c' character and is followed by the exact text of the field. The** use of an 'a', 'b', or 'c' character at the beginning of each field** guarantees that NULLs sort before numbers and that numbers sort** before text. 0x00 characters do not occur except as separators** between fields.**** See also: MakeIdxKey, SortMakeKey*//* Opcode: MakeIdxKey P1 P2 P3**** Convert the top P1 entries of the stack into a single entry suitable** for use as the key in an index. In addition, take one additional integer** off of the stack, treat that integer as a four-byte record number, and** append the four bytes to the key. Thus a total of P1+1 entries are** popped from the stack for this instruction and a single entry is pushed** back. The first P1 entries that are popped are strings and the last** entry (the lowest on the stack) is an integer record number.**** The converstion of the first P1 string entries occurs just like in** MakeKey. Each entry is separated from the others by a null.** The entire concatenation is null-terminated. The lowest entry** in the stack is the first field and the top of the stack becomes the** last.**** If P2 is not zero and one or more of the P1 entries that go into the** generated key is NULL, then jump to P2 after the new key has been** pushed on the stack. In other words, jump to P2 if the key is** guaranteed to be unique. This jump can be used to skip a subsequent** uniqueness test.**** P3 is a string that is P1 characters long. Each character is either** an 'n' or a 't' to indicates if the argument should be numeric or** text. The first character corresponds to the lowest element on the** stack. If P3 is null then all arguments are assumed to be numeric.**** See also: MakeKey, SortMakeKey*/case OP_MakeIdxKey:case OP_MakeKey: { char *zNewKey; int nByte; int nField; int addRowid; int i, j; int containsNull = 0; Mem *pRec; char zTemp[NBFS]; addRowid = pOp->opcode==OP_MakeIdxKey; nField = pOp->p1; pRec = &pTos[1-nField]; assert( pRec>=p->aStack ); nByte = 0; for(j=0, i=0; i<nField; i++, j++, pRec++){ int flags = pRec->flags; int len; char *z; if( flags & MEM_Null ){ nByte += 2; containsNull = 1; }else if( pOp->p3 && pOp->p3[j]=='t' ){ Stringify(pRec); pRec->flags &= ~(MEM_Int|MEM_Real); nByte += pRec->n+1; }else if( (flags & (MEM_Real|MEM_Int))!=0 || sqliteIsNumber(pRec->z) ){ if( (flags & (MEM_Real|MEM_Int))==MEM_Int ){ pRec->r = pRec->i; }else if( (flags & (MEM_Real|MEM_Int))==0 ){ pRec->r = sqliteAtoF(pRec->z, 0); } Release(pRec); z = pRec->zShort; sqliteRealToSortable(pRec->r, z); len = strlen(z); pRec->z = 0; pRec->flags = MEM_Real; pRec->n = len+1; nByte += pRec->n+1; }else{ nByte += pRec->n+1; } } if( nByte+sizeof(u32)>MAX_BYTES_PER_ROW ){ rc = SQLITE_TOOBIG; goto abort_due_to_error; } if( addRowid ) nByte += sizeof(u32); if( nByte<=NBFS ){ zNewKey = zTemp; }else{ zNewKey = sqliteMallocRaw( nByte ); if( zNewKey==0 ) goto no_mem; } j = 0; pRec = &pTos[1-nField]; for(i=0; i<nField; i++, pRec++){ if( pRec->flags & MEM_Null ){ zNewKey[j++] = 'a'; zNewKey[j++] = 0; }else if( pRec->flags==MEM_Real ){ zNewKey[j++] = 'b'; memcpy(&zNewKey[j], pRec->zShort, pRec->n); j += pRec->n; }else{ assert( pRec->flags & MEM_Str ); zNewKey[j++] = 'c'; memcpy(&zNewKey[j], pRec->z, pRec->n); j += pRec->n; } } if( addRowid ){ u32 iKey; pRec = &pTos[-nField]; assert( pRec>=p->aStack ); Integerify(pRec); iKey = intToKey(pRec->i); memcpy(&zNewKey[j], &iKey, sizeof(u32)); popStack(&pTos, nField+1); if( pOp->p2 && containsNull ) pc = pOp->p2 - 1; }else{ if( pOp->p2==0 ) popStack(&pTos, nField); } pTos++; pTos->n = nByte; if( nByte<=NBFS ){ assert( zNewKey==zTemp ); pTos->z = pTos->zShort; memcpy(pTos->zShort, zTemp, nByte); pTos->flags = MEM_Str | MEM_Short; }else{ pTos->z = zNewKey; pTos->flags = MEM_Str | MEM_Dyn; } break;}/* Opcode: IncrKey * * ***** The top of the stack should contain an index key generated by** The MakeKey opcode. This routine increases the least significant** byte of that key by one. This is used so that the MoveTo opcode** will move to the first entry greater than the key rather than to** the key itself.*/case OP_IncrKey: { assert( pTos>=p->aStack ); /* The IncrKey opcode is only applied to keys generated by ** MakeKey or MakeIdxKey and the results of those operands ** are always dynamic strings or zShort[] strings. So we ** are always free to modify the string in place. */ assert( pTos->flags & (MEM_Dyn|MEM_Short) ); pTos->z[pTos->n-1]++; break;}/* Opcode: Checkpoint P1 * ***** Begin a checkpoint. A checkpoint is the beginning of a operation that** is part of a larger transaction but which might need to be rolled back** itself without effecting the containing transaction. A checkpoint will** be automatically committed or rollback when the VDBE halts.**** The checkpoint is begun on the database file with index P1. The main** database file has an index of 0 and the file used for temporary tables** has an index of 1.*/case OP_Checkpoint: { int i = pOp->p1; if( i>=0 && i<db->nDb && db->aDb[i].pBt && db->aDb[i].inTrans==1 ){ rc = sqliteBtreeBeginCkpt(db->aDb[i].pBt); if( rc==SQLITE_OK ) db->aDb[i].inTrans = 2; } bre
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -