mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-18 10:21:03 +03:00
Better integrate the changes on this branch with OP_Insert and OP_IdxInsert.
FossilOrigin-Name: 101cef14910d6e865a94bc870aed599321b893188062a9a61d70a9434992cf23
This commit is contained in:
166
src/btree.c
166
src/btree.c
@@ -8679,7 +8679,7 @@ int sqlite3BtreeInsert(
|
||||
unsigned char *newCell = 0;
|
||||
|
||||
assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND|BTREE_PREFORMAT))==flags );
|
||||
assert( (flags & BTREE_PREFORMAT)==0 || seekResult );
|
||||
assert( (flags & BTREE_PREFORMAT)==0 || seekResult || pCur->pKeyInfo==0 );
|
||||
|
||||
if( pCur->eState==CURSOR_FAULT ){
|
||||
assert( pCur->skipNext!=SQLITE_OK );
|
||||
@@ -8825,14 +8825,21 @@ int sqlite3BtreeInsert(
|
||||
newCell = pBt->pTmpSpace;
|
||||
assert( newCell!=0 );
|
||||
if( flags & BTREE_PREFORMAT ){
|
||||
assert( pX->pData==pBt->pTmpSpace );
|
||||
szNew = pX->nData;
|
||||
if( szNew<4 ) szNew = 4;
|
||||
rc = SQLITE_OK;
|
||||
szNew = pBt->nPreformatSize;
|
||||
if( szNew<4 ) szNew = 4;
|
||||
if( ISAUTOVACUUM && szNew>pPage->maxLocal ){
|
||||
CellInfo info;
|
||||
pPage->xParseCell(pPage, newCell, &info);
|
||||
if( ISAUTOVACUUM && info.nPayload!=info.nLocal ){
|
||||
Pgno ovfl = get4byte(&newCell[szNew-4]);
|
||||
ptrmapPut(pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
rc = fillInCell(pPage, newCell, pX, &szNew);
|
||||
if( rc ) goto end_insert;
|
||||
}
|
||||
if( rc ) goto end_insert;
|
||||
assert( szNew==pPage->xCellSize(pPage, newCell) );
|
||||
assert( szNew <= MX_CELL_SIZE(pBt) );
|
||||
idx = pCur->ix;
|
||||
@@ -8938,97 +8945,88 @@ end_insert:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sqlite3BtreeTransfer(
|
||||
BtCursor *pDest,
|
||||
BtCursor *pSrc,
|
||||
i64 iKey,
|
||||
int seekResult
|
||||
){
|
||||
int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
|
||||
int rc = SQLITE_OK;
|
||||
BtreePayload x;
|
||||
Pager *pSrcPager = pSrc->pBt->pPager;
|
||||
u8 *pCell = pDest->pBt->pTmpSpace;
|
||||
u8 *aOut; /* Pointer to next output buffer */
|
||||
int nOut; /* Size of output buffer aOut[] */
|
||||
BtShared *pBt = pDest->pBt;
|
||||
u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */
|
||||
const u8 *aIn; /* Pointer to next input buffer */
|
||||
int nIn; /* Size of input buffer aIn[] */
|
||||
int nRem; /* Bytes of data still to copy */
|
||||
u8 *pPgnoOut = 0;
|
||||
Pgno ovflIn = 0;
|
||||
DbPage *pPageIn = 0;
|
||||
MemPage *pPageOut = 0;
|
||||
|
||||
memset(&x, 0, sizeof(x));
|
||||
x.nKey = iKey;
|
||||
getCellInfo(pSrc);
|
||||
|
||||
x.pData = pCell;
|
||||
x.nData += putVarint32(pCell, pSrc->info.nPayload);
|
||||
if( pDest->pKeyInfo==0 ) x.nData += putVarint(&pCell[x.nData], iKey);
|
||||
|
||||
nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload);
|
||||
aOut = &pCell[x.nData];
|
||||
aOut += putVarint32(aOut, pSrc->info.nPayload);
|
||||
if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey);
|
||||
nIn = pSrc->info.nLocal;
|
||||
aIn = pSrc->info.pPayload;
|
||||
nRem = pSrc->info.nPayload;
|
||||
if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
|
||||
memcpy(aOut, aIn, nIn);
|
||||
pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace);
|
||||
}else{
|
||||
Pager *pSrcPager = pSrc->pBt->pPager;
|
||||
u8 *pPgnoOut = 0;
|
||||
Pgno ovflIn = 0;
|
||||
DbPage *pPageIn = 0;
|
||||
MemPage *pPageOut = 0;
|
||||
int nOut; /* Size of output buffer aOut[] */
|
||||
|
||||
x.nData += nOut;
|
||||
if( nOut<pSrc->info.nPayload ){
|
||||
pPgnoOut = &pCell[x.nData];
|
||||
x.nData += 4;
|
||||
}
|
||||
|
||||
if( nRem>nIn ){
|
||||
ovflIn = get4byte(&pSrc->info.pPayload[nIn]);
|
||||
}
|
||||
|
||||
do {
|
||||
nRem -= nOut;
|
||||
do{
|
||||
assert( nOut>0 );
|
||||
if( nIn>0 ){
|
||||
int nCopy = MIN(nOut, nIn);
|
||||
memcpy(aOut, aIn, nCopy);
|
||||
nOut -= nCopy;
|
||||
nIn -= nCopy;
|
||||
aOut += nCopy;
|
||||
aIn += nCopy;
|
||||
}
|
||||
if( nOut>0 ){
|
||||
sqlite3PagerUnref(pPageIn);
|
||||
pPageIn = 0;
|
||||
rc = sqlite3PagerGet(pSrcPager, ovflIn, &pPageIn, PAGER_GET_READONLY);
|
||||
if( rc==SQLITE_OK ){
|
||||
aIn = (const u8*)sqlite3PagerGetData(pPageIn);
|
||||
ovflIn = get4byte(aIn);
|
||||
aIn += 4;
|
||||
nIn = pSrc->pBt->usableSize - 4;
|
||||
nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload);
|
||||
pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace);
|
||||
if( nOut<pSrc->info.nPayload ){
|
||||
pPgnoOut = &aOut[nOut];
|
||||
pBt->nPreformatSize += 4;
|
||||
}
|
||||
|
||||
if( nRem>nIn ){
|
||||
ovflIn = get4byte(&pSrc->info.pPayload[nIn]);
|
||||
}
|
||||
|
||||
do {
|
||||
nRem -= nOut;
|
||||
do{
|
||||
assert( nOut>0 );
|
||||
if( nIn>0 ){
|
||||
int nCopy = MIN(nOut, nIn);
|
||||
memcpy(aOut, aIn, nCopy);
|
||||
nOut -= nCopy;
|
||||
nIn -= nCopy;
|
||||
aOut += nCopy;
|
||||
aIn += nCopy;
|
||||
}
|
||||
if( nOut>0 ){
|
||||
sqlite3PagerUnref(pPageIn);
|
||||
pPageIn = 0;
|
||||
rc = sqlite3PagerGet(pSrcPager, ovflIn, &pPageIn, PAGER_GET_READONLY);
|
||||
if( rc==SQLITE_OK ){
|
||||
aIn = (const u8*)sqlite3PagerGetData(pPageIn);
|
||||
ovflIn = get4byte(aIn);
|
||||
aIn += 4;
|
||||
nIn = pSrc->pBt->usableSize - 4;
|
||||
}
|
||||
}
|
||||
}while( rc==SQLITE_OK && nOut>0 );
|
||||
|
||||
if( rc==SQLITE_OK && nRem>0 ){
|
||||
Pgno pgnoNew;
|
||||
MemPage *pNew = 0;
|
||||
rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
|
||||
put4byte(pPgnoOut, pgnoNew);
|
||||
if( ISAUTOVACUUM && pPageOut ){
|
||||
ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc);
|
||||
}
|
||||
releasePage(pPageOut);
|
||||
pPageOut = pNew;
|
||||
if( pPageOut ){
|
||||
pPgnoOut = pPageOut->aData;
|
||||
put4byte(pPgnoOut, 0);
|
||||
aOut = &pPgnoOut[4];
|
||||
nOut = MIN(pBt->usableSize - 4, nRem);
|
||||
}
|
||||
}
|
||||
}while( rc==SQLITE_OK && nOut>0 );
|
||||
|
||||
if( rc==SQLITE_OK && nRem>0 ){
|
||||
Pgno pgnoNew;
|
||||
MemPage *pNew = 0;
|
||||
rc = allocateBtreePage(pDest->pBt, &pNew, &pgnoNew, 0, 0);
|
||||
put4byte(pPgnoOut, pgnoNew);
|
||||
releasePage(pPageOut);
|
||||
pPageOut = pNew;
|
||||
if( pPageOut ){
|
||||
pPgnoOut = pPageOut->aData;
|
||||
put4byte(pPgnoOut, 0);
|
||||
aOut = &pPgnoOut[4];
|
||||
nOut = MIN(pDest->pBt->usableSize - 4, nRem);
|
||||
}
|
||||
}
|
||||
}while( nRem>0 && rc==SQLITE_OK );
|
||||
|
||||
releasePage(pPageOut);
|
||||
sqlite3PagerUnref(pPageIn);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
int flags = BTREE_APPEND|BTREE_PREFORMAT;
|
||||
rc = sqlite3BtreeInsert(pDest, &x, flags, seekResult);
|
||||
}while( nRem>0 && rc==SQLITE_OK );
|
||||
|
||||
releasePage(pPageOut);
|
||||
sqlite3PagerUnref(pPageIn);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -262,7 +262,7 @@ int sqlite3BtreeDelete(BtCursor*, u8 flags);
|
||||
#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */
|
||||
#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */
|
||||
#define BTREE_APPEND 0x08 /* Insert is likely an append */
|
||||
#define BTREE_PREFORMAT 0x10 /* Insert is likely an append */
|
||||
#define BTREE_PREFORMAT 0x80 /* Insert is likely an append */
|
||||
|
||||
/* An instance of the BtreePayload object describes the content of a single
|
||||
** entry in either an index or table btree.
|
||||
@@ -362,7 +362,7 @@ void sqlite3BtreeCursorList(Btree*);
|
||||
int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
|
||||
#endif
|
||||
|
||||
int sqlite3BtreeTransfer(BtCursor*, BtCursor*, i64, int);
|
||||
int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64);
|
||||
|
||||
/*
|
||||
** If we are not using shared cache, then there is no need to
|
||||
|
||||
@@ -455,6 +455,7 @@ struct BtShared {
|
||||
Btree *pWriter; /* Btree with currently open write transaction */
|
||||
#endif
|
||||
u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */
|
||||
int nPreformatSize; /* Size of last cell written by TransferRow() */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
34
src/insert.c
34
src/insert.c
@@ -2748,6 +2748,7 @@ static int xferOptimization(
|
||||
iDest = pParse->nTab++;
|
||||
regAutoinc = autoIncBegin(pParse, iDbDest, pDest);
|
||||
regData = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regData);
|
||||
regRowid = sqlite3GetTempReg(pParse);
|
||||
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
|
||||
assert( HasRowid(pDest) || destHasUniqueIdx );
|
||||
@@ -2797,17 +2798,26 @@ static int xferOptimization(
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
||||
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
|
||||
}
|
||||
|
||||
if( db->mDbFlags & DBFLAG_Vacuum ){
|
||||
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
|
||||
insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
|
||||
sqlite3VdbeAddOp3(v, OP_Transfer, iDest, iSrc, regRowid);
|
||||
insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT;
|
||||
}else{
|
||||
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND;
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
|
||||
(char*)pDest, P4_TABLE);
|
||||
sqlite3VdbeChangeP5(v, insFlags);
|
||||
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND|OPFLAG_PREFORMAT;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
if( db->xPreUpdateCallback ){
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
insFlags &= ~OPFLAG_PREFORMAT;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regRowid);
|
||||
}
|
||||
sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
|
||||
(char*)pDest, P4_TABLE);
|
||||
sqlite3VdbeChangeP5(v, insFlags);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
||||
@@ -2849,18 +2859,18 @@ static int xferOptimization(
|
||||
if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
|
||||
}
|
||||
if( i==pSrcIdx->nColumn ){
|
||||
idxInsFlags = OPFLAG_USESEEKRESULT;
|
||||
idxInsFlags = OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT;
|
||||
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
|
||||
sqlite3VdbeAddOp3(v, OP_Transfer, iDest, iSrc, 0);
|
||||
sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regData);
|
||||
}
|
||||
}else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
|
||||
idxInsFlags |= OPFLAG_NCHANGE;
|
||||
}
|
||||
if( idxInsFlags!=OPFLAG_USESEEKRESULT ){
|
||||
if( idxInsFlags!=(OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT) ){
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
|
||||
sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
|
||||
sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||
|
||||
@@ -3517,6 +3517,7 @@ struct AuthContext {
|
||||
#define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */
|
||||
#define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */
|
||||
#define OPFLAG_NOCHNG_MAGIC 0x6d /* OP_MakeRecord: serialtype 10 is ok */
|
||||
#define OPFLAG_PREFORMAT 0x80 /* OP_Insert uses preformatted cell */
|
||||
|
||||
/*
|
||||
* Each trigger present in the database schema is stored as an instance of
|
||||
|
||||
26
src/vdbe.c
26
src/vdbe.c
@@ -5126,7 +5126,8 @@ case OP_Insert: {
|
||||
}
|
||||
x.pKey = 0;
|
||||
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
|
||||
seekResult
|
||||
);
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
@@ -5143,29 +5144,20 @@ case OP_Insert: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Transfer P1 P2 P3 * *
|
||||
** Synopsis: intkey=r[P3]
|
||||
**
|
||||
** P1 and P2 are both cursors open on either intkey or index btrees. This
|
||||
** instruction reads the current row from P2 and writes it into the
|
||||
** table opened by P1. If P1 and P2 are opened on intkey tables, register
|
||||
** P3 contains the rowid value to use when inserting into P1.
|
||||
/* Opcode: RowCell P1 P2 P3 * *
|
||||
*/
|
||||
case OP_Transfer: {
|
||||
case OP_RowCell: {
|
||||
VdbeCursor *pDest; /* Cursor to write to */
|
||||
VdbeCursor *pSrc; /* Cursor to read from */
|
||||
i64 iKey; /* Rowid value to insert with */
|
||||
|
||||
assert( pOp[1].opcode==OP_Insert || pOp[1].opcode==OP_IdxInsert );
|
||||
pDest = p->apCsr[pOp->p1];
|
||||
pSrc = p->apCsr[pOp->p2];
|
||||
iKey = pOp->p3 ? aMem[pOp->p3].u.i : 0;
|
||||
|
||||
rc = sqlite3BtreeTransfer(
|
||||
pDest->uc.pCursor, pSrc->uc.pCursor, iKey, pDest->seekResult
|
||||
);
|
||||
rc = sqlite3BtreeTransferRow(pDest->uc.pCursor, pSrc->uc.pCursor, iKey);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/* Opcode: Delete P1 P2 P3 P4 P5
|
||||
**
|
||||
@@ -5822,7 +5814,7 @@ case OP_IdxInsert: { /* in2 */
|
||||
assert( pC!=0 );
|
||||
assert( !isSorter(pC) );
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
assert( pIn2->flags & MEM_Blob );
|
||||
assert( (pIn2->flags & MEM_Blob) || (pOp->p5 & OPFLAG_PREFORMAT) );
|
||||
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->isTable==0 );
|
||||
@@ -5833,7 +5825,7 @@ case OP_IdxInsert: { /* in2 */
|
||||
x.aMem = aMem + pOp->p3;
|
||||
x.nMem = (u16)pOp->p4.i;
|
||||
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)),
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
|
||||
((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
|
||||
);
|
||||
assert( pC->deferredMoveto==0 );
|
||||
|
||||
Reference in New Issue
Block a user