📄 vdbe.c
字号:
*/case OP_SetNumColumns: { /* no-push */ Cursor *pC; assert( (pOp->p1)<p->nCursor ); assert( p->apCsr[pOp->p1]!=0 ); pC = p->apCsr[pOp->p1]; pC->nField = pOp->p2; break;}/* Opcode: Column P1 P2 P3**** Interpret the data that cursor P1 points to as a structure built using** the MakeRecord instruction. (See the MakeRecord opcode for additional** information about the format of the data.) Push onto the stack the value** of the P2-th column contained in the data. If there are less that (P2+1) ** values in the record, push a NULL onto the stack.**** If the KeyAsData opcode has previously executed on this cursor, then the** field might be extracted from the key rather than the data.**** If P1 is negative, then the record is stored on the stack rather than in** a table. For P1==-1, the top of the stack is used. For P1==-2, the** next on the stack is used. And so forth. The value pushed is always** just a pointer into the record which is stored further down on the** stack. The column value is not copied. The number of columns in the** record is stored on the stack just above the record itself.*/case OP_Column: { u32 payloadSize; /* Number of bytes in the record */ int p1 = pOp->p1; /* P1 value of the opcode */ int p2 = pOp->p2; /* column number to retrieve */ Cursor *pC = 0; /* The VDBE cursor */ char *zRec; /* Pointer to complete record-data */ BtCursor *pCrsr; /* The BTree cursor */ u32 *aType; /* aType[i] holds the numeric type of the i-th column */ u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ u32 nField; /* number of fields in the record */ u32 szHdr; /* Number of bytes in the record header */ int len; /* The length of the serialized data for the column */ int offset = 0; /* Offset into the data */ int idx; /* Index into the header */ int i; /* Loop counter */ char *zData; /* Part of the record being decoded */ Mem sMem; /* For storing the record being decoded */ sMem.flags = 0; assert( p1<p->nCursor ); pTos++; pTos->flags = MEM_Null; /* This block sets the variable payloadSize to be the total number of ** bytes in the record. ** ** zRec is set to be the complete text of the record if it is available. ** The complete record text is always available for pseudo-tables and ** when we are decoded a record from the stack. If the record is stored ** in a cursor, the complete record text might be available in the ** pC->aRow cache. Or it might not be. If the data is unavailable, ** zRec is set to NULL. ** ** We also compute the number of columns in the record. For cursors, ** the number of columns is stored in the Cursor.nField element. For ** records on the stack, the next entry down on the stack is an integer ** which is the number of records. */ assert( p1<0 || p->apCsr[p1]!=0 ); if( p1<0 ){ /* Take the record off of the stack */ Mem *pRec = &pTos[p1]; Mem *pCnt = &pRec[-1]; assert( pRec>=p->aStack ); assert( pRec->flags & MEM_Blob ); payloadSize = pRec->n; zRec = pRec->z; assert( pCnt>=p->aStack ); assert( pCnt->flags & MEM_Int ); nField = pCnt->i; pCrsr = 0; }else if( (pC = p->apCsr[p1])->pCursor!=0 ){ /* The record is stored in a B-Tree */ rc = sqlite3VdbeCursorMoveto(pC); if( rc ) goto abort_due_to_error; zRec = 0; pCrsr = pC->pCursor; if( pC->nullRow ){ payloadSize = 0; }else if( pC->cacheValid ){ payloadSize = pC->payloadSize; zRec = pC->aRow; }else if( pC->isIndex ){ i64 payloadSize64; sqlite3BtreeKeySize(pCrsr, &payloadSize64); payloadSize = payloadSize64; }else{ sqlite3BtreeDataSize(pCrsr, &payloadSize); } nField = pC->nField;#ifndef SQLITE_OMIT_TRIGGER }else if( pC->pseudoTable ){ /* The record is the sole entry of a pseudo-table */ payloadSize = pC->nData; zRec = pC->pData; pC->cacheValid = 0; assert( payloadSize==0 || zRec!=0 ); nField = pC->nField; pCrsr = 0;#endif }else{ zRec = 0; payloadSize = 0; pCrsr = 0; nField = 0; } /* If payloadSize is 0, then just push a NULL onto the stack. */ if( payloadSize==0 ){ pTos->flags = MEM_Null; break; } assert( p2<nField ); /* Read and parse the table header. Store the results of the parse ** into the record header cache fields of the cursor. */ if( pC && pC->cacheValid ){ aType = pC->aType; aOffset = pC->aOffset; }else{ int avail; /* Number of bytes of available data */ if( pC && pC->aType ){ aType = pC->aType; }else{ aType = sqliteMallocRaw( 2*nField*sizeof(aType) ); } aOffset = &aType[nField]; if( aType==0 ){ goto no_mem; } /* Figure out how many bytes are in the header */ if( zRec ){ zData = zRec; }else{ if( pC->isIndex ){ zData = (char*)sqlite3BtreeKeyFetch(pCrsr, &avail); }else{ zData = (char*)sqlite3BtreeDataFetch(pCrsr, &avail); } /* If KeyFetch()/DataFetch() managed to get the entire payload, ** save the payload in the pC->aRow cache. That will save us from ** having to make additional calls to fetch the content portion of ** the record. */ if( avail>=payloadSize ){ zRec = pC->aRow = zData; }else{ pC->aRow = 0; } } idx = sqlite3GetVarint32(zData, &szHdr); /* The KeyFetch() or DataFetch() above are fast and will get the entire ** record header in most cases. But they will fail to get the complete ** record header if the record header does not fit on a single page ** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to ** acquire the complete header text. */ if( !zRec && avail<szHdr ){ rc = sqlite3VdbeMemFromBtree(pCrsr, 0, szHdr, pC->isIndex, &sMem); if( rc!=SQLITE_OK ){ goto op_column_out; } zData = sMem.z; } /* Scan the header and use it to fill in the aType[] and aOffset[] ** arrays. aType[i] will contain the type integer for the i-th ** column and aOffset[i] will contain the offset from the beginning ** of the record to the start of the data for the i-th column */ offset = szHdr; assert( offset>0 ); i = 0; while( idx<szHdr && i<nField && offset<=payloadSize ){ aOffset[i] = offset; idx += sqlite3GetVarint32(&zData[idx], &aType[i]); offset += sqlite3VdbeSerialTypeLen(aType[i]); i++; } Release(&sMem); sMem.flags = MEM_Null; /* If i is less that nField, then there are less fields in this ** record than SetNumColumns indicated there are columns in the ** table. Set the offset for any extra columns not present in ** the record to 0. This tells code below to push a NULL onto the ** stack instead of deserializing a value from the record. */ while( i<nField ){ aOffset[i++] = 0; } /* The header should end at the start of data and the data should ** end at last byte of the record. If this is not the case then ** we are dealing with a malformed record. */ if( idx!=szHdr || offset!=payloadSize ){ rc = SQLITE_CORRUPT; goto op_column_out; } /* Remember all aType and aColumn information if we have a cursor ** to remember it in. */ if( pC ){ pC->payloadSize = payloadSize; pC->aType = aType; pC->aOffset = aOffset; pC->cacheValid = 1; } } /* Get the column information. If aOffset[p2] is non-zero, then ** deserialize the value from the record. If aOffset[p2] is zero, ** then there are not enough fields in the record to satisfy the ** request. The value is NULL in this case. */ if( aOffset[p2] ){ assert( rc==SQLITE_OK ); if( zRec ){ zData = &zRec[aOffset[p2]]; }else{ len = sqlite3VdbeSerialTypeLen(aType[p2]); rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex,&sMem); if( rc!=SQLITE_OK ){ goto op_column_out; } zData = sMem.z; } sqlite3VdbeSerialGet(zData, aType[p2], pTos); pTos->enc = db->enc; }else{ if( pOp->p3 ){ sqlite3VdbeMemShallowCopy(pTos, (Mem *)(pOp->p3), MEM_Static); }else{ pTos->flags = MEM_Null; } } /* If we dynamically allocated space to hold the data (in the ** sqlite3VdbeMemFromBtree() call above) then transfer control of that ** dynamically allocated space over to the pTos structure rather. ** This prevents a memory copy. */ if( (sMem.flags & MEM_Dyn)!=0 ){ assert( pTos->flags & MEM_Ephem ); assert( pTos->flags & (MEM_Str|MEM_Blob) ); assert( pTos->z==sMem.z ); assert( sMem.flags & MEM_Term ); pTos->flags &= ~MEM_Ephem; pTos->flags |= MEM_Dyn|MEM_Term; } /* pTos->z might be pointing to sMem.zShort[]. Fix that so that we ** can abandon sMem */ rc = sqlite3VdbeMemMakeWriteable(pTos);op_column_out: /* Release the aType[] memory if we are not dealing with cursor */ if( !pC || !pC->aType ){ sqliteFree(aType); } break;}/* Opcode: MakeRecord P1 P2 P3**** Convert the top abs(P1) entries of the stack into a single entry** suitable for use as a data record in a database table or as a key** in an index. The details of the format are irrelavant as long as** the OP_Column opcode can decode the record later and as long as the** sqlite3VdbeRecordCompare function will correctly compare two encoded** records. Refer to source code comments for the details of the record** format.**** The original stack entries are popped from the stack if P1>0 but** remain on the stack if P1<0.**** The P2 argument is divided into two 16-bit words before it is processed.** If the hi-word is non-zero, then an extra integer is read from the stack** and appended to the record as a varint. If the low-word of P2 is not** zero and one or more of the entries are NULL, then jump to the value of** the low-word of P2. This feature can be used to skip a uniqueness test** on indices.**** P3 may be a string that is P1 characters long. The nth character of the** string indicates the column affinity that should be used for the nth** field of the index key (i.e. the first character of P3 corresponds to the** lowest element on the stack).**** The mapping from character to affinity is as follows:** 'n' = NUMERIC.** 'i' = INTEGER.** 't' = TEXT.** 'o' = NONE.**** If P3 is NULL then all index fields have the affinity NONE.*/case OP_MakeRecord: { /* Assuming the record contains N fields, the record format looks ** like this: ** ** ------------------------------------------------------------------------ ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 | ** ------------------------------------------------------------------------ ** ** Data(0) is taken from the lowest element of the stack and data(N-1) is ** the top of the stack. ** ** Each type field is a varint representing the serial type of the ** corresponding data element (see sqlite3VdbeSerialType()). The ** hdr-size field is also a varint which is the offset from the beginning ** of the record to data0. */ unsigned char *zNewRecord; unsigned char *zCsr; Mem *pRec; Mem *pRowid = 0; int nData = 0; /* Number of bytes of data space */ int nHdr = 0; /* Number of bytes of header space */ int nByte = 0; /* Space required for this record */ int nVarint; /* Number of bytes in a varint */ u32 serial_type; /* Type field */ int containsNull = 0; /* True if any of the data fields are NULL */ char zTemp[NBFS]; /* Space to hold small records */ Mem *pData0; int leaveOnStack; /* If true, leave the entries on the stack */ int nField; /* Number of fields in the record */ int jumpIfNull; /* Jump here if non-zero and any entries are NULL. */ int addRowid; /* True to append a rowid column at the end */ char *zAffinity; /* The affinity string for the record */ leaveOnStack = ((pOp->p1<0)?1:0); nField = pOp->p1 * (leaveOnStack?-1:1); jumpIfNull = (pOp->p2 & 0x00FFFFFF); addRowid = ((pOp->p2>>24) & 0x0000FFFF)?1:0; zAffinity = pOp->p3; pData0 = &pTos[1-nField]; assert( pData0>=p->aStack ); containsNull = 0; /* Loop through the elements that will make up the record to figure ** out how much space is required for the new record. */ for(pRec=pData0; pRec<=pTos; pRec++){ if( zAffinity ){ applyAffinity(pRec, zAffinity[pRec-pData0], db->enc); } if( pRec->flags&MEM_Null ){ containsNull = 1; } serial_type = sqlite3VdbeSerialType(pRec); nData += sqlite3VdbeSerialTypeLen(serial_type); nHdr += sqlite3VarintLen(serial_type); } /* If we have to append a varint rowid to this record, set 'rowid' ** to the value of the rowid and increase nByte by the amount of space ** required to store it and the 0x00 seperator byte. */ if( addRowid ){ pRowid = &pTos[0-nField]; assert( pRowid>=p->aStack ); Integerify(pRowid); serial_type = sqlite3VdbeSerialType(pRowid); nData += sqlite3VdbeSerialTypeLen(serial_type); nHdr += sqlite3VarintLen(serial_type); } /* Add the initial header varint and total the size */ nHdr += nVarint = sqlite3VarintLen(nHdr); if( nVarint<sqlite3VarintLen(nHdr) ){ nHdr++; } nByte = nHdr+nData; /* Allocate space for the new record. */ if( nByte>sizeof(zTemp) ){ zNewRecord = sqliteMallocRaw(nByte); if( !zNewRecord ){ goto no_mem; } }else{ zNewRecord = zTemp; } /* Write the record */ zCsr = zNewRecord; zCsr += sqlite3PutVarint(zCsr, nHdr); for(pRec=pData0; pRec<=pTos; pRec++){ serial_type = sqlite3VdbeSerialType(pRec); zCsr += sqlite3PutVarint(zCsr, serial_type); /* serial type */ } if( addRowid ){ zCsr += sqlite3PutVarint(zCsr, sqlite3VdbeSerialType(pRowid)); } for(pRec=pData0; pRec<=pTos; pRec++){ zCsr += sqlite3VdbeSerialPut(zCsr, pRec); /* serial data */ } if( addRowid ){ zCsr += sqlite3VdbeSerialPut(zCsr, pRowid); } assert( zCsr==(zNewRecord+nByte) ); /* Pop entries off the stack if required. Push the new record on. */ if( !leaveOnStack ){ popStack(&pTos, nField+addRowid); } pTos++; pTos->n = nByte; if( nByte<=sizeof(zTemp) ){ assert( z
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -