Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge latest trunk changes into this branch. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | exp-window-functions |
Files: | files | file ages | folders |
SHA3-256: |
6232519899efc568465d8fcc9fcd79d4 |
User & Date: | dan 2018-05-25 09:36:27.522 |
Context
2018-05-25
| ||
20:30 | Fix "RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING" window frame processing. (check-in: b4e9c68669 user: dan tags: exp-window-functions) | |
09:36 | Merge latest trunk changes into this branch. (check-in: 6232519899 user: dan tags: exp-window-functions) | |
09:29 | Fixes for "ROWS BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING" and "ROWS BETWEEN <expr> FOLLOWING AND UNBOUNDED FOLLOWING" (check-in: 5ac44872fd user: dan tags: exp-window-functions) | |
2018-05-24
| ||
23:51 | When doing a one-pass UPDATE or DELETE on virtual tables, close the cursor prior to running VUpdate. This allows one-pass to work on virtual tables that do not allow concurrent reads and writes. Enhance rtree to take advantage of this new capability. (check-in: b816023ce0 user: drh tags: trunk) | |
Changes
Changes to ext/rtree/rtree.c.
︙ | ︙ | |||
129 130 131 132 133 134 135 136 137 138 139 140 141 142 | u8 nAux; /* # of auxiliary columns in %_rowid */ int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ u32 nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ u32 nCursor; /* Number of open cursors */ char *zReadAuxSql; /* SQL for statement to read aux data */ /* List of nodes removed during a CondenseTree operation. List is ** linked together via the pointer normally used for hash chains - ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree ** headed by the node (leaf nodes have RtreeNode.iNode==0). */ | > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | u8 nAux; /* # of auxiliary columns in %_rowid */ int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ u32 nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ u32 nCursor; /* Number of open cursors */ u32 nNodeRef; /* Number RtreeNodes with positive nRef */ char *zReadAuxSql; /* SQL for statement to read aux data */ /* List of nodes removed during a CondenseTree operation. List is ** linked together via the pointer normally used for hash chains - ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree ** headed by the node (leaf nodes have RtreeNode.iNode==0). */ |
︙ | ︙ | |||
530 531 532 533 534 535 536 537 538 539 540 541 542 543 | } /* ** Increment the reference count of node p. */ static void nodeReference(RtreeNode *p){ if( p ){ p->nRef++; } } /* ** Clear the content of node p (set all bytes to 0x00). */ | > | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | } /* ** Increment the reference count of node p. */ static void nodeReference(RtreeNode *p){ if( p ){ assert( p->nRef>0 ); p->nRef++; } } /* ** Clear the content of node p (set all bytes to 0x00). */ |
︙ | ︙ | |||
597 598 599 600 601 602 603 604 605 606 607 608 609 610 | static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ RtreeNode *pNode; pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize); if( pNode ){ memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize); pNode->zData = (u8 *)&pNode[1]; pNode->nRef = 1; pNode->pParent = pParent; pNode->isDirty = 1; nodeReference(pParent); } return pNode; } | > | 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 | static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ RtreeNode *pNode; pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize); if( pNode ){ memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize); pNode->zData = (u8 *)&pNode[1]; pNode->nRef = 1; pRtree->nNodeRef++; pNode->pParent = pParent; pNode->isDirty = 1; nodeReference(pParent); } return pNode; } |
︙ | ︙ | |||
630 631 632 633 634 635 636 | ){ int rc = SQLITE_OK; RtreeNode *pNode = 0; /* Check if the requested node is already in the hash table. If so, ** increase its reference count and return it. */ | | | | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 | ){ int rc = SQLITE_OK; RtreeNode *pNode = 0; /* Check if the requested node is already in the hash table. If so, ** increase its reference count and return it. */ if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){ assert( !pParent || !pNode->pParent || pNode->pParent==pParent ); if( pParent && !pNode->pParent ){ pParent->nRef++; pNode->pParent = pParent; } pNode->nRef++; *ppNode = pNode; return SQLITE_OK; } |
︙ | ︙ | |||
672 673 674 675 676 677 678 679 680 681 682 683 684 685 | pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize); if( !pNode ){ rc = SQLITE_NOMEM; }else{ pNode->pParent = pParent; pNode->zData = (u8 *)&pNode[1]; pNode->nRef = 1; pNode->iNode = iNode; pNode->isDirty = 0; pNode->pNext = 0; rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData, pRtree->iNodeSize, 0); nodeReference(pParent); } | > | 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize); if( !pNode ){ rc = SQLITE_NOMEM; }else{ pNode->pParent = pParent; pNode->zData = (u8 *)&pNode[1]; pNode->nRef = 1; pRtree->nNodeRef++; pNode->iNode = iNode; pNode->isDirty = 0; pNode->pNext = 0; rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData, pRtree->iNodeSize, 0); nodeReference(pParent); } |
︙ | ︙ | |||
712 713 714 715 716 717 718 | if( pNode!=0 ){ nodeHashInsert(pRtree, pNode); }else{ rc = SQLITE_CORRUPT_VTAB; } *ppNode = pNode; }else{ | > > | > | 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 | if( pNode!=0 ){ nodeHashInsert(pRtree, pNode); }else{ rc = SQLITE_CORRUPT_VTAB; } *ppNode = pNode; }else{ if( pNode ){ pRtree->nNodeRef--; sqlite3_free(pNode); } *ppNode = 0; } return rc; } /* |
︙ | ︙ | |||
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 | ** Release a reference to a node. If the node is dirty and the reference ** count drops to zero, the node data is written to the database. */ static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; if( pNode ){ assert( pNode->nRef>0 ); pNode->nRef--; if( pNode->nRef==0 ){ if( pNode->iNode==1 ){ pRtree->iDepth = -1; } if( pNode->pParent ){ rc = nodeRelease(pRtree, pNode->pParent); } if( rc==SQLITE_OK ){ | > > | 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 | ** Release a reference to a node. If the node is dirty and the reference ** count drops to zero, the node data is written to the database. */ static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; if( pNode ){ assert( pNode->nRef>0 ); assert( pRtree->nNodeRef>0 ); pNode->nRef--; if( pNode->nRef==0 ){ pRtree->nNodeRef--; if( pNode->iNode==1 ){ pRtree->iDepth = -1; } if( pNode->pParent ){ rc = nodeRelease(pRtree, pNode->pParent); } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
927 928 929 930 931 932 933 | ** Decrement the r-tree reference count. When the reference count reaches ** zero the structure is deleted. */ static void rtreeRelease(Rtree *pRtree){ pRtree->nBusy--; if( pRtree->nBusy==0 ){ pRtree->inWrTrans = 0; | | > | 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 | ** Decrement the r-tree reference count. When the reference count reaches ** zero the structure is deleted. */ static void rtreeRelease(Rtree *pRtree){ pRtree->nBusy--; if( pRtree->nBusy==0 ){ pRtree->inWrTrans = 0; assert( pRtree->nCursor==0 ); nodeBlobReset(pRtree); assert( pRtree->nNodeRef==0 ); sqlite3_finalize(pRtree->pWriteNode); sqlite3_finalize(pRtree->pDeleteNode); sqlite3_finalize(pRtree->pReadRowid); sqlite3_finalize(pRtree->pWriteRowid); sqlite3_finalize(pRtree->pDeleteRowid); sqlite3_finalize(pRtree->pReadParent); sqlite3_finalize(pRtree->pWriteParent); |
︙ | ︙ | |||
1399 1400 1401 1402 1403 1404 1405 | int ii; pNew = rtreeEnqueue(pCur, rScore, iLevel); if( pNew==0 ) return 0; ii = (int)(pNew - pCur->aPoint) + 1; if( ii<RTREE_CACHE_SZ ){ assert( pCur->aNode[ii]==0 ); pCur->aNode[ii] = pCur->aNode[0]; | | | 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 | int ii; pNew = rtreeEnqueue(pCur, rScore, iLevel); if( pNew==0 ) return 0; ii = (int)(pNew - pCur->aPoint) + 1; if( ii<RTREE_CACHE_SZ ){ assert( pCur->aNode[ii]==0 ); pCur->aNode[ii] = pCur->aNode[0]; }else{ nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]); } pCur->aNode[0] = 0; *pNew = pCur->sPoint; } pCur->sPoint.rScore = rScore; pCur->sPoint.iLevel = iLevel; |
︙ | ︙ | |||
1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 | ** and then a linear search of an R-Tree node. This should be ** considered almost as quick as a direct rowid lookup (for which ** sqlite uses an internal cost of 0.0). It is expected to return ** a single row. */ pIdxInfo->estimatedCost = 30.0; pIdxInfo->estimatedRows = 1; return SQLITE_OK; } if( p->usable && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2) || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){ | > | 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 | ** and then a linear search of an R-Tree node. This should be ** considered almost as quick as a direct rowid lookup (for which ** sqlite uses an internal cost of 0.0). It is expected to return ** a single row. */ pIdxInfo->estimatedCost = 30.0; pIdxInfo->estimatedRows = 1; pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; return SQLITE_OK; } if( p->usable && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2) || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){ |
︙ | ︙ | |||
2469 2470 2471 2472 2473 2474 2475 | pLeft = nodeNew(pRtree, pNode); pRtree->iDepth++; pNode->isDirty = 1; writeInt16(pNode->zData, pRtree->iDepth); }else{ pLeft = pNode; pRight = nodeNew(pRtree, pLeft->pParent); | | | 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 | pLeft = nodeNew(pRtree, pNode); pRtree->iDepth++; pNode->isDirty = 1; writeInt16(pNode->zData, pRtree->iDepth); }else{ pLeft = pNode; pRight = nodeNew(pRtree, pLeft->pParent); pLeft->nRef++; } if( !pLeft || !pRight ){ rc = SQLITE_NOMEM; goto splitnode_out; } |
︙ | ︙ | |||
2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 | /* Re-insert the contents of any underfull nodes removed from the tree. */ for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ if( rc==SQLITE_OK ){ rc = reinsertNodeContent(pRtree, pLeaf); } pRtree->pDeleted = pLeaf->pNext; sqlite3_free(pLeaf); } /* Release the reference to the root node. */ if( rc==SQLITE_OK ){ rc = nodeRelease(pRtree, pRoot); }else{ | > | 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 | /* Re-insert the contents of any underfull nodes removed from the tree. */ for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ if( rc==SQLITE_OK ){ rc = reinsertNodeContent(pRtree, pLeaf); } pRtree->pDeleted = pLeaf->pNext; pRtree->nNodeRef--; sqlite3_free(pLeaf); } /* Release the reference to the root node. */ if( rc==SQLITE_OK ){ rc = nodeRelease(pRtree, pRoot); }else{ |
︙ | ︙ | |||
3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 | sqlite_int64 *pRowid ){ Rtree *pRtree = (Rtree *)pVtab; int rc = SQLITE_OK; RtreeCell cell; /* New cell to insert if nData>1 */ int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ rtreeReference(pRtree); assert(nData>=1); cell.iRowid = 0; /* Used only to suppress a compiler warning */ /* Constraint handling. A write operation on an r-tree table may return ** SQLITE_CONSTRAINT for two reasons: | > > > > > > | 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 | sqlite_int64 *pRowid ){ Rtree *pRtree = (Rtree *)pVtab; int rc = SQLITE_OK; RtreeCell cell; /* New cell to insert if nData>1 */ int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ if( pRtree->nNodeRef ){ /* Unable to write to the btree while another cursor is reading from it, ** since the write might do a rebalance which would disrupt the read ** cursor. */ return SQLITE_LOCKED_VTAB; } rtreeReference(pRtree); assert(nData>=1); cell.iRowid = 0; /* Used only to suppress a compiler warning */ /* Constraint handling. A write operation on an r-tree table may return ** SQLITE_CONSTRAINT for two reasons: |
︙ | ︙ |
Changes to ext/rtree/rtree1.test.
︙ | ︙ | |||
472 473 474 475 476 477 478 | ABORT 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} IGNORE 1 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7 5 8 8 8 8} FAIL 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7 5 8 8 8 8} REPLACE 1 0 {1 1 2 3 4 2 7 7 7 7 3 3 4 5 6 4 4 5 6 7 5 8 8 8 8} } 3 "UPDATE %CONF% t1 SET idx = 2 WHERE idx = 4" { | | | | | | | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | ABORT 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} IGNORE 1 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7 5 8 8 8 8} FAIL 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7 5 8 8 8 8} REPLACE 1 0 {1 1 2 3 4 2 7 7 7 7 3 3 4 5 6 4 4 5 6 7 5 8 8 8 8} } 3 "UPDATE %CONF% t1 SET idx = 2 WHERE idx = 4" { ROLLBACK 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6} ABORT 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} IGNORE 0 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} FAIL 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} REPLACE 0 0 {1 1 2 3 4 2 4 5 6 7 3 3 4 5 6} } 3 "UPDATE %CONF% t1 SET idx = ((idx+1)%5)+1 WHERE idx > 2" { ROLLBACK 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6} ABORT 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} IGNORE 1 0 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} FAIL 1 1 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} |
︙ | ︙ |
Changes to ext/rtree/rtree8.test.
︙ | ︙ | |||
34 35 36 37 38 39 40 | do_test rtree8-1.1.1 { execsql { PRAGMA page_size = 512 } execsql { CREATE VIRTUAL TABLE t1 USING rtree_i32(id, x1, x2) } populate_t1 5 } {} do_test rtree8-1.1.2 { set res [list] | > | | | | > > | > > > > > > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | do_test rtree8-1.1.1 { execsql { PRAGMA page_size = 512 } execsql { CREATE VIRTUAL TABLE t1 USING rtree_i32(id, x1, x2) } populate_t1 5 } {} do_test rtree8-1.1.2 { set res [list] set rc [catch { db eval { SELECT * FROM t1 } { lappend res $x1 $x2 if {$id==3} { db eval { DELETE FROM t1 WHERE id>3 } } } } msg]; lappend rc $msg set rc } {1 {database table is locked}} do_test rtree8-1.1.2b { db eval { SELECT * FROM t1 ORDER BY +id } { if {$id==3} { db eval { DELETE FROM t1 WHERE id>3 } } } db eval {SELECT x1, x2 FROM t1} } {1 3 2 4 3 5} do_test rtree8-1.1.3 { execsql { SELECT * FROM t1 } } {1 1 3 2 2 4 3 3 5} # Many SELECTs on the same small table. # |
︙ | ︙ | |||
165 166 167 168 169 170 171 172 | execsql BEGIN for {set i 0} {$i < 200} {incr i} { execsql { DELETE FROM t2 WHERE id = $i } } execsql COMMIT } {} do_rtree_integrity_test rtree8-5.5 t2 | > > > > | > > > > > > > > > > > > > > > > > > > > | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | execsql BEGIN for {set i 0} {$i < 200} {incr i} { execsql { DELETE FROM t2 WHERE id = $i } } execsql COMMIT } {} do_rtree_integrity_test rtree8-5.5 t2 # 2018-05-24 # The following script caused an assertion fault and/or segfault # prior to the fix that prevents simultaneous reads and writes on # the same rtree virtual table. # do_test rtree8-6.1 { db close sqlite3 db :memory: db eval { PRAGMA page_size=512; CREATE VIRTUAL TABLE t1 USING rtree(id,x1,x2,y1,y2); WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<49) INSERT INTO t1 SELECT x, x, x+1, x, x+1 FROM c; } set rc [catch { db eval {SELECT id FROM t1} x { db eval {DELETE FROM t1 WHERE id=$x(id)} } } msg] lappend rc $msg } {1 {database table is locked}} finish_test |
Changes to src/delete.c.
︙ | ︙ | |||
549 550 551 552 553 554 555 | } /* Delete the row */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); | < < | > > | | > > > | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | } /* Delete the row */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); sqlite3MayAbort(pParse); if( eOnePass==ONEPASS_SINGLE ){ sqlite3VdbeAddOp1(v, OP_Close, iTabCur); if( sqlite3IsToplevel(pParse) ){ pParse->isMultiWrite = 0; } } sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB); sqlite3VdbeChangeP5(v, OE_Abort); }else #endif { int count = (pParse->nested==0); /* True to count changes */ sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]); } |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | */ static int autoIncBegin( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database holding pTab */ Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ if( (pTab->tabFlags & TF_Autoincrement)!=0 && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); AutoincInfo *pInfo; pInfo = pToplevel->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } if( pInfo==0 ){ pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo)); if( pInfo==0 ) return 0; pInfo->pNext = pToplevel->pAinc; | > > > > > > > > > > > > > > > | 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 | */ static int autoIncBegin( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database holding pTab */ Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ assert( pParse->db->aDb[iDb].pSchema!=0 ); if( (pTab->tabFlags & TF_Autoincrement)!=0 && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); AutoincInfo *pInfo; Table *pSeqTab = pParse->db->aDb[iDb].pSchema->pSeqTab; /* Verify that the sqlite_sequence table exists and is an ordinary ** rowid table with exactly two columns. ** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */ if( pSeqTab==0 || !HasRowid(pSeqTab) || IsVirtual(pSeqTab) || pSeqTab->nCol!=2 ){ pParse->nErr++; pParse->rc = SQLITE_CORRUPT_SEQUENCE; return 0; } pInfo = pToplevel->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } if( pInfo==0 ){ pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo)); if( pInfo==0 ) return 0; pInfo->pNext = pToplevel->pAinc; |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) #define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8)) #define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) | > > | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) #define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8)) #define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) |
︙ | ︙ | |||
8529 8530 8531 8532 8533 8534 8535 | /* ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE ** ** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn] ** method of a [virtual table], then it returns true if and only if the ** column is being fetched as part of an UPDATE operation during which the ** column value will not change. Applications might use this to substitute | | | | | 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 | /* ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE ** ** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn] ** method of a [virtual table], then it returns true if and only if the ** column is being fetched as part of an UPDATE operation during which the ** column value will not change. Applications might use this to substitute ** a return value that is less expensive to compute and that the corresponding ** [xUpdate] method understands as a "no-change" value. ** ** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that ** the column is not changed by the UPDATE statement, then the xColumn ** method can optionally return without setting a result, without calling ** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces]. ** In that case, [sqlite3_value_nochange(X)] will return true for the ** same column in the [xUpdate] method. */ int sqlite3_vtab_nochange(sqlite3_context*); |
︙ | ︙ |
Changes to src/test_malloc.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | ** by malloc() fault simulation. */ static struct MemFault { int iCountdown; /* Number of pending successes before a failure */ int nRepeat; /* Number of times to repeat the failure */ int nBenign; /* Number of benign failures seen since last config */ int nFail; /* Number of failures seen since last config */ u8 enable; /* True if enabled */ int isInstalled; /* True if the fault simulation layer is installed */ int isBenignMode; /* True if malloc failures are considered benign */ sqlite3_mem_methods m; /* 'Real' malloc implementation */ } memfault; /* ** This routine exists as a place to set a breakpoint that will ** fire on any simulated malloc() failure. */ static void sqlite3Fault(void){ static int cnt = 0; cnt++; } /* ** Check to see if a fault should be simulated. Return true to simulate ** the fault. Return false if the fault should not be simulated. */ static int faultsimStep(void){ if( likely(!memfault.enable) ){ return 0; } if( memfault.iCountdown>0 ){ memfault.iCountdown--; return 0; } sqlite3Fault(); memfault.nFail++; if( memfault.isBenignMode>0 ){ memfault.nBenign++; } memfault.nRepeat--; if( memfault.nRepeat<=0 ){ | > > > > > > > > > > > > > > > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 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 | ** by malloc() fault simulation. */ static struct MemFault { int iCountdown; /* Number of pending successes before a failure */ int nRepeat; /* Number of times to repeat the failure */ int nBenign; /* Number of benign failures seen since last config */ int nFail; /* Number of failures seen since last config */ int nOkBefore; /* Successful allocations prior to the first fault */ int nOkAfter; /* Successful allocations after a fault */ u8 enable; /* True if enabled */ int isInstalled; /* True if the fault simulation layer is installed */ int isBenignMode; /* True if malloc failures are considered benign */ sqlite3_mem_methods m; /* 'Real' malloc implementation */ } memfault; /* ** This routine exists as a place to set a breakpoint that will ** fire on any simulated malloc() failure. */ static void sqlite3Fault(void){ static int cnt = 0; cnt++; } /* ** This routine exists as a place to set a breakpoint that will ** fire the first time any malloc() fails on a single test case. ** The sqlite3Fault() routine above runs on every malloc() failure. ** This routine only runs on the first such failure. */ static void sqlite3FirstFault(void){ static int cnt2 = 0; cnt2++; } /* ** Check to see if a fault should be simulated. Return true to simulate ** the fault. Return false if the fault should not be simulated. */ static int faultsimStep(void){ if( likely(!memfault.enable) ){ memfault.nOkAfter++; return 0; } if( memfault.iCountdown>0 ){ memfault.iCountdown--; memfault.nOkBefore++; return 0; } if( memfault.nFail==0 ) sqlite3FirstFault(); sqlite3Fault(); memfault.nFail++; if( memfault.isBenignMode>0 ){ memfault.nBenign++; } memfault.nRepeat--; if( memfault.nRepeat<=0 ){ |
︙ | ︙ | |||
129 130 131 132 133 134 135 136 137 138 139 140 141 142 | ** to succeed again. */ static void faultsimConfig(int nDelay, int nRepeat){ memfault.iCountdown = nDelay; memfault.nRepeat = nRepeat; memfault.nBenign = 0; memfault.nFail = 0; memfault.enable = nDelay>=0; /* Sometimes, when running multi-threaded tests, the isBenignMode ** variable is not properly incremented/decremented so that it is ** 0 when not inside a benign malloc block. This doesn't affect ** the multi-threaded tests, as they do not use this system. But ** it does affect OOM tests run later in the same process. So | > > | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | ** to succeed again. */ static void faultsimConfig(int nDelay, int nRepeat){ memfault.iCountdown = nDelay; memfault.nRepeat = nRepeat; memfault.nBenign = 0; memfault.nFail = 0; memfault.nOkBefore = 0; memfault.nOkAfter = 0; memfault.enable = nDelay>=0; /* Sometimes, when running multi-threaded tests, the isBenignMode ** variable is not properly incremented/decremented so that it is ** 0 when not inside a benign malloc block. This doesn't affect ** the multi-threaded tests, as they do not use this system. But ** it does affect OOM tests run later in the same process. So |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
841 842 843 844 845 846 847 | WhereInfo *pWInfo; int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */ int regArg; /* First register in VUpdate arg array */ int regRec; /* Register in which to assemble record */ int regRowid; /* Register for ephem table rowid */ int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */ int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */ | | | 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 | WhereInfo *pWInfo; int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */ int regArg; /* First register in VUpdate arg array */ int regRec; /* Register in which to assemble record */ int regRowid; /* Register for ephem table rowid */ int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */ int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */ int eOnePass; /* True to use onepass strategy */ int addr; /* Address of OP_OpenEphemeral */ /* Allocate nArg registers in which to gather the arguments for VUpdate. Then ** create and open the ephemeral table in which the records created from ** these arguments will be temporarily stored. */ assert( v ); ephemTab = pParse->nTab++; |
︙ | ︙ | |||
886 887 888 889 890 891 892 | assert( pPk!=0 ); assert( pPk->nKeyCol==1 ); iPk = pPk->aiColumn[0]; sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg); sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1); } | | > > > | > | | | 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 | assert( pPk!=0 ); assert( pPk->nKeyCol==1 ); iPk = pPk->aiColumn[0]; sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg); sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1); } eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy); /* There is no ONEPASS_MULTI on virtual tables */ assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); if( eOnePass ){ /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded ** above. */ sqlite3VdbeChangeToNoop(v, addr); sqlite3VdbeAddOp1(v, OP_Close, iCsr); }else{ /* Create a record from the argument register contents and insert it into ** the ephemeral table. */ sqlite3MultiWrite(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec); #ifdef SQLITE_DEBUG /* Signal an assert() within OP_MakeRecord that it is allowed to ** accept no-change records with serial_type 10 */ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC); #endif sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid); } if( eOnePass==ONEPASS_OFF ){ /* End the virtual table scan */ sqlite3WhereEnd(pWInfo); /* Begin scannning through the ephemeral table. */ addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v); /* Extract arguments from the current row of the ephemeral table and ** invoke the VUpdate method. */ for(i=0; i<nArg; i++){ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i, regArg+i); } } sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 0, nArg, regArg, pVTab, P4_VTAB); sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); sqlite3MayAbort(pParse); /* End of the ephemeral table scan. Or, if using the onepass strategy, ** jump to here if the scan visited zero rows. */ if( eOnePass==ONEPASS_OFF ){ sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr); sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0); }else{ sqlite3WhereEnd(pWInfo); } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
Changes to src/vdbe.c.
︙ | ︙ | |||
4283 4284 4285 4286 4287 4288 4289 | VdbeFrame *pFrame; /* Root frame of VDBE */ v = 0; res = 0; pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; | < < < < > | 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 | VdbeFrame *pFrame; /* Root frame of VDBE */ v = 0; res = 0; pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->isTable ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); { /* The next rowid or record number (different terms for the same ** thing) is obtained in a two-step algorithm. ** ** First we attempt to find the largest existing rowid and add one |
︙ | ︙ | |||
6747 6748 6749 6750 6751 6752 6753 | ** ** Store in register P3 the value of the P2-th column of ** the current row of the virtual-table of cursor P1. ** ** If the VColumn opcode is being used to fetch the value of ** an unchanging column during an UPDATE operation, then the P5 ** value is 1. Otherwise, P5 is 0. The P5 value is returned | | | 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 | ** ** Store in register P3 the value of the P2-th column of ** the current row of the virtual-table of cursor P1. ** ** If the VColumn opcode is being used to fetch the value of ** an unchanging column during an UPDATE operation, then the P5 ** value is 1. Otherwise, P5 is 0. The P5 value is returned ** by sqlite3_vtab_nochange() routine and can be used ** by virtual table implementations to return special "no-change" ** marks which can be more efficient, depending on the virtual table. */ case OP_VColumn: { sqlite3_vtab *pVtab; const sqlite3_module *pModule; Mem *pDest; |
︙ | ︙ |
Changes to test/autoinc.test.
︙ | ︙ | |||
679 680 681 682 683 684 685 686 687 | # do_execsql_test autoinc-11.1 { CREATE TABLE t11(a INTEGER PRIMARY KEY AUTOINCREMENT,b UNIQUE); INSERT INTO t11(a,b) VALUES(2,3),(5,6),(4,3),(1,2) ON CONFLICT(b) DO UPDATE SET a=a+1000; SELECT seq FROM sqlite_sequence WHERE name='t11'; } {5} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 | # do_execsql_test autoinc-11.1 { CREATE TABLE t11(a INTEGER PRIMARY KEY AUTOINCREMENT,b UNIQUE); INSERT INTO t11(a,b) VALUES(2,3),(5,6),(4,3),(1,2) ON CONFLICT(b) DO UPDATE SET a=a+1000; SELECT seq FROM sqlite_sequence WHERE name='t11'; } {5} # 2018-05-23 ticket d8dc2b3a58cd5dc2918a1d4acbba4676a23ada4c # Does not crash if the sqlite_sequence table schema is missing # or corrupt. # do_test autoinc-12.1 { db close forcedelete test.db sqlite3 db test.db db eval { CREATE TABLE fake_sequence(name TEXT PRIMARY KEY,seq) WITHOUT ROWID; PRAGMA writable_schema=on; UPDATE sqlite_master SET sql=replace(sql,'fake_','sqlite_'), name='sqlite_sequence', tbl_name='sqlite_sequence' WHERE name='fake_sequence'; } db close sqlite3 db test.db set res [catch {db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT); INSERT INTO t1(b) VALUES('one'); }} msg] lappend res $msg } {1 {database disk image is malformed}} do_test autoinc-12.2 { db close forcedelete test.db sqlite3 db test.db db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT); INSERT INTO t1(b) VALUES('one'); PRAGMA writable_schema=on; UPDATE sqlite_master SET sql=replace(sql,'sqlite_','x_'), name='x_sequence', tbl_name='x_sequence' WHERE name='sqlite_sequence'; } db close sqlite3 db test.db set res [catch {db eval { INSERT INTO t1(b) VALUES('two'); }} msg] lappend res $msg } {1 {database disk image is malformed}} do_test autoinc-12.3 { db close forcedelete test.db sqlite3 db test.db db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT); INSERT INTO t1(b) VALUES('one'); PRAGMA writable_schema=on; UPDATE sqlite_master SET sql='CREATE VIRTUAL TABLE sqlite_sequence USING sqlite_dbpage' WHERE name='sqlite_sequence'; } db close sqlite3 db test.db set res [catch {db eval { INSERT INTO t1(b) VALUES('two'); }} msg] lappend res $msg } {1 {database disk image is malformed}} do_test autoinc-12.4 { db close forcedelete test.db sqlite3 db test.db db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT); INSERT INTO t1(b) VALUES('one'); CREATE TABLE fake(name TEXT PRIMARY KEY,seq) WITHOUT ROWID; } set root1 [db one {SELECT rootpage FROM sqlite_master WHERE name='sqlite_sequence'}] set root2 [db one {SELECT rootpage FROM sqlite_master WHERE name='fake'}] db eval { PRAGMA writable_schema=on; UPDATE sqlite_master SET rootpage=$root2 WHERE name='sqlite_sequence'; UPDATE sqlite_master SET rootpage=$root1 WHERE name='fake'; } db close sqlite3 db test.db set res [catch {db eval { INSERT INTO t1(b) VALUES('two'); }} msg] lappend res $msg } {1 {database disk image is malformed}} breakpoint do_test autoinc-12.5 { db close forcedelete test.db sqlite3 db test.db db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT); INSERT INTO t1(b) VALUES('one'); PRAGMA writable_schema=on; UPDATE sqlite_master SET sql='CREATE TABLE sqlite_sequence(x)' WHERE name='sqlite_sequence'; } db close sqlite3 db test.db set res [catch {db eval { INSERT INTO t1(b) VALUES('two'); }} msg] lappend res $msg } {1 {database disk image is malformed}} do_test autoinc-12.6 { db close forcedelete test.db sqlite3 db test.db db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT); INSERT INTO t1(b) VALUES('one'); PRAGMA writable_schema=on; UPDATE sqlite_master SET sql='CREATE TABLE sqlite_sequence(x,y INTEGER PRIMARY KEY)' WHERE name='sqlite_sequence'; } db close sqlite3 db test.db set res [catch {db eval { INSERT INTO t1(b) VALUES('two'),('three'),('four'); INSERT INTO t1(b) VALUES('five'); PRAGMA integrity_check; }} msg] lappend res $msg } {0 ok} do_test autoinc-12.7 { db close forcedelete test.db sqlite3 db test.db db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT); INSERT INTO t1(b) VALUES('one'); PRAGMA writable_schema=on; UPDATE sqlite_master SET sql='CREATE TABLE sqlite_sequence(y INTEGER PRIMARY KEY,x)' WHERE name='sqlite_sequence'; } db close sqlite3 db test.db set res [catch {db eval { INSERT INTO t1(b) VALUES('two'),('three'),('four'); INSERT INTO t1(b) VALUES('five'); PRAGMA integrity_check; }} msg] lappend res $msg } {0 ok} finish_test |
Changes to test/speedtest1.c.
︙ | ︙ | |||
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 | ** A testset for the R-Tree virtual table */ void testset_rtree(int p1, int p2){ unsigned i, n; unsigned mxCoord; unsigned x0, x1, y0, y1, z0, z1; unsigned iStep; int *aCheck = sqlite3_malloc( sizeof(int)*g.szTest*500 ); mxCoord = 15000; | > | | 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 | ** A testset for the R-Tree virtual table */ void testset_rtree(int p1, int p2){ unsigned i, n; unsigned mxCoord; unsigned x0, x1, y0, y1, z0, z1; unsigned iStep; unsigned mxRowid; int *aCheck = sqlite3_malloc( sizeof(int)*g.szTest*500 ); mxCoord = 15000; mxRowid = n = g.szTest*500; speedtest1_begin_test(100, "%d INSERTs into an r-tree", n); speedtest1_exec("BEGIN"); speedtest1_exec("CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1,z0,z1)"); speedtest1_prepare("INSERT INTO rt1(id,x0,x1,y0,y1,z0,z1)" "VALUES(?1,?2,?3,?4,?5,?6,?7)"); for(i=1; i<=n; i++){ twoCoords(p1, p2, mxCoord, &x0, &x1); |
︙ | ︙ | |||
1273 1274 1275 1276 1277 1278 1279 | speedtest1_end_test(); speedtest1_begin_test(101, "Copy from rtree to a regular table"); speedtest1_exec("CREATE TABLE t1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)"); speedtest1_exec("INSERT INTO t1 SELECT * FROM rt1"); speedtest1_end_test(); | | | | | | | 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 | speedtest1_end_test(); speedtest1_begin_test(101, "Copy from rtree to a regular table"); speedtest1_exec("CREATE TABLE t1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)"); speedtest1_exec("INSERT INTO t1 SELECT * FROM rt1"); speedtest1_end_test(); n = g.szTest*200; speedtest1_begin_test(110, "%d one-dimensional intersect slice queries", n); speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x0>=?1 AND x1<=?2"); iStep = mxCoord/n; for(i=0; i<n; i++){ sqlite3_bind_int(g.pStmt, 1, i*iStep); sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); speedtest1_run(); aCheck[i] = atoi(g.zResult); } speedtest1_end_test(); if( g.bVerify ){ n = g.szTest*200; speedtest1_begin_test(111, "Verify result from 1-D intersect slice queries"); speedtest1_prepare("SELECT count(*) FROM t1 WHERE x0>=?1 AND x1<=?2"); iStep = mxCoord/n; for(i=0; i<n; i++){ sqlite3_bind_int(g.pStmt, 1, i*iStep); sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); speedtest1_run(); if( aCheck[i]!=atoi(g.zResult) ){ fatal_error("Count disagree step %d: %d..%d. %d vs %d", i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult)); } } speedtest1_end_test(); } n = g.szTest*200; speedtest1_begin_test(120, "%d one-dimensional overlap slice queries", n); speedtest1_prepare("SELECT count(*) FROM rt1 WHERE y1>=?1 AND y0<=?2"); iStep = mxCoord/n; for(i=0; i<n; i++){ sqlite3_bind_int(g.pStmt, 1, i*iStep); sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); speedtest1_run(); aCheck[i] = atoi(g.zResult); } speedtest1_end_test(); if( g.bVerify ){ n = g.szTest*200; speedtest1_begin_test(121, "Verify result from 1-D overlap slice queries"); speedtest1_prepare("SELECT count(*) FROM t1 WHERE y1>=?1 AND y0<=?2"); iStep = mxCoord/n; for(i=0; i<n; i++){ sqlite3_bind_int(g.pStmt, 1, i*iStep); sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); speedtest1_run(); if( aCheck[i]!=atoi(g.zResult) ){ fatal_error("Count disagree step %d: %d..%d. %d vs %d", i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult)); } } speedtest1_end_test(); } n = g.szTest*200; speedtest1_begin_test(125, "%d custom geometry callback queries", n); sqlite3_rtree_geometry_callback(g.db, "xslice", xsliceGeometryCallback, 0); speedtest1_prepare("SELECT count(*) FROM rt1 WHERE id MATCH xslice(?1,?2)"); iStep = mxCoord/n; for(i=0; i<n; i++){ sqlite3_bind_int(g.pStmt, 1, i*iStep); sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep); |
︙ | ︙ | |||
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 | speedtest1_begin_test(140, "%d rowid queries", n); speedtest1_prepare("SELECT * FROM rt1 WHERE id=?1"); for(i=1; i<=n; i++){ sqlite3_bind_int(g.pStmt, 1, i); speedtest1_run(); } speedtest1_end_test(); } #endif /* SQLITE_ENABLE_RTREE */ /* ** A testset that does key/value storage on tables with many columns. ** This is the kind of workload generated by ORMs such as CoreData. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 | speedtest1_begin_test(140, "%d rowid queries", n); speedtest1_prepare("SELECT * FROM rt1 WHERE id=?1"); for(i=1; i<=n; i++){ sqlite3_bind_int(g.pStmt, 1, i); speedtest1_run(); } speedtest1_end_test(); n = g.szTest*50; speedtest1_begin_test(150, "%d UPDATEs using rowid", n); speedtest1_prepare("UPDATE rt1 SET x0=x0+100, x1=x1+100 WHERE id=?1"); for(i=1; i<=n; i++){ sqlite3_bind_int(g.pStmt, 1, (i*251)%mxRowid + 1); speedtest1_run(); } speedtest1_end_test(); n = g.szTest*5; speedtest1_begin_test(155, "%d UPDATEs using one-dimensional overlap", n); speedtest1_prepare("UPDATE rt1 SET x0=x0-100, x1=x1-100" " WHERE y1>=?1 AND y0<=?1+5"); iStep = mxCoord/n; for(i=0; i<n; i++){ sqlite3_bind_int(g.pStmt, 1, i*iStep); speedtest1_run(); aCheck[i] = atoi(g.zResult); } speedtest1_end_test(); n = g.szTest*50; speedtest1_begin_test(160, "%d DELETEs using rowid", n); speedtest1_prepare("DELETE FROM rt1 WHERE id=?1"); for(i=1; i<=n; i++){ sqlite3_bind_int(g.pStmt, 1, (i*257)%mxRowid + 1); speedtest1_run(); } speedtest1_end_test(); n = g.szTest*5; speedtest1_begin_test(165, "%d DELETEs using one-dimensional overlap", n); speedtest1_prepare("DELETE FROM rt1 WHERE y1>=?1 AND y0<=?1+5"); iStep = mxCoord/n; for(i=0; i<n; i++){ sqlite3_bind_int(g.pStmt, 1, i*iStep); speedtest1_run(); aCheck[i] = atoi(g.zResult); } speedtest1_end_test(); speedtest1_begin_test(170, "Restore deleted entries using INSERT OR IGNORE"); speedtest1_exec("INSERT OR IGNORE INTO rt1 SELECT * FROM t1"); speedtest1_end_test(); } #endif /* SQLITE_ENABLE_RTREE */ /* ** A testset that does key/value storage on tables with many columns. ** This is the kind of workload generated by ORMs such as CoreData. */ |
︙ | ︙ |
Changes to tool/speed-check.sh.
︙ | ︙ | |||
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_SHARED_CACHE" LEAN_OPTS="$LEAN_OPTS -DSQLITE_USE_ALLOCA" BASELINE="trunk" doExplain=0 doCachegrind=1 doVdbeProfile=0 doWal=1 while test "$1" != ""; do case $1 in --reprepare) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --autovacuum) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --utf16be) | > > > > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_SHARED_CACHE" LEAN_OPTS="$LEAN_OPTS -DSQLITE_USE_ALLOCA" BASELINE="trunk" doExplain=0 doCachegrind=1 doVdbeProfile=0 doWal=1 doDiff=1 while test "$1" != ""; do case $1 in --nodiff) doDiff=0 ;; --reprepare) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --autovacuum) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --utf16be) |
︙ | ︙ | |||
175 176 177 178 179 180 181 | if test $doExplain -eq 1; then ./speedtest1 --explain $SPEEDTEST_OPTS | ./sqlite3 >explain-$NAME.txt fi if test $doVdbeProfile -eq 1; then tclsh ../sqlite/tool/vdbe_profile.tcl >vdbeprofile-$NAME.txt open vdbeprofile-$NAME.txt fi | | | 179 180 181 182 183 184 185 186 187 188 | if test $doExplain -eq 1; then ./speedtest1 --explain $SPEEDTEST_OPTS | ./sqlite3 >explain-$NAME.txt fi if test $doVdbeProfile -eq 1; then tclsh ../sqlite/tool/vdbe_profile.tcl >vdbeprofile-$NAME.txt open vdbeprofile-$NAME.txt fi if test "$NAME" != "$BASELINE" -a $doVdbeProfile -ne 1 -a $doDiff -ne 0; then fossil test-diff --tk -c 20 cout-$BASELINE.txt cout-$NAME.txt fi |