⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vdbe.c

📁 sqlite 嵌入式数据库的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
*/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 + -