Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Back out changes allowing writes to tables that have open cursors. (CVS 2133) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
91acd87e52509a8f78894d0f4b625b54 |
User & Date: | danielk1977 2004-11-22 10:02:10.000 |
Context
2004-11-22
| ||
10:02 | Back out changes allowing writes to tables that have open cursors. (CVS 2134) (check-in: af635cab8a user: danielk1977 tags: trunk) | |
10:02 | Back out changes allowing writes to tables that have open cursors. (CVS 2133) (check-in: 91acd87e52 user: danielk1977 tags: trunk) | |
08:43 | Modify test suite to work when SQLITE_OMIT_VIEW is defined. (CVS 2132) (check-in: 711e8d7695 user: danielk1977 tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: btree.c,v 1.223 2004/11/22 10:02:10 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. |
︙ | ︙ | |||
340 341 342 343 344 345 346 | u16 nSize; /* Size of the cell content on the main b-tree page */ }; /* ** A cursor is a pointer to a particular entry in the BTree. ** The entry is identified by its MemPage and the index in ** MemPage.aCell[] of the entry. | < < < < < < < < < < < | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | u16 nSize; /* Size of the cell content on the main b-tree page */ }; /* ** A cursor is a pointer to a particular entry in the BTree. ** The entry is identified by its MemPage and the index in ** MemPage.aCell[] of the entry. */ struct BtCursor { Btree *pBt; /* The Btree to which this cursor belongs */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */ void *pArg; /* First arg to xCompare() */ Pgno pgnoRoot; /* The root page of this tree */ MemPage *pPage; /* Page that contains the entry */ int idx; /* Index of the entry in pPage->aCell[] */ CellInfo info; /* A parse of the cell we are pointing at */ u8 wrFlag; /* True if writable */ u8 isValid; /* TRUE if points to a valid entry */ u8 status; /* Set to SQLITE_ABORT if cursors is invalidated */ }; /* ** Forward declaration */ static int checkReadLocks(Btree*,Pgno,BtCursor*); |
︙ | ︙ | |||
2121 2122 2123 2124 2125 2126 2127 | if( pCur->pNext ){ pCur->pNext->pPrev = pCur; } pCur->pPrev = 0; pBt->pCursor = pCur; pCur->isValid = 0; pCur->status = SQLITE_OK; | < | 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 | if( pCur->pNext ){ pCur->pNext->pPrev = pCur; } pCur->pPrev = 0; pBt->pCursor = pCur; pCur->isValid = 0; pCur->status = SQLITE_OK; *ppCur = pCur; return SQLITE_OK; create_cursor_exception: if( pCur ){ releasePage(pCur->pPage); sqliteFree(pCur); |
︙ | ︙ | |||
2220 2221 2222 2223 2224 2225 2226 | ** the key for the current entry. If the cursor is not pointing ** to a valid entry, *pSize is set to 0. ** ** For a table with the INTKEY flag set, this routine returns the key ** itself, not the number of bytes in the key. */ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ | | | | 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 | ** the key for the current entry. If the cursor is not pointing ** to a valid entry, *pSize is set to 0. ** ** For a table with the INTKEY flag set, this routine returns the key ** itself, not the number of bytes in the key. */ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ if( !pCur->isValid ){ *pSize = 0; }else{ getCellInfo(pCur); *pSize = pCur->info.nKey; } return SQLITE_OK; } /* ** Set *pSize to the number of bytes of data in the entry the ** cursor currently points to. Always return SQLITE_OK. ** Failure is not possible. If the cursor is not currently ** pointing to an entry (which can happen, for example, if ** the database is empty) then *pSize is set to 0. */ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ if( !pCur->isValid ){ /* Not pointing at a valid entry - set *pSize to 0. */ *pSize = 0; }else{ getCellInfo(pCur); *pSize = pCur->info.nData; } return SQLITE_OK; |
︙ | ︙ | |||
2348 2349 2350 2351 2352 2353 2354 | ** begins at "offset". ** ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ | | | | 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 | ** begins at "offset". ** ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ if( !pCur->isValid ){ return pCur->status; } assert( pCur->pPage!=0 ); assert( pCur->pPage->intKey==0 ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); return getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } /* ** Read part of the data associated with cursor pCur. Exactly ** "amt" bytes will be transfered into pBuf[]. The transfer ** begins at "offset". ** ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ if( !pCur->isValid ){ return pCur->status ? pCur->status : SQLITE_INTERNAL; } assert( pCur->pPage!=0 ); assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell ); return getPayload(pCur, offset, amt, pBuf, 1); } |
︙ | ︙ | |||
2555 2556 2557 2558 2559 2560 2561 | assert( pRoot->pgno==1 ); subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]); assert( subpage>0 ); pCur->isValid = 1; rc = moveToChild(pCur, subpage); } pCur->isValid = pCur->pPage->nCell>0; | < | 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 | assert( pRoot->pgno==1 ); subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]); assert( subpage>0 ); pCur->isValid = 1; rc = moveToChild(pCur, subpage); } pCur->isValid = pCur->pPage->nCell>0; return rc; } /* ** Move the cursor down to the left-most leaf entry beneath the ** entry to which it is currently pointing. */ |
︙ | ︙ | |||
2793 2794 2795 2796 2797 2798 2799 | if( pCur->isValid==0 ){ *pRes = 1; return SQLITE_OK; } assert( pPage->isInit ); assert( pCur->idx<pPage->nCell ); | < < < < < < < < < | 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 | if( pCur->isValid==0 ){ *pRes = 1; return SQLITE_OK; } assert( pPage->isInit ); assert( pCur->idx<pPage->nCell ); pCur->idx++; pCur->info.nSize = 0; if( pCur->idx>=pPage->nCell ){ if( !pPage->leaf ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); if( rc ) return rc; rc = moveToLeftmost(pCur); |
︙ | ︙ | |||
2852 2853 2854 2855 2856 2857 2858 | Pgno pgno; MemPage *pPage; if( pCur->isValid==0 ){ *pRes = 1; return SQLITE_OK; } | < < < < < < < < < | 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 | Pgno pgno; MemPage *pPage; if( pCur->isValid==0 ){ *pRes = 1; return SQLITE_OK; } pPage = pCur->pPage; assert( pPage->isInit ); assert( pCur->idx>=0 ); if( !pPage->leaf ){ pgno = get4byte( findCell(pPage, pCur->idx) ); rc = moveToChild(pCur, pgno); if( rc ) return rc; |
︙ | ︙ | |||
3652 3653 3654 3655 3656 3657 3658 | u8 *apDiv[NB]; /* Divider cells in pParent */ int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */ int szNew[NB+2]; /* Combined size of cells place on i-th page */ u8 **apCell; /* All cells begin balanced */ int *szCell; /* Local size of all cells in apCell[] */ u8 *aCopy[NB]; /* Space for holding data of apCopy[] */ u8 *aSpace; /* Space to hold copies of dividers cells */ | < | 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 | u8 *apDiv[NB]; /* Divider cells in pParent */ int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */ int szNew[NB+2]; /* Combined size of cells place on i-th page */ u8 **apCell; /* All cells begin balanced */ int *szCell; /* Local size of all cells in apCell[] */ u8 *aCopy[NB]; /* Space for holding data of apCopy[] */ u8 *aSpace; /* Space to hold copies of dividers cells */ /* ** Find the parent page. */ assert( pPage->isInit ); assert( sqlite3pager_iswriteable(pPage->aData) ); pBt = pPage->pBt; |
︙ | ︙ | |||
3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 | rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1], 0); if( rc ) goto balance_cleanup; apNew[i] = pNew; } nNew++; zeroPage(pNew, pageFlags); } /* ** Put the new pages in accending order. This helps to ** keep entries in the disk file in order so that a scan ** of the table is a linear scan through the file. That ** in turn helps the operating system to deliver pages ** from the disk more rapidly. | > > > > > > > > > > | 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 | rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1], 0); if( rc ) goto balance_cleanup; apNew[i] = pNew; } nNew++; zeroPage(pNew, pageFlags); } /* Free any old pages that were not reused as new pages. */ while( i<nOld ){ rc = freePage(apOld[i]); if( rc ) goto balance_cleanup; releasePage(apOld[i]); apOld[i] = 0; i++; } /* ** Put the new pages in accending order. This helps to ** keep entries in the disk file in order so that a scan ** of the table is a linear scan through the file. That ** in turn helps the operating system to deliver pages ** from the disk more rapidly. |
︙ | ︙ | |||
3945 3946 3947 3948 3949 3950 3951 | nOld>=3 ? pgnoOld[2] : 0, pgnoNew[0], szNew[0], nNew>=2 ? pgnoNew[1] : 0, nNew>=2 ? szNew[1] : 0, nNew>=3 ? pgnoNew[2] : 0, nNew>=3 ? szNew[2] : 0, nNew>=4 ? pgnoNew[3] : 0, nNew>=4 ? szNew[3] : 0, nNew>=5 ? pgnoNew[4] : 0, nNew>=5 ? szNew[4] : 0)); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 | nOld>=3 ? pgnoOld[2] : 0, pgnoNew[0], szNew[0], nNew>=2 ? pgnoNew[1] : 0, nNew>=2 ? szNew[1] : 0, nNew>=3 ? pgnoNew[2] : 0, nNew>=3 ? szNew[2] : 0, nNew>=4 ? pgnoNew[3] : 0, nNew>=4 ? szNew[3] : 0, nNew>=5 ? pgnoNew[4] : 0, nNew>=5 ? szNew[4] : 0)); /* ** Evenly distribute the data in apCell[] across the new pages. ** Insert divider cells into pParent as necessary. */ j = 0; for(i=0; i<nNew; i++){ MemPage *pNew = apNew[i]; |
︙ | ︙ | |||
4177 4178 4179 4180 4181 4182 4183 | rc = initPage(pChild, pPage); if( rc ) goto end_shallow_balance; assert( pChild->nOverflow==0 ); if( pChild->nFree>=100 ){ /* The child information will fit on the root page, so do the ** copy */ int i; | < < < < < < < < < < < < < < < < < < < < < < < < | 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 | rc = initPage(pChild, pPage); if( rc ) goto end_shallow_balance; assert( pChild->nOverflow==0 ); if( pChild->nFree>=100 ){ /* The child information will fit on the root page, so do the ** copy */ int i; zeroPage(pPage, pChild->aData[0]); for(i=0; i<pChild->nCell; i++){ apCell[i] = findCell(pChild,i); szCell[i] = cellSizePtr(pChild, apCell[i]); } assemblePage(pPage, pChild->nCell, apCell, szCell); freePage(pChild); TRACE(("BALANCE: child %d transfer to page 1\n", pChild->pgno)); }else{ /* The child has more information that will fit on the root. ** The tree is already balanced. Do nothing. */ TRACE(("BALANCE: child %d will not fit on page 1\n", pChild->pgno)); } }else{ memcpy(pPage->aData, pChild->aData, pPage->pBt->usableSize); pPage->isInit = 0; pPage->pParent = 0; rc = initPage(pPage, 0); assert( rc==SQLITE_OK ); freePage(pChild); TRACE(("BALANCE: transfer child %d into root %d\n", pChild->pgno, pPage->pgno)); } rc = reparentChildPages(pPage); if( rc!=SQLITE_OK ) goto end_shallow_balance; releasePage(pChild); } end_shallow_balance: sqliteFree(apCell); |
︙ | ︙ | |||
4253 4254 4255 4256 4257 4258 4259 | Pgno pgnoChild; /* Page number of the new child page */ Btree *pBt; /* The BTree */ int usableSize; /* Total usable size of a page */ u8 *data; /* Content of the parent page */ u8 *cdata; /* Content of the child page */ int hdr; /* Offset to page header in parent */ int brk; /* Offset to content of first cell in parent */ | < | 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 | Pgno pgnoChild; /* Page number of the new child page */ Btree *pBt; /* The BTree */ int usableSize; /* Total usable size of a page */ u8 *data; /* Content of the parent page */ u8 *cdata; /* Content of the child page */ int hdr; /* Offset to page header in parent */ int brk; /* Offset to content of first cell in parent */ assert( pPage->pParent==0 ); assert( pPage->nOverflow>0 ); pBt = pPage->pBt; rc = allocatePage(pBt, &pChild, &pgnoChild, pPage->pgno, 0); if( rc ) return rc; assert( sqlite3pager_iswriteable(pChild->aData) ); |
︙ | ︙ | |||
4280 4281 4282 4283 4284 4285 4286 | if( pChild->nOverflow ){ pChild->nFree = 0; } assert( pChild->nCell==pPage->nCell ); zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF); put4byte(&pPage->aData[pPage->hdrOffset+8], pgnoChild); TRACE(("BALANCE: copy root %d into %d\n", pPage->pgno, pChild->pgno)); | < < < < < < < < < < < < < < < | 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 | if( pChild->nOverflow ){ pChild->nFree = 0; } assert( pChild->nCell==pPage->nCell ); zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF); put4byte(&pPage->aData[pPage->hdrOffset+8], pgnoChild); TRACE(("BALANCE: copy root %d into %d\n", pPage->pgno, pChild->pgno)); rc = balance_nonroot(pChild); releasePage(pChild); return rc; } /* ** Decide if the page pPage needs to be balanced. If balancing is |
︙ | ︙ | |||
4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 | /* ** This routine checks all cursors that point to table pgnoRoot. ** If any of those cursors other than pExclude were opened with ** wrFlag==0 then this routine returns SQLITE_LOCKED. If all ** cursors that point to pgnoRoot were opened with wrFlag==1 ** then this routine returns SQLITE_OK. */ static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){ return SQLITE_OK; } /* ** Insert a new record into the BTree. The key is given by (pKey,nKey) ** and the data is given by (pData,nData). The cursor is used only to ** define what table the record should be inserted into. The cursor | > > > > > > > > > > > > > > > > | 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 | /* ** This routine checks all cursors that point to table pgnoRoot. ** If any of those cursors other than pExclude were opened with ** wrFlag==0 then this routine returns SQLITE_LOCKED. If all ** cursors that point to pgnoRoot were opened with wrFlag==1 ** then this routine returns SQLITE_OK. ** ** In addition to checking for read-locks (where a read-lock ** means a cursor opened with wrFlag==0) this routine also moves ** all cursors other than pExclude so that they are pointing to the ** first Cell on root page. This is necessary because an insert ** or delete might change the number of cells on a page or delete ** a page entirely and we do not want to leave any cursors ** pointing to non-existant pages or cells. */ static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){ BtCursor *p; for(p=pBt->pCursor; p; p=p->pNext){ if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue; if( p->wrFlag==0 ) return SQLITE_LOCKED; if( p->pPage->pgno!=p->pgnoRoot ){ moveToRoot(p); } } return SQLITE_OK; } /* ** Insert a new record into the BTree. The key is given by (pKey,nKey) ** and the data is given by (pData,nData). The cursor is used only to ** define what table the record should be inserted into. The cursor |
︙ | ︙ | |||
4353 4354 4355 4356 4357 4358 4359 | int rc; int loc; int szNew; MemPage *pPage; Btree *pBt = pCur->pBt; unsigned char *oldCell; unsigned char *newCell = 0; | < | 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 | int rc; int loc; int szNew; MemPage *pPage; Btree *pBt = pCur->pBt; unsigned char *oldCell; unsigned char *newCell = 0; if( pCur->status ){ return pCur->status; /* A rollback destroyed this cursor */ } if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction before doing an insert */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; |
︙ | ︙ | |||
4405 4406 4407 4408 4409 4410 4411 | assert( pPage->leaf ); pCur->idx++; pCur->info.nSize = 0; }else{ assert( pPage->leaf ); } rc = insertCell(pPage, pCur->idx, newCell, szNew, 0); | < < < < < < < < < < < < < < < < < < < < > > > < < | 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 | assert( pPage->leaf ); pCur->idx++; pCur->info.nSize = 0; }else{ assert( pPage->leaf ); } rc = insertCell(pPage, pCur->idx, newCell, szNew, 0); if( rc!=SQLITE_OK ) goto end_insert; rc = balance(pPage); /* sqlite3BtreePageDump(pCur->pBt, pCur->pgnoRoot, 1); */ /* fflush(stdout); */ if( rc==SQLITE_OK ){ moveToRoot(pCur); } end_insert: sqliteFree(newCell); return rc; } /* ** Delete the entry that the cursor is pointing to. The cursor ** is left pointing at a random location. */ int sqlite3BtreeDelete(BtCursor *pCur){ MemPage *pPage = pCur->pPage; unsigned char *pCell; int rc; Pgno pgnoChild = 0; Btree *pBt = pCur->pBt; assert( pPage->isInit ); if( pCur->status ){ return pCur->status; /* A rollback destroyed this cursor */ } if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction before doing a delete */ |
︙ | ︙ | |||
4468 4469 4470 4471 4472 4473 4474 | } if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){ return SQLITE_LOCKED; /* The table pCur points to has a read lock */ } rc = sqlite3pager_write(pPage->aData); if( rc ) return rc; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < > < < < < < < > | | | | < < < < < < < | | < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | | | < < < < < < < < < < < < < < | < < | 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 | } if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){ return SQLITE_LOCKED; /* The table pCur points to has a read lock */ } rc = sqlite3pager_write(pPage->aData); if( rc ) return rc; /* Locate the cell within it's page and leave pCell pointing to the ** data. The clearCell() call frees any overflow pages associated with the ** cell. The cell itself is still intact. */ pCell = findCell(pPage, pCur->idx); if( !pPage->leaf ){ pgnoChild = get4byte(pCell); } clearCell(pPage, pCell); if( !pPage->leaf ){ /* ** The entry we are about to delete is not a leaf so if we do not ** do something we will leave a hole on an internal page. ** We have to fill the hole by moving in a cell from a leaf. The ** next Cell after the one to be deleted is guaranteed to exist and ** to be a leaf so we can use it. */ BtCursor leafCur; unsigned char *pNext; int szNext; int notUsed; unsigned char *tempCell; assert( !pPage->leafData ); getTempCursor(pCur, &leafCur); rc = sqlite3BtreeNext(&leafCur, ¬Used); if( rc!=SQLITE_OK ){ if( rc!=SQLITE_NOMEM ){ rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */ } return rc; } rc = sqlite3pager_write(leafCur.pPage->aData); if( rc ) return rc; TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n", pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno)); dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); pNext = findCell(leafCur.pPage, leafCur.idx); szNext = cellSizePtr(leafCur.pPage, pNext); assert( MX_CELL_SIZE(pBt)>=szNext+4 ); tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) ); if( tempCell==0 ) return SQLITE_NOMEM; rc = insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell); if( rc!=SQLITE_OK ) return rc; put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild); rc = balance(pPage); sqliteFree(tempCell); if( rc ) return rc; dropCell(leafCur.pPage, leafCur.idx, szNext); rc = balance(leafCur.pPage); releaseTempCursor(&leafCur); }else{ TRACE(("DELETE: table=%d delete from leaf %d\n", pCur->pgnoRoot, pPage->pgno)); dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); rc = balance(pPage); } moveToRoot(pCur); return rc; } /* ** Create a new BTree table. Write into *piTable the page ** number for the root page of the new table. ** |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** ** $Id: delete.c,v 1.90 2004/11/22 10:02:10 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Look up every table that is named in pSrc. If any table is not found, ** add an error message to pParse->zErrMsg and return NULL. If all tables ** are found, return a pointer to the last table. |
︙ | ︙ | |||
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | Table *pTab /* The table to be opened */ ){ sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); VdbeComment((v, "# %s", pTab->zName)); sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } /* ** Process a DELETE FROM statement. */ void sqlite3DeleteFrom( Parse *pParse, /* The parser context */ SrcList *pTabList, /* The table from which we should delete things */ Expr *pWhere /* The WHERE clause. May be null */ ){ Vdbe *v; /* The virtual database engine */ Table *pTab; /* The table from which records will be deleted */ const char *zDb; /* Name of database holding pTab */ | > | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | Table *pTab /* The table to be opened */ ){ sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); VdbeComment((v, "# %s", pTab->zName)); sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } /* ** Process a DELETE FROM statement. */ void sqlite3DeleteFrom( Parse *pParse, /* The parser context */ SrcList *pTabList, /* The table from which we should delete things */ Expr *pWhere /* The WHERE clause. May be null */ ){ Vdbe *v; /* The virtual database engine */ Table *pTab; /* The table from which records will be deleted */ const char *zDb; /* Name of database holding pTab */ int end, addr = 0; /* A couple addresses of generated code */ int i; /* Loop counter */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Index *pIdx; /* For looping over indices of the table */ int iCur; /* VDBE Cursor number for pTab */ sqlite3 *db; /* Main database structure */ AuthContext sContext; /* Authorization context */ int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ |
︙ | ︙ | |||
145 146 147 148 149 150 151 | /* Allocate a cursor used to store the old.* data for a trigger. */ if( row_triggers_exist ){ oldIdx = pParse->nTab++; } | | < < < < < | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | /* Allocate a cursor used to store the old.* data for a trigger. */ if( row_triggers_exist ){ oldIdx = pParse->nTab++; } /* Resolve the column names in all the expressions. */ assert( pTabList->nSrc==1 ); iCur = pTabList->a[0].iCursor = pParse->nTab++; if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){ goto delete_from_cleanup; } /* Start the view context */ if( isView ){ |
︙ | ︙ | |||
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | else{ /* Ensure all required collation sequences are available. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){ goto delete_from_cleanup; } } /* Open the pseudo-table used to store OLD if there are triggers. */ if( row_triggers_exist ){ sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol); } | > > > > > > > > > > > > > > > > < < < < | | > | < | | | > > > > > > > > > > < | > > > > > | > | > > > | | | > | | > > | > > > > > > > | > > > | > > | | > > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | else{ /* Ensure all required collation sequences are available. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){ goto delete_from_cleanup; } } /* Begin the database scan */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0); if( pWInfo==0 ) goto delete_from_cleanup; /* Remember the key of every item to be deleted. */ sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0); if( db->flags & SQLITE_CountRows ){ sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); } /* End the database scan loop. */ sqlite3WhereEnd(pWInfo); /* Open the pseudo-table used to store OLD if there are triggers. */ if( row_triggers_exist ){ sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol); } /* Delete every item whose key was written to the list during the ** database scan. We have to delete items after the scan is complete ** because deleting an item can change the scan order. */ sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0); end = sqlite3VdbeMakeLabel(v); /* This is the beginning of the delete loop when there are ** row triggers. */ if( row_triggers_exist ){ addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end); sqlite3VdbeAddOp(v, OP_Dup, 0, 0); if( !isView ){ sqlite3OpenTableForReading(v, iCur, pTab); } sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); sqlite3VdbeAddOp(v, OP_RowData, iCur, 0); sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0); if( !isView ){ sqlite3VdbeAddOp(v, OP_Close, iCur, 0); } (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, addr); } if( !isView ){ /* Open cursors for the table we are deleting from and all its ** indices. If there are row triggers, this happens inside the ** OP_ListRead loop because the cursor have to all be closed ** before the trigger fires. If there are no row triggers, the ** cursors are opened only once on the outside the loop. */ sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite); /* This is the beginning of the delete loop when there are no ** row triggers */ if( !row_triggers_exist ){ addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end); } /* Delete the row */ sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0); } /* If there are row triggers, close all cursors then invoke ** the AFTER triggers */ if( row_triggers_exist ){ if( !isView ){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); } sqlite3VdbeAddOp(v, OP_Close, iCur, 0); } (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, addr); } /* End of the delete loop */ sqlite3VdbeAddOp(v, OP_Goto, 0, addr); sqlite3VdbeResolveLabel(v, end); sqlite3VdbeAddOp(v, OP_ListReset, 0, 0); /* Close the cursors after the loop if there are no row triggers */ if( !row_triggers_exist ){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); } sqlite3VdbeAddOp(v, OP_Close, iCur, 0); } } /* ** Return the number of rows that were deleted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.215 2004/11/22 10:02:11 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. |
︙ | ︙ | |||
2519 2520 2521 2522 2523 2524 2525 | }else{ distinct = -1; } /* Begin the database scan */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, | | | 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 | }else{ distinct = -1; } /* Begin the database scan */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, pGroupBy ? 0 : &pOrderBy); if( pWInfo==0 ) goto select_end; /* Use the standard inner loop if we are not dealing with ** aggregates */ if( !isAgg ){ if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest, |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.342 2004/11/22 10:02:11 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** These #defines should enable >2GB file support on Posix if the ** underlying operating system supports it. If the OS lacks |
︙ | ︙ | |||
1310 1311 1312 1313 1314 1315 1316 | Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*, int,int,int); void sqlite3SelectDelete(Select*); void sqlite3SelectUnbind(Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*); | < | | 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 | Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*, int,int,int); void sqlite3SelectDelete(Select*); void sqlite3SelectUnbind(Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*); void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**); void sqlite3WhereEnd(WhereInfo*); void sqlite3ExprCode(Parse*, Expr*); int sqlite3ExprCodeExprList(Parse*, ExprList*); void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); void sqlite3NextedParse(Parse*, const char*, ...); Table *sqlite3FindTable(sqlite3*,const char*, const char*); |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** ** $Id: update.c,v 1.96 2004/11/22 10:02:11 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Process an UPDATE statement. ** ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; |
︙ | ︙ | |||
231 232 233 234 235 236 237 | pView = sqlite3SelectDup(pTab->pSelect); sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0); sqlite3SelectDelete(pView); } /* Begin the database scan */ | | | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | pView = sqlite3SelectDup(pTab->pSelect); sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0); sqlite3SelectDelete(pView); } /* Begin the database scan */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0); if( pWInfo==0 ) goto update_cleanup; /* Remember the index of every item to be updated. */ sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0); /* End the database scan loop. |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** ** $Id: where.c,v 1.118 2004/11/22 10:02:20 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** The query generator uses an array of instances of this structure to ** help it analyze the subexpressions of the WHERE clause. Each WHERE ** clause subexpression is separated from the others by an AND operator. |
︙ | ︙ | |||
477 478 479 480 481 482 483 | ** one. */ WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ SrcList *pTabList, /* A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ int pushKey, /* If TRUE, leave the table key on the stack */ | | < | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | ** one. */ WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ SrcList *pTabList, /* A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ int pushKey, /* If TRUE, leave the table key on the stack */ ExprList **ppOrderBy /* An ORDER BY clause, or NULL */ ){ int i; /* Loop counter */ WhereInfo *pWInfo; /* Will become the return value of this function */ Vdbe *v = pParse->pVdbe; /* The virtual database engine */ int brk, cont = 0; /* Addresses used during code generation */ int nExpr; /* Number of subexpressions in the WHERE clause */ int loopMask; /* One bit set for each outer loop */ |
︙ | ︙ | |||
774 775 776 777 778 779 780 | sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ for(i=0; i<pTabList->nSrc; i++){ Table *pTab; Index *pIx; pTab = pTabList->a[i].pTab; if( pTab->isTransient || pTab->pSelect ) continue; | < | < | 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 | sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ for(i=0; i<pTabList->nSrc; i++){ Table *pTab; Index *pIx; pTab = pTabList->a[i].pTab; if( pTab->isTransient || pTab->pSelect ) continue; sqlite3OpenTableForReading(v, pTabList->a[i].iCursor, pTab); sqlite3CodeVerifySchema(pParse, pTab->iDb); if( (pIx = pWInfo->a[i].pIdx)!=0 ){ sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0); sqlite3VdbeOp3(v, OP_OpenRead, pWInfo->a[i].iCur, pIx->tnum, (char*)&pIx->keyInfo, P3_KEYINFO); } } |
︙ | ︙ |