Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Cache record headers in the OP_Column opcode. (CVS 1382) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
8d9eab178f285415775060369f372a88 |
User & Date: | drh 2004-05-14 21:12:23.000 |
Context
2004-05-14
| ||
21:59 | Allocates VDBE cursors one by one in separate memory so that pointers to cursors can persist through a realloc(). (CVS 1383) (check-in: d8bacc1680 user: drh tags: trunk) | |
21:12 | Cache record headers in the OP_Column opcode. (CVS 1382) (check-in: 8d9eab178f user: drh tags: trunk) | |
19:08 | More speed improvements. (CVS 1381) (check-in: cf75cac9b6 user: drh 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.139 2004/05/14 21:12:23 drh 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. |
︙ | ︙ | |||
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 | ** function above. */ static void releaseTempCursor(BtCursor *pCur){ if( pCur->pPage ){ sqlite3pager_unref(pCur->pPage->aData); } } /* ** Set *pSize to the size of the buffer needed to hold the value of ** 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){ | > > > > > > > > > > > > > > > > > < < < > | < < < < < < < < < < < < < < < | < < < < | < < < < < < < < < | 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 | ** function above. */ static void releaseTempCursor(BtCursor *pCur){ if( pCur->pPage ){ sqlite3pager_unref(pCur->pPage->aData); } } /* ** Make sure the BtCursor.info field of the given cursor is valid. */ static void getCellInfo(BtCursor *pCur){ MemPage *pPage = pCur->pPage; if( !pCur->infoValid ){ parseCell(pPage, pPage->aCell[pCur->idx], &pCur->info); pCur->infoValid = 1; }else{ #ifndef NDEBUG CellInfo info; parseCell(pPage, pPage->aCell[pCur->idx], &info); assert( memcmp(&info, &pCur->info, sizeof(info))==0 ); #endif } } /* ** Set *pSize to the size of the buffer needed to hold the value of ** 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; } /* ** Read payload information from the entry that the pCur cursor is ** pointing to. Begin reading the payload at "offset" and read |
︙ | ︙ | |||
1551 1552 1553 1554 1555 1556 1557 | assert( pCur!=0 && pCur->pPage!=0 ); assert( pCur->isValid ); pBt = pCur->pBt; pPage = pCur->pPage; pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); aPayload = pPage->aCell[pCur->idx]; | < < < < < | < < < < | 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 | assert( pCur!=0 && pCur->pPage!=0 ); assert( pCur->isValid ); pBt = pCur->pBt; pPage = pCur->pPage; pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); aPayload = pPage->aCell[pCur->idx]; getCellInfo(pCur); aPayload += pCur->info.nHeader; if( pPage->intKey ){ nKey = 0; }else{ nKey = pCur->info.nKey; } assert( offset>=0 ); |
︙ | ︙ | |||
1699 1700 1701 1702 1703 1704 1705 | assert( pCur!=0 && pCur->pPage!=0 ); assert( pCur->isValid ); pBt = pCur->pBt; pPage = pCur->pPage; pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); aPayload = pPage->aCell[pCur->idx]; | < < < < < | < < < < | 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 | assert( pCur!=0 && pCur->pPage!=0 ); assert( pCur->isValid ); pBt = pCur->pBt; pPage = pCur->pPage; pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idx<pPage->nCell ); aPayload = pPage->aCell[pCur->idx]; getCellInfo(pCur); aPayload += pCur->info.nHeader; if( pPage->intKey ){ nKey = 0; }else{ nKey = pCur->info.nKey; } if( skipKey ){ |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** ** $Id: vdbe.c,v 1.292 2004/05/14 21:12:23 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include "vdbeInt.h" /* |
︙ | ︙ | |||
1871 1872 1873 1874 1875 1876 1877 | 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; } | | < < < | 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 | 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: Column P1 P2 * ** ** 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 the KeyAsData opcode has previously executed on this cursor, then the |
︙ | ︙ | |||
1901 1902 1903 1904 1905 1906 1907 | Cursor *pC; char *zRec; /* Pointer to record-data from stack or pseudo-table. */ BtCursor *pCrsr; char *zData; int freeZdata = 0; /* zData requires sqliteFree() */ | | < > > > > | | < > > | | | | | | > > | | | | | | | | > > > > > | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | < | | | < < < < < < < < < | | | < | | | | > > | > > > > > | | | < < | < | < | 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 | Cursor *pC; char *zRec; /* Pointer to record-data from stack or pseudo-table. */ BtCursor *pCrsr; char *zData; int freeZdata = 0; /* zData requires sqliteFree() */ u64 nField; /* number of fields in the record */ int len; /* The length of the serialized data for the column */ int offset; int nn; assert( i<p->nCursor ); pTos++; /* This block sets the variable payloadSize, and if the data is coming ** from the stack or from a pseudo-table zRec. If the data is coming ** from a real cursor, then zRec is left as NULL. */ if( i<0 ){ assert( &pTos[i]>=p->aStack ); assert( pTos[i].flags & MEM_Str ); zRec = pTos[i].z; payloadSize = pTos[i].n; pC->cacheValid = 0; }else if( (pC = &p->aCsr[i])->pCursor!=0 ){ sqlite3VdbeCursorMoveto(pC); zRec = 0; pCrsr = pC->pCursor; if( pC->nullRow ){ payloadSize = 0; }else if( pC->cacheValid ){ payloadSize = pC->payloadSize; }else if( pC->keyAsData ){ i64 payloadSize64; sqlite3BtreeKeySize(pCrsr, &payloadSize64); payloadSize = payloadSize64; }else{ sqlite3BtreeDataSize(pCrsr, &payloadSize); } }else if( pC->pseudoTable ){ payloadSize = pC->nData; zRec = pC->pData; pC->cacheValid = 0; assert( payloadSize==0 || zRec!=0 ); }else{ payloadSize = 0; } /* If payloadSize is 0, then just push a NULL onto the stack. */ if( payloadSize==0 ){ pTos->flags = MEM_Null; break; } /* Read and parse the table header. Store the results of the parse ** into the record header cache fields of the cursor. */ if( !pC->cacheValid ){ pC->payloadSize = payloadSize; if( zRec ){ zData = zRec; }else{ /* We can assume that 9 bytes (maximum length of a varint) fits ** on the main page in all cases. */ int n = 9; if( payloadSize<9 ) n = payloadSize; if( pC->keyAsData ){ zData = (char *)sqlite3BtreeKeyFetch(pCrsr, n); }else{ zData = (char *)sqlite3BtreeDataFetch(pCrsr, n); } assert( zData ); } offset = sqlite3GetVarint(zData, &nField); if( nField>pC->nField ){ sqliteFree(pC->aType); pC->aType = sqliteMallocRaw( nField*sizeof(pC->aType[0]) ); if( pC->aType==0 ){ goto no_mem; } } pC->nField = nField; if( !zRec ){ /* If the record is stored in a table, see if enough of it is on ** the main page to use sqlite3BtreeDataFetch() to get the data ** containing the nField serial types (varints). This will almost ** always work, but if it doesn't sqliteMalloc() space and use ** sqlite3BtreeData(). ** ** Estimate the maximum space required by the nField varints by ** assuming the maximum space for each is the length required to store: ** ** (<record length> * 2) + 13 ** ** This is the serial-type for a text object as long as the record ** itself. In all cases the length required to store this is three ** bytes or less. */ int max_space = sqlite3VarintLen((((u64)payloadSize)<<1)+13)*nField; max_space += offset; if( max_space>payloadSize ){ max_space = payloadSize; } if( pC->keyAsData ){ zData = (char *)sqlite3BtreeKeyFetch(pCrsr, max_space); }else{ zData = (char *)sqlite3BtreeDataFetch(pCrsr, max_space); } if( !zData ){ /* This code will run very infrequently (e.g. tables with several ** hundred columns). */ zData = (char *)sqliteMallocRaw(max_space); if( !zData ){ goto no_mem; } if( pC->keyAsData ){ rc = sqlite3BtreeKey(pCrsr, 0, max_space, zData); }else{ rc = sqlite3BtreeData(pCrsr, 0, max_space, zData); } if( rc!=SQLITE_OK ){ sqliteFree(zData); goto abort_due_to_error; } freeZdata = 1; } } /* Read all the serial types for the record. At the end of this block ** variable offset is set to the offset to the start of Data0 in the record. */ for(nn=0; nn<nField; nn++){ offset += sqlite3GetVarint(&zData[offset], &pC->aType[nn]); } if( freeZdata ){ freeZdata = 0; sqliteFree(zData); } pC->nHeader = offset; pC->cacheValid = 1; } /* Compute the offset from the beginning of the record to the beginning ** of the data. And get the length of the data. */ offset = pC->nHeader; for(nn=0; nn<p2; nn++){ offset += sqlite3VdbeSerialTypeLen(pC->aType[nn]); } len = sqlite3VdbeSerialTypeLen(pC->aType[p2]); if( !zRec ){ /* If the record is stored in a table, see if enough of it ** is on the main page to read our column using ** sqlite3BtreeDataFetch(). If not sqliteMalloc() space and read data ** with sqlite3BtreeData(). */ if( pC->keyAsData ){ zData = (char *)sqlite3BtreeKeyFetch(pCrsr, offset+len); }else{ zData = (char *)sqlite3BtreeDataFetch(pCrsr, offset+len); } if( !zData ){ zData = (char *)sqliteMallocRaw(len); if( !zData ){ goto no_mem; } if( pC->keyAsData ){ rc = sqlite3BtreeKey(pCrsr, offset, len, zData); }else{ rc = sqlite3BtreeData(pCrsr, offset, len, zData); } if( rc!=SQLITE_OK ){ sqliteFree( zData ); goto abort_due_to_error; } freeZdata = 1; offset = 0; } } /* Deserialize the value directly into the top of the stack */ sqlite3VdbeSerialGet(&zData[offset], pC->aType[p2], pTos); if( freeZdata ){ sqliteFree(zData); } break; } /* Opcode MakeRecord P1 * P3 |
︙ | ︙ | |||
2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 | } Stringify(pTos); sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); pC->incrKey = 0; pC->recnoIsValid = 0; } pC->deferredMoveto = 0; pC->incrKey = 0; sqlite3_search_count++; oc = pOp->opcode; if( oc==OP_MoveTo && res<0 ){ sqlite3BtreeNext(pC->pCursor, &res); pC->recnoIsValid = 0; if( res && pOp->p2>0 ){ | > | 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 | } Stringify(pTos); sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); pC->incrKey = 0; pC->recnoIsValid = 0; } pC->deferredMoveto = 0; pC->cacheValid = 0; pC->incrKey = 0; sqlite3_search_count++; oc = pOp->opcode; if( oc==OP_MoveTo && res<0 ){ sqlite3BtreeNext(pC->pCursor, &res); pC->recnoIsValid = 0; if( res && pOp->p2>0 ){ |
︙ | ︙ | |||
2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 | if( (pC = &p->aCsr[i])->pCursor!=0 ){ int res, rx; assert( pC->intKey==0 ); Stringify(pTos); rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); alreadyExists = rx==SQLITE_OK && res==0; pC->deferredMoveto = 0; } if( pOp->opcode==OP_Found ){ if( alreadyExists ) pc = pOp->p2 - 1; }else{ if( !alreadyExists ) pc = pOp->p2 - 1; } if( pOp->opcode!=OP_Distinct ){ | > | 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 | if( (pC = &p->aCsr[i])->pCursor!=0 ){ int res, rx; assert( pC->intKey==0 ); Stringify(pTos); rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); alreadyExists = rx==SQLITE_OK && res==0; pC->deferredMoveto = 0; pC->cacheValid = 0; } if( pOp->opcode==OP_Found ){ if( alreadyExists ) pc = pOp->p2 - 1; }else{ if( !alreadyExists ) pc = pOp->p2 - 1; } if( pOp->opcode!=OP_Distinct ){ |
︙ | ︙ | |||
2964 2965 2966 2967 2968 2969 2970 | assert( nKey >= 2 ); len = nKey-2; while( zKey[len] && --len ); /* Search for an entry in P1 where all but the last four bytes match K. ** If there is no such entry, jump immediately to P2. */ | | > | 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 | assert( nKey >= 2 ); len = nKey-2; while( zKey[len] && --len ); /* Search for an entry in P1 where all but the last four bytes match K. ** If there is no such entry, jump immediately to P2. */ assert( pCx->deferredMoveto==0 ); pCx->cacheValid = 0; rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; if( res<0 ){ rc = sqlite3BtreeNext(pCrsr, &res); if( res ){ pc = pOp->p2 - 1; break; |
︙ | ︙ | |||
3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 | ** operation assumes the key is an integer and NotFound assumes it ** is a string. ** ** See also: Distinct, Found, MoveTo, NotFound, IsUnique */ case OP_NotExists: { int i = pOp->p1; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); | > | | | | > | | 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 | ** operation assumes the key is an integer and NotFound assumes it ** is a string. ** ** See also: Distinct, Found, MoveTo, NotFound, IsUnique */ case OP_NotExists: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){ int res, rx; u64 iKey; assert( pTos->flags & MEM_Int ); assert( p->aCsr[i].intKey ); iKey = intToKey(pTos->i); rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res); pC->lastRecno = pTos->i; pC->recnoIsValid = res==0; pC->nullRow = 0; pC->cacheValid = 0; if( rx!=SQLITE_OK || res!=0 ){ pc = pOp->p2 - 1; pC->recnoIsValid = 0; } } Release(pTos); pTos--; break; } |
︙ | ︙ | |||
3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 | if( rx==SQLITE_OK && res==0 ){ rc = SQLITE_FULL; goto abort_due_to_error; } } pC->recnoIsValid = 0; pC->deferredMoveto = 0; } pTos++; pTos->i = v; pTos->flags = MEM_Int; break; } | > | 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 | if( rx==SQLITE_OK && res==0 ){ rc = SQLITE_FULL; goto abort_due_to_error; } } pC->recnoIsValid = 0; pC->deferredMoveto = 0; pC->cacheValid = 0; } pTos++; pTos->i = v; pTos->flags = MEM_Int; break; } |
︙ | ︙ | |||
3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 | } pC->nullRow = 0; }else{ rc = sqlite3BtreeInsert(pC->pCursor, zKey, nKey, pTos->z, pTos->n); } pC->recnoIsValid = 0; pC->deferredMoveto = 0; } popStack(&pTos, 2); break; } /* Opcode: Delete P1 P2 * ** | > | 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 | } pC->nullRow = 0; }else{ rc = sqlite3BtreeInsert(pC->pCursor, zKey, nKey, pTos->z, pTos->n); } pC->recnoIsValid = 0; pC->deferredMoveto = 0; pC->cacheValid = 0; } popStack(&pTos, 2); break; } /* Opcode: Delete P1 P2 * ** |
︙ | ︙ | |||
3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 | Cursor *pC; assert( i>=0 && i<p->nCursor ); pC = &p->aCsr[i]; if( pC->pCursor!=0 ){ sqlite3VdbeCursorMoveto(pC); rc = sqlite3BtreeDelete(pC->pCursor); pC->nextRowidValid = 0; } if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++; if( pOp->p2 & OPFLAG_CSCHANGE ) db->csChange++; break; } /* Opcode: SetCounts * * * | > | 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 | Cursor *pC; assert( i>=0 && i<p->nCursor ); pC = &p->aCsr[i]; if( pC->pCursor!=0 ){ sqlite3VdbeCursorMoveto(pC); rc = sqlite3BtreeDelete(pC->pCursor); pC->nextRowidValid = 0; pC->cacheValid = 0; } if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++; if( pOp->p2 & OPFLAG_CSCHANGE ) db->csChange++; break; } /* Opcode: SetCounts * * * |
︙ | ︙ | |||
3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 | assert( i>=0 && i<p->nCursor ); pC = &p->aCsr[i]; if( (pCrsr = pC->pCursor)!=0 ){ int res; rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = res; pC->deferredMoveto = 0; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } }else{ pC->nullRow = 0; } break; | > | 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 | assert( i>=0 && i<p->nCursor ); pC = &p->aCsr[i]; if( (pCrsr = pC->pCursor)!=0 ){ int res; rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = res; pC->deferredMoveto = 0; pC->cacheValid = 0; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } }else{ pC->nullRow = 0; } break; |
︙ | ︙ | |||
3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 | assert( i>=0 && i<p->nCursor ); pC = &p->aCsr[i]; if( (pCrsr = pC->pCursor)!=0 ){ rc = sqlite3BtreeFirst(pCrsr, &res); pC->atFirst = res==0; pC->deferredMoveto = 0; }else{ res = 1; } pC->nullRow = res; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } | > | 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 | assert( i>=0 && i<p->nCursor ); pC = &p->aCsr[i]; if( (pCrsr = pC->pCursor)!=0 ){ rc = sqlite3BtreeFirst(pCrsr, &res); pC->atFirst = res==0; pC->deferredMoveto = 0; pC->cacheValid = 0; }else{ res = 1; } pC->nullRow = res; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } |
︙ | ︙ | |||
3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 | if( pC->nullRow ){ res = 1; }else{ assert( pC->deferredMoveto==0 ); rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : sqlite3BtreePrevious(pCrsr, &res); pC->nullRow = res; } if( res==0 ){ pc = pOp->p2 - 1; sqlite3_search_count++; } }else{ pC->nullRow = 1; | > | 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 | if( pC->nullRow ){ res = 1; }else{ assert( pC->deferredMoveto==0 ); rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : sqlite3BtreePrevious(pCrsr, &res); pC->nullRow = res; pC->cacheValid = 0; } if( res==0 ){ pc = pOp->p2 - 1; sqlite3_search_count++; } }else{ pC->nullRow = 1; |
︙ | ︙ | |||
3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 | ** If P2==1, then the key must be unique. If the key is not unique, ** the program aborts with a SQLITE_CONSTRAINT error and the database ** is rolled back. If P3 is not null, then it becomes part of the ** error message returned with the SQLITE_CONSTRAINT. */ case OP_IdxPut: { int i = pOp->p1; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); assert( pTos->flags & MEM_Str ); | > | | | | > > | | > | 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 | ** If P2==1, then the key must be unique. If the key is not unique, ** the program aborts with a SQLITE_CONSTRAINT error and the database ** is rolled back. If P3 is not null, then it becomes part of the ** error message returned with the SQLITE_CONSTRAINT. */ case OP_IdxPut: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); assert( pTos->flags & MEM_Str ); if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){ int nKey = pTos->n; const char *zKey = pTos->z; if( pOp->p2 ){ int res; int len; u64 n; /* 'len' is the length of the key minus the rowid at the end */ len = nKey-2; while( zKey[len] && --len ); rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; while( res!=0 ){ int c; sqlite3BtreeKeySize(pCrsr, &n); if( n==nKey && sqlite3VdbeIdxKeyCompare(pC, len, zKey, 0, &c)==SQLITE_OK && c==0 ){ rc = SQLITE_CONSTRAINT; if( pOp->p3 && pOp->p3[0] ){ sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0); } goto abort_due_to_error; } if( res<0 ){ sqlite3BtreeNext(pCrsr, &res); res = +1; }else{ break; } } } assert( pC->intKey==0 ); rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0); assert( pC->deferredMoveto==0 ); pC->cacheValid = 0; } Release(pTos); pTos--; break; } /* Opcode: IdxDelete P1 * * ** ** The top of the stack is an index key built using the MakeIdxKey opcode. ** This opcode removes that entry from the index. */ case OP_IdxDelete: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( pTos->flags & MEM_Str ); assert( i>=0 && i<p->nCursor ); if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){ int rx, res; rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res); if( rx==SQLITE_OK && res==0 ){ rc = sqlite3BtreeDelete(pCrsr); } assert( pC->deferredMoveto==0 ); pC->cacheValid = 0; } Release(pTos); pTos--; break; } /* Opcode: IdxRecno P1 * * |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
74 75 76 77 78 79 80 81 82 83 84 85 86 87 | Bool zeroData; /* True if table contains keys only - no data */ Bool incrKey; /* Searches on the table simulate OP_IncrKey */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ Btree *pBt; /* Separate file holding temporary table */ int nData; /* Number of bytes in pData */ char *pData; /* Data for a NEW or OLD pseudo-table */ i64 iKey; /* Key for the NEW or OLD pseudo-table row */ }; typedef struct Cursor Cursor; /* ** A sorter builds a list of elements to be sorted. Each element of ** the list is an instance of the following structure. */ | > > > > > > > > | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | Bool zeroData; /* True if table contains keys only - no data */ Bool incrKey; /* Searches on the table simulate OP_IncrKey */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ Btree *pBt; /* Separate file holding temporary table */ int nData; /* Number of bytes in pData */ char *pData; /* Data for a NEW or OLD pseudo-table */ i64 iKey; /* Key for the NEW or OLD pseudo-table row */ /* Cached information about the header for the data record that the ** cursor is currently pointing to */ Bool cacheValid; /* True if the cache is valid */ int nField; /* Number of fields in the header */ int nHeader; /* Number of bytes in the entire header */ int payloadSize; /* Total number of bytes in the record */ u64 *aType; /* Type values for all entries in the record */ }; typedef struct Cursor Cursor; /* ** A sorter builds a list of elements to be sorted. Each element of ** the list is an instance of the following structure. */ |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
731 732 733 734 735 736 737 738 739 740 741 742 743 744 | if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } if( pCx->pBt ){ sqlite3BtreeClose(pCx->pBt); } sqliteFree(pCx->pData); memset(pCx, 0, sizeof(Cursor)); } /* ** Close all cursors */ static void closeAllCursors(Vdbe *p){ | > | 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } if( pCx->pBt ){ sqlite3BtreeClose(pCx->pBt); } sqliteFree(pCx->pData); sqliteFree(pCx->aType); memset(pCx, 0, sizeof(Cursor)); } /* ** Close all cursors */ static void closeAllCursors(Vdbe *p){ |
︙ | ︙ | |||
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 | p->lastRecno = keyToInt(p->movetoTarget); p->recnoIsValid = res==0; if( res<0 ){ sqlite3BtreeNext(p->pCursor, &res); } sqlite3_search_count++; p->deferredMoveto = 0; } return SQLITE_OK; } /* ** FIX ME ** | > | 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 | p->lastRecno = keyToInt(p->movetoTarget); p->recnoIsValid = res==0; if( res<0 ){ sqlite3BtreeNext(p->pCursor, &res); } sqlite3_search_count++; p->deferredMoveto = 0; p->cacheValid = 0; } return SQLITE_OK; } /* ** FIX ME ** |
︙ | ︙ |
Changes to test/limit.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the LIMIT ... OFFSET ... clause # of SELECT statements. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the LIMIT ... OFFSET ... clause # of SELECT statements. # # $Id: limit.test,v 1.12 2004/05/14 21:12:24 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Build some test data # set fd [open data1.txt w] |
︙ | ︙ | |||
86 87 88 89 90 91 92 93 94 95 96 97 98 99 | do_test limit-3.1 { execsql { SELECT z FROM (SELECT y*10+x AS z FROM t1 ORDER BY x LIMIT 10) ORDER BY z LIMIT 5; } } {50 51 52 53 54} do_test limit-4.1 { execsql { BEGIN; CREATE TABLE t3(x); INSERT INTO t3 SELECT x FROM t1 ORDER BY x LIMIT 10 OFFSET 1; INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; | > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | do_test limit-3.1 { execsql { SELECT z FROM (SELECT y*10+x AS z FROM t1 ORDER BY x LIMIT 10) ORDER BY z LIMIT 5; } } {50 51 52 53 54} btree_breakpoint do_test limit-4.1 { execsql { BEGIN; CREATE TABLE t3(x); INSERT INTO t3 SELECT x FROM t1 ORDER BY x LIMIT 10 OFFSET 1; INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; |
︙ | ︙ |