/ Changes On Branch mistake
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch mistake Excluding Merge-Ins

This is equivalent to a diff from 0f93b52c77 to 4c23cad98d

2024-04-15
14:45
Merge all of the latest trunk enhancements into the bedrock branch. (Leaf check-in: 16dac180b5 user: drh tags: bedrock)
14:29
Merge from wrong branch. Bedrock should be updated from wal2, not from trunk. (Closed-Leaf check-in: 4c23cad98d user: drh tags: mistake)
2024-04-12
18:46
If a build fails in testrunner.tcl, do not attempt to run the jobs that depend on that build. Instead, report those jobs as having been skipped. (check-in: b40580be71 user: drh tags: trunk)
2024-04-08
12:02
Merge the latest trunk enhancements, and especially the enhancement to the WHERE-clause push-down optimization, into the bedrock branch. (check-in: 0f93b52c77 user: drh tags: bedrock)
11:57
Merge the latest trunk enhancements into the wal2 branch. (check-in: 59ccea7db7 user: drh tags: wal2)
2024-04-05
14:54
Merge the latest trunk enhancements into the bedrock branch. (check-in: 7a2a64b646 user: drh tags: bedrock)

Changes to ext/fts3/fts3_snippet.c.

442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
        if( (mCover|mCovered)&mPhrase ){
          iScore++;
        }else{
          iScore += 1000;
        }
        mCover |= mPhrase;

        for(j=0; j<pPhrase->nToken; j++){
          mHighlight |= (mPos>>j);
        }

        if( 0==(*pCsr & 0x0FE) ) break;
        fts3GetDeltaPosition(&pCsr, &iCsr);
      }
    }







|







442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
        if( (mCover|mCovered)&mPhrase ){
          iScore++;
        }else{
          iScore += 1000;
        }
        mCover |= mPhrase;

        for(j=0; j<pPhrase->nToken && j<pIter->nSnippet; j++){
          mHighlight |= (mPos>>j);
        }

        if( 0==(*pCsr & 0x0FE) ) break;
        fts3GetDeltaPosition(&pCsr, &iCsr);
      }
    }

Changes to ext/recover/dbdata.c.

490
491
492
493
494
495
496









497
498
499
500
501
502
503
          sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
        }
      }
    }
  }
}










/*
** Move an sqlite_dbdata or sqlite_dbptr cursor to the next entry.
*/
static int dbdataNext(sqlite3_vtab_cursor *pCursor){
  DbdataCursor *pCsr = (DbdataCursor*)pCursor;
  DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;








>
>
>
>
>
>
>
>
>







490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
          sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
        }
      }
    }
  }
}

/* This macro is a copy of the MX_CELL() macro in the SQLite core. Given
** a page-size, it returns the maximum number of cells that may be present
** on the page.  */
#define DBDATA_MX_CELL(pgsz) ((pgsz-8)/6)

/* Maximum number of fields that may appear in a single record. This is
** the "hard-limit", according to comments in sqliteLimit.h. */
#define DBDATA_MX_FIELD 32676

/*
** Move an sqlite_dbdata or sqlite_dbptr cursor to the next entry.
*/
static int dbdataNext(sqlite3_vtab_cursor *pCursor){
  DbdataCursor *pCsr = (DbdataCursor*)pCursor;
  DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;

518
519
520
521
522
523
524



525
526
527
528
529
530
531
        if( pCsr->bOnePage ) return SQLITE_OK;
        pCsr->iPgno++;
      }

      assert( iOff+3+2<=pCsr->nPage );
      pCsr->iCell = pTab->bPtr ? -2 : 0;
      pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]);



    }

    if( pTab->bPtr ){
      if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){
        pCsr->iCell = pCsr->nCell;
      }
      pCsr->iCell++;







>
>
>







527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
        if( pCsr->bOnePage ) return SQLITE_OK;
        pCsr->iPgno++;
      }

      assert( iOff+3+2<=pCsr->nPage );
      pCsr->iCell = pTab->bPtr ? -2 : 0;
      pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]);
      if( pCsr->nCell>DBDATA_MX_CELL(pCsr->nPage) ){
        pCsr->nCell = DBDATA_MX_CELL(pCsr->nPage);
      }
    }

    if( pTab->bPtr ){
      if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){
        pCsr->iCell = pCsr->nCell;
      }
      pCsr->iCell++;
562
563
564
565
566
567
568

569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
            pCsr->iCell = pCsr->nCell;
            break;
        }

        if( pCsr->iCell>=pCsr->nCell ){
          bNextPage = 1;
        }else{

  
          iOff += 8 + nPointer + pCsr->iCell*2;
          if( iOff>pCsr->nPage ){
            bNextPage = 1;
          }else{
            iOff = get_uint16(&pCsr->aPage[iOff]);
          }
    
          /* For an interior node cell, skip past the child-page number */
          iOff += nPointer;
    
          /* Load the "byte of payload including overflow" field */
          if( bNextPage || iOff>pCsr->nPage ){
            bNextPage = 1;
          }else{
            iOff += dbdataGetVarintU32(&pCsr->aPage[iOff], &nPayload);
            if( nPayload>0x7fffff00 ) nPayload &= 0x3fff;
          }
    
          /* If this is a leaf intkey cell, load the rowid */







>

<
|


|






|







574
575
576
577
578
579
580
581
582

583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
            pCsr->iCell = pCsr->nCell;
            break;
        }

        if( pCsr->iCell>=pCsr->nCell ){
          bNextPage = 1;
        }else{
          int iCellPtr = iOff + 8 + nPointer + pCsr->iCell*2;
  

          if( iCellPtr>pCsr->nPage ){
            bNextPage = 1;
          }else{
            iOff = get_uint16(&pCsr->aPage[iCellPtr]);
          }
    
          /* For an interior node cell, skip past the child-page number */
          iOff += nPointer;
    
          /* Load the "byte of payload including overflow" field */
          if( bNextPage || iOff>pCsr->nPage || iOff<=iCellPtr ){
            bNextPage = 1;
          }else{
            iOff += dbdataGetVarintU32(&pCsr->aPage[iOff], &nPayload);
            if( nPayload>0x7fffff00 ) nPayload &= 0x3fff;
          }
    
          /* If this is a leaf intkey cell, load the rowid */
657
658
659
660
661
662
663
664


665
666
667
668
669
670
671
            pCsr->iField = (bHasRowid ? -1 : 0);
          }
        }
      }else{
        pCsr->iField++;
        if( pCsr->iField>0 ){
          sqlite3_int64 iType;
          if( pCsr->pHdrPtr>&pCsr->pRec[pCsr->nRec] ){


            bNextPage = 1;
          }else{
            int szField = 0;
            pCsr->pHdrPtr += dbdataGetVarintU32(pCsr->pHdrPtr, &iType);
            szField = dbdataValueBytes(iType);
            if( (pCsr->nRec - (pCsr->pPtr - pCsr->pRec))<szField ){
              pCsr->pPtr = &pCsr->pRec[pCsr->nRec];







|
>
>







669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
            pCsr->iField = (bHasRowid ? -1 : 0);
          }
        }
      }else{
        pCsr->iField++;
        if( pCsr->iField>0 ){
          sqlite3_int64 iType;
          if( pCsr->pHdrPtr>=&pCsr->pRec[pCsr->nRec] 
           || pCsr->iField>=DBDATA_MX_FIELD
          ){
            bNextPage = 1;
          }else{
            int szField = 0;
            pCsr->pHdrPtr += dbdataGetVarintU32(pCsr->pHdrPtr, &iType);
            szField = dbdataValueBytes(iType);
            if( (pCsr->nRec - (pCsr->pPtr - pCsr->pRec))<szField ){
              pCsr->pPtr = &pCsr->pRec[pCsr->nRec];

Changes to ext/recover/recovercorrupt2.test.

519
520
521
522
523
524
525




























526
527
528
| end x1.db
}]} {}
do_test 7.1 {
  set R [sqlite3_recover_init db main test.db2]
  catch { $R run }
  list [catch { $R finish } msg] $msg
} {1 {file is not a database}}





























finish_test








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
| end x1.db
}]} {}
do_test 7.1 {
  set R [sqlite3_recover_init db main test.db2]
  catch { $R run }
  list [catch { $R finish } msg] $msg
} {1 {file is not a database}}

reset_db
breakpoint
do_test 8.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
| size 8192 pagesize 4096 filename db.sqlite
| page 1 offset 0
|      0: ac ae b3 76 74 65 20 66 6f 72 6d 61 74 20 33 00   ...vte format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 01 00 00 00 02   .....@  ........
|     32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04   ................
|     48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00   ................
|     80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01   ................
|     96: 00 2e 76 8a 0d ff ff ff 1e 0f cb 00 0f cb 00 00   ..v.............
|   4032: 00 00 00 00 00 00 00 00 00 00 00 33 01 06 17 19   ...........3....
|   4048: 19 01 43 74 61 62 6c 65 54 61 62 6c 65 30 54 61   ..CtableTable0Ta
|   4064: 62 6c 65 30 02 43 52 45 41 54 45 20 54 41 42 4c   ble0.CREATE TABL
|   4080: 45 20 54 61 62 6c 65 30 20 28 43 6f 6c 30 20 29   E Table0 (Col0 )
| page 2 offset 4096
|      0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00   ................
| end db.sqlite
}]} {}

do_test 8.1 {
  set R [sqlite3_recover_init db main test.db2]
  catch { $R run }
  list [catch { $R finish } msg] $msg
} {0 {}}

finish_test

Changes to ext/recover/sqlite3recover.c.

1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
      }
      rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0);
      if( rc==SQLITE_OK ){
        recoverSqlCallback(p, zSql);
        if( bTable && !bVirtual ){
          if( SQLITE_ROW==sqlite3_step(pTblname) ){
            const char *zTbl = (const char*)sqlite3_column_text(pTblname, 0);
            recoverAddTable(p, zTbl, iRoot);
          }
          recoverReset(p, pTblname);
        }
      }else if( rc!=SQLITE_ERROR ){
        recoverDbError(p, p->dbOut);
      }
      sqlite3_free(zFree);







|







1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
      }
      rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0);
      if( rc==SQLITE_OK ){
        recoverSqlCallback(p, zSql);
        if( bTable && !bVirtual ){
          if( SQLITE_ROW==sqlite3_step(pTblname) ){
            const char *zTbl = (const char*)sqlite3_column_text(pTblname, 0);
            if( zTbl ) recoverAddTable(p, zTbl, iRoot);
          }
          recoverReset(p, pTblname);
        }
      }else if( rc!=SQLITE_ERROR ){
        recoverDbError(p, p->dbOut);
      }
      sqlite3_free(zFree);

Changes to src/btree.c.

5615
5616
5617
5618
5619
5620
5621




5622
5623
5624
5625
5626
5627
5628
        }else{
          pCur->aOverflow = aNew;
        }
      }
      memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
      pCur->curFlags |= BTCF_ValidOvfl;
    }else{




      /* If the overflow page-list cache has been allocated and the
      ** entry for the first required overflow page is valid, skip
      ** directly to it.
      */
      if( pCur->aOverflow[offset/ovflSize] ){
        iIdx = (offset/ovflSize);
        nextPage = pCur->aOverflow[iIdx];







>
>
>
>







5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
        }else{
          pCur->aOverflow = aNew;
        }
      }
      memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
      pCur->curFlags |= BTCF_ValidOvfl;
    }else{
      /* Sanity check the validity of the overflow page cache */
      assert( pCur->aOverflow[0]==nextPage || pCur->aOverflow[0]==0 );
      assert( pCur->aOverflow[0]!=0 || pCur->aOverflow[offset/ovflSize]==0 );

      /* If the overflow page-list cache has been allocated and the
      ** entry for the first required overflow page is valid, skip
      ** directly to it.
      */
      if( pCur->aOverflow[offset/ovflSize] ){
        iIdx = (offset/ovflSize);
        nextPage = pCur->aOverflow[iIdx];
6103
6104
6105
6106
6107
6108
6109

















6110
6111
6112
6113
6114
6115
6116
  }else if( rc==SQLITE_EMPTY ){
    assert( pCur->pgnoRoot==0 || (pCur->pPage!=0 && pCur->pPage->nCell==0) );
    *pRes = 1;
    rc = SQLITE_OK;
  }
  return rc;
}


















/* Move the cursor to the last entry in the table.  Return SQLITE_OK
** on success.  Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty.
*/
static SQLITE_NOINLINE int btreeLast(BtCursor *pCur, int *pRes){
  int rc = moveToRoot(pCur);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
  }else if( rc==SQLITE_EMPTY ){
    assert( pCur->pgnoRoot==0 || (pCur->pPage!=0 && pCur->pPage->nCell==0) );
    *pRes = 1;
    rc = SQLITE_OK;
  }
  return rc;
}

#ifdef SQLITE_DEBUG
/* The cursors is CURSOR_VALID and has BTCF_AtLast set.  Verify that
** this flags are true for a consistent database.
**
** This routine is is called from within assert() statements only.
** It is an internal verification routine and does not appear in production
** builds.
*/
static int cursorIsAtLastEntry(BtCursor *pCur){
  int ii;
  for(ii=0; ii<pCur->iPage; ii++){
    if( pCur->aiIdx[ii]!=pCur->apPage[ii]->nCell ) return 0;
  }
  return pCur->ix==pCur->pPage->nCell-1 && pCur->pPage->leaf!=0;
}
#endif

/* Move the cursor to the last entry in the table.  Return SQLITE_OK
** on success.  Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty.
*/
static SQLITE_NOINLINE int btreeLast(BtCursor *pCur, int *pRes){
  int rc = moveToRoot(pCur);
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
}
int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
  assert( cursorOwnsBtShared(pCur) );
  assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );

  /* If the cursor already points to the last entry, this is a no-op. */
  if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
#ifdef SQLITE_DEBUG
    /* This block serves to assert() that the cursor really does point
    ** to the last entry in the b-tree. */
    int ii;
    for(ii=0; ii<pCur->iPage; ii++){
      assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
    }
    assert( pCur->ix==pCur->pPage->nCell-1 || CORRUPT_DB );
    testcase( pCur->ix!=pCur->pPage->nCell-1 );
    /* ^-- dbsqlfuzz b92b72e4de80b5140c30ab71372ca719b8feb618 */
    assert( pCur->pPage->leaf );
#endif
    *pRes = 0;
    return SQLITE_OK;
  }
  return btreeLast(pCur, pRes);
}

/* Move the cursor so that it points to an entry in a table (a.k.a INTKEY)







<
<
<
<
<
<
<
|
<
<
<
<







6153
6154
6155
6156
6157
6158
6159







6160




6161
6162
6163
6164
6165
6166
6167
}
int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
  assert( cursorOwnsBtShared(pCur) );
  assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );

  /* If the cursor already points to the last entry, this is a no-op. */
  if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){







    assert( cursorIsAtLastEntry(pCur) || CORRUPT_DB );




    *pRes = 0;
    return SQLITE_OK;
  }
  return btreeLast(pCur, pRes);
}

/* Move the cursor so that it points to an entry in a table (a.k.a INTKEY)
6196
6197
6198
6199
6200
6201
6202

6203
6204
6205
6206
6207
6208
6209
  if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){
    if( pCur->info.nKey==intKey ){
      *pRes = 0;
      return SQLITE_OK;
    }
    if( pCur->info.nKey<intKey ){
      if( (pCur->curFlags & BTCF_AtLast)!=0 ){

        *pRes = -1;
        return SQLITE_OK;
      }
      /* If the requested key is one more than the previous key, then
      ** try to get there using sqlite3BtreeNext() rather than a full
      ** binary search.  This is an optimization only.  The correct answer
      ** is still obtained without this case, only a little more slowly. */







>







6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
  if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){
    if( pCur->info.nKey==intKey ){
      *pRes = 0;
      return SQLITE_OK;
    }
    if( pCur->info.nKey<intKey ){
      if( (pCur->curFlags & BTCF_AtLast)!=0 ){
        assert( cursorIsAtLastEntry(pCur) || CORRUPT_DB );
        *pRes = -1;
        return SQLITE_OK;
      }
      /* If the requested key is one more than the previous key, then
      ** try to get there using sqlite3BtreeNext() rather than a full
      ** binary search.  This is an optimization only.  The correct answer
      ** is still obtained without this case, only a little more slowly. */
10015
10016
10017
10018
10019
10020
10021
10022
10023
10024
10025
10026
10027
10028
10029
      return SQLITE_OK;
    }
    dropCell(pPage, idx, info.nSize, &rc);
    if( rc ) goto end_insert;
  }else if( loc<0 && pPage->nCell>0 ){
    assert( pPage->leaf );
    idx = ++pCur->ix;
    pCur->curFlags &= ~BTCF_ValidNKey;
  }else{
    assert( pPage->leaf );
  }
  rc = insertCellFast(pPage, idx, newCell, szNew);
  assert( pPage->nOverflow==0 || rc==SQLITE_OK );
  assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );








|







10026
10027
10028
10029
10030
10031
10032
10033
10034
10035
10036
10037
10038
10039
10040
      return SQLITE_OK;
    }
    dropCell(pPage, idx, info.nSize, &rc);
    if( rc ) goto end_insert;
  }else if( loc<0 && pPage->nCell>0 ){
    assert( pPage->leaf );
    idx = ++pCur->ix;
    pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
  }else{
    assert( pPage->leaf );
  }
  rc = insertCellFast(pPage, idx, newCell, szNew);
  assert( pPage->nOverflow==0 || rc==SQLITE_OK );
  assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );

10045
10046
10047
10048
10049
10050
10051
10052
10053
10054
10055
10056
10057
10058
10059
  ** the b-tree if possible. If the cursor is left pointing to the last
  ** entry in the table, and the next row inserted has an integer key
  ** larger than the largest existing key, it is possible to insert the
  ** row without seeking the cursor. This can be a big performance boost.
  */
  if( pPage->nOverflow ){
    assert( rc==SQLITE_OK );
    pCur->curFlags &= ~(BTCF_ValidNKey);
    rc = balance(pCur);

    /* Must make sure nOverflow is reset to zero even if the balance()
    ** fails. Internal data structure corruption will result otherwise.
    ** Also, set the cursor state to invalid. This stops saveCursorPosition()
    ** from trying to save the current position of the cursor.  */
    pCur->pPage->nOverflow = 0;







|







10056
10057
10058
10059
10060
10061
10062
10063
10064
10065
10066
10067
10068
10069
10070
  ** the b-tree if possible. If the cursor is left pointing to the last
  ** entry in the table, and the next row inserted has an integer key
  ** larger than the largest existing key, it is possible to insert the
  ** row without seeking the cursor. This can be a big performance boost.
  */
  if( pPage->nOverflow ){
    assert( rc==SQLITE_OK );
    pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
    rc = balance(pCur);

    /* Must make sure nOverflow is reset to zero even if the balance()
    ** fails. Internal data structure corruption will result otherwise.
    ** Also, set the cursor state to invalid. This stops saveCursorPosition()
    ** from trying to save the current position of the cursor.  */
    pCur->pPage->nOverflow = 0;

Changes to src/insert.c.

3178
3179
3180
3181
3182
3183
3184


3185

3186
3187
3188
3189
3190
3191
3192
      /* The sqlite3FaultSim() call allows this corruption test to be
      ** bypassed during testing, in order to exercise other corruption tests
      ** further downstream. */
      return 0;   /* Corrupt schema - two indexes on the same btree */
    }
  }
#ifndef SQLITE_OMIT_CHECK


  if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){

    return 0;   /* Tables have different CHECK constraints.  Ticket #2252 */
  }
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
  /* Disallow the transfer optimization if the destination table contains
  ** any foreign key constraints.  This is more restrictive than necessary.
  ** But the main beneficiary of the transfer optimization is the VACUUM







>
>
|
>







3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
      /* The sqlite3FaultSim() call allows this corruption test to be
      ** bypassed during testing, in order to exercise other corruption tests
      ** further downstream. */
      return 0;   /* Corrupt schema - two indexes on the same btree */
    }
  }
#ifndef SQLITE_OMIT_CHECK
  if( pDest->pCheck
   && (db->mDbFlags & DBFLAG_Vacuum)==0
   && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1)
  ){
    return 0;   /* Tables have different CHECK constraints.  Ticket #2252 */
  }
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
  /* Disallow the transfer optimization if the destination table contains
  ** any foreign key constraints.  This is more restrictive than necessary.
  ** But the main beneficiary of the transfer optimization is the VACUUM

Changes to src/pager.c.

7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
}

/*
** Return the file handle for the journal file (if it exists).
** This will be either the rollback journal or the WAL file.
*/
sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
#if SQLITE_OMIT_WAL
  return pPager->jfd;
#else
  return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd;
#endif
}

/*







|







7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
}

/*
** Return the file handle for the journal file (if it exists).
** This will be either the rollback journal or the WAL file.
*/
sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
#ifdef SQLITE_OMIT_WAL
  return pPager->jfd;
#else
  return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd;
#endif
}

/*

Changes to test/fts3snippet2.test.

50
51
52
53
54
55
56











57
58
59
  );
  INSERT INTO t0 VALUES ('one', '1234','aaaa','bbbb');
}
do_execsql_test 2.2 {
  SELECT snippet(t0)  FROM t0 WHERE t0 MATCH 
  '(def AND (one NEAR abc)) OR one'
} {<b>one</b>}












set sqlite_fts3_enable_parentheses 0
finish_test







>
>
>
>
>
>
>
>
>
>
>



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  );
  INSERT INTO t0 VALUES ('one', '1234','aaaa','bbbb');
}
do_execsql_test 2.2 {
  SELECT snippet(t0)  FROM t0 WHERE t0 MATCH 
  '(def AND (one NEAR abc)) OR one'
} {<b>one</b>}

#-------------------------------------------------------------------------

do_execsql_test 3.0 {
CREATE VIRTUAL TABLE f USING fts3(a,b);
INSERT INTO f VALUES (101,x'056522650565056505650d051e056505650565286505650565056505056505650565056505650565056505650565056505650565056505656505650565056505650d05650505656505650565ef65056505844c746e65650565056505650565056505650565056505650565058405800565056505650565056505651e650565056505650565056505650d056505056565056505650565056505840580056505650565056f05650565056505650565056505650565050565056505640565056505650565056505651e05650565056505650565056505650505656565056505650565056505651e0565056505650565056505650565052265056505650569056505650565056505650565056505650565056505650500406505650565056505650565056505000101e5c501014b010101c501c5c501010101f5010201010101014101017373737373737373737373737373737373737373737373737373737330737373737373737373737373737365056505650d051e05650565056528056505650d05650505656505650565650565056505650565056505e505650565056505656505650565056505650d05650505656505650565ef65056505844c746e65650565056505650565056505650565056505650565058405800565056505650565056505651e650565056505650565056505650d056505056565056505650565056505840580056505650565286505c705650565050565059494949494949494949494949494949494949494949494949494949494949494949494650565056505650565056505650565056505650565056505656505650565056505650d05650505656505650565ef650565058405056505650565056505650565056505650565056505650565058405800565056505650565056505651e650565056505650565056505650d056505056565056505650565056505840580056505650565056505650565056505650505650565056505650565056505650565056500000000000000000000000000000000000000000000000000000000000000000565056505656505650565056505650d056500000000000000000000000000000000000000000000000000000000000000000100000000000000ed0000000000ffffffffffffffffffffff0007ffffff0001c5c50001c5c50001c5c50001c5c50001c5c50001c5c50001e5c50001c5c50001c5c50001c5c50001c5c50001c5c5000100000014720000000000000016dac5c50001c5c50001c5c50001c5c50001c5c50001c5c50d0505656505650565ef650565058405056505650565056505650565056505650565056505650565058405800465056505650565056505651e650565056505650565056505650d05650505656505650565050565650584058005650565056505650565056505650565056522650565056505650d051e056505650561286505c70565056505056505650565056505650565056505650565056505650565056505656505650565056505650d05650505656505650565ef650565058405056505650565056505650565056505650565056505650565058405800565056505650565056505651e650565056505650565056505650d056505056565056505650565056505840580056505650565056505650565056505650565226505737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373737373733a73737373737373737373737373737373737373737373737373737373737373737373737373737373737c7373737365056505650d051e05650565056528650565056505650505650565056505650565056505650565056505e505650565056505656505650565056505650d05650505656505650565ef65056505');
}

do_execsql_test 3.1 {
  SELECT  length(snippet(f))  FROM f WHERE b MATCH x'0565056505650565056505650565056505650565058405800565056505650565056505651e650565056505650565056505650d056505056565056505650565056505840580056505650565056505650565056505650565056505650565050565056505640565056505650565056505651e05650565056522650565056505650d051e056505650565286505650565056505056505650565056505650565056505650565056505650565056505656505650565056505650d05650505656505650565ef65056505844c746e65650565056505650565056505650565056505650565058405800565056505650565056505651e650565056505650565056505650d056505056565056505650565056505840580056505650565056f05650565056505650565056505650565050565056505640565056505650565056505651e05650565056505650565056505650505656565056505650565056505651e0565056505650565056505650565052265056505650569056505650565056505650565056505650565056505650500406505650565056505650565056505000101e5c501014b010101c501c5c501010101f50102010101010141010141010001017bf15905000000000017';
} {192}

set sqlite_fts3_enable_parentheses 0
finish_test

Changes to test/returning1.test.

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
  
  do_execsql_test 10.4 {
    SELECT * FROM log;
  } {}
} else {
  # Note: The values returned by the RETURNING clauses of the following
  # two statements are the rowid columns of views. These values are not
  # well defined, so the INSERT returns -1, and the UPDATE returns 1, 2 
  # and 3. These match the values used for new.rowid expressions, but 
  # not much else.
  do_catchsql_test 10.3a {
    INSERT INTO t1(a, b) VALUES(1234, 5678) RETURNING rowid;
  } {0 -1}
  
  do_catchsql_test 10.3b {
    UPDATE t1 SET a='z' WHERE b='y' RETURNING rowid;
  } {0 {1 2 3}}
  
  do_execsql_test 10.4 {
    SELECT * FROM log;
  } {
    insert -1 1234 5678 update 1 z y update 2 z y update 3 z y
  }
}

# 2021-04-27 dbsqlfuzz 78b9400770ef8cc7d9427dfba26f4fcf46ea7dc2
# Returning clauses on TEMP tables with triggers.
#
reset_db







|
|
|






|




|







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
  
  do_execsql_test 10.4 {
    SELECT * FROM log;
  } {}
} else {
  # Note: The values returned by the RETURNING clauses of the following
  # two statements are the rowid columns of views. These values are not
  # well defined, so the INSERT returns -1, and the UPDATE returns NULL.
  # These match the values used for new.rowid expressions, but not much 
  # else.
  do_catchsql_test 10.3a {
    INSERT INTO t1(a, b) VALUES(1234, 5678) RETURNING rowid;
  } {0 -1}
  
  do_catchsql_test 10.3b {
    UPDATE t1 SET a='z' WHERE b='y' RETURNING rowid;
  } {0 {{} {} {}}}
  
  do_execsql_test 10.4 {
    SELECT * FROM log;
  } {
    insert -1 1234 5678 update {} z y update {} z y update {} z y
  }
}

# 2021-04-27 dbsqlfuzz 78b9400770ef8cc7d9427dfba26f4fcf46ea7dc2
# Returning clauses on TEMP tables with triggers.
#
reset_db

Changes to test/testrunner.tcl.

266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
    cmd TEXT NOT NULL,                  -- shell command to run
    depid INTEGER,                      -- identifier of dependency (or '')
    priority INTEGER NOT NULL,          -- higher priority jobs may run earlier
  
    /* Fields updated as jobs run */
    starttime INTEGER, 
    endtime INTEGER,
    state TEXT CHECK( state IN ('', 'ready', 'running', 'done', 'failed') ),
    output TEXT
  );

  CREATE TABLE config(
    name TEXT COLLATE nocase PRIMARY KEY,
    value 
  ) WITHOUT ROWID;







|







266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
    cmd TEXT NOT NULL,                  -- shell command to run
    depid INTEGER,                      -- identifier of dependency (or '')
    priority INTEGER NOT NULL,          -- higher priority jobs may run earlier
  
    /* Fields updated as jobs run */
    starttime INTEGER, 
    endtime INTEGER,
    state TEXT CHECK( state IN ('','ready','running','done','failed','omit') ),
    output TEXT
  );

  CREATE TABLE config(
    name TEXT COLLATE nocase PRIMARY KEY,
    value 
  ) WITHOUT ROWID;
442
443
444
445
446
447
448




449
450
451
452
453
454
455
  }
  if {$S(failed)>0} {
    puts "Failures: "
    mydb eval {
      SELECT * FROM jobs WHERE state='failed' ORDER BY starttime
    } job {
      display_job [array get job]




    }
  }
 
  mydb close
  exit
}








>
>
>
>







442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  }
  if {$S(failed)>0} {
    puts "Failures: "
    mydb eval {
      SELECT * FROM jobs WHERE state='failed' ORDER BY starttime
    } job {
      display_job [array get job]
    }
    set nOmit [db one {SELECT count(*) FROM jobs WHERE state='omit'}]
    if {$nOmit} {
      puts "$nOmit jobs omitted due to failures"
    }
  }
 
  mydb close
  exit
}

971
972
973
974
975
976
977





978
979
980
981
982
983
984
985
986
987
988
989
    add_jobs_from_cmdline $TRG(patternlist)
  }

}

proc mark_job_as_finished {jobid output state endtm} {
  r_write_db {





    trdb eval {
      UPDATE jobs 
        SET output=$output, state=$state, endtime=$endtm
        WHERE jobid=$jobid;
      UPDATE jobs SET state='ready' WHERE depid=$jobid;
    }
  }
}

proc script_input_ready {fd iJob jobid} {
  global TRG
  global O







>
>
>
>
>




|







975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
    add_jobs_from_cmdline $TRG(patternlist)
  }

}

proc mark_job_as_finished {jobid output state endtm} {
  r_write_db {
    if {$state=="failed"} {
      set childstate omit
    } else {
      set childstate ready
    }
    trdb eval {
      UPDATE jobs 
        SET output=$output, state=$state, endtime=$endtm
        WHERE jobid=$jobid;
      UPDATE jobs SET state=$childstate WHERE depid=$jobid;
    }
  }
}

proc script_input_ready {fd iJob jobid} {
  global TRG
  global O
1197
1198
1199
1200
1201
1202
1203




1204
1205
1206
1207
1208
1209
1210
    if {$nErr>0} {
      puts "$nErr failures:"
      trdb eval {
        SELECT displayname FROM jobs WHERE state='failed'
      } {
        puts "FAILED: $displayname"
      }




    }
  }

  puts "\nTest database is $TRG(dbname)"
  puts "Test log is $TRG(logname)"
}








>
>
>
>







1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
    if {$nErr>0} {
      puts "$nErr failures:"
      trdb eval {
        SELECT displayname FROM jobs WHERE state='failed'
      } {
        puts "FAILED: $displayname"
      }
    }
    set nOmit [trdb one {SELECT count(*) FROM jobs WHERE state='omit'}]
    if {$nOmit>0} {
      puts "$nOmit jobs skipped due to prior failures"
    }
  }

  puts "\nTest database is $TRG(dbname)"
  puts "Test log is $TRG(logname)"
}

Changes to test/upsert1.test.

263
264
265
266
267
268
269
























270
271
  CREATE TABLE t1(a INT, b INT);
  CREATE UNIQUE INDEX t1x ON t1(b+3);
}
sqlite3_db_config db ENABLE_QPSG 1
do_catchsql_test upsert1-1210 {
  INSERT INTO t1(a,b) VALUES(1,2) ON CONFLICT(b+?1) DO NOTHING;
} {1 {ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint}}

























finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


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
  CREATE TABLE t1(a INT, b INT);
  CREATE UNIQUE INDEX t1x ON t1(b+3);
}
sqlite3_db_config db ENABLE_QPSG 1
do_catchsql_test upsert1-1210 {
  INSERT INTO t1(a,b) VALUES(1,2) ON CONFLICT(b+?1) DO NOTHING;
} {1 {ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint}}

# 2024-04-11 https://sqlite.org/forum/forumpost/284955a3cd454a15
# Incorrect value passed into a trigger that fires as the result of
# an upsert.
#
reset_db
do_execsql_test upsert1-1300 {
  CREATE TABLE t1(x INT, y TEXT);
  INSERT INTO t1 VALUES
    (11, printf('%.9000c','a')),
    (11, printf('%.9000c','a')),
    (33, printf('%.9000c','b')),
    (33, printf('%.9000c','b'));
  CREATE TABLE t2(x INT UNIQUE, y TEXT);
  CREATE TRIGGER r1 BEFORE UPDATE ON t2 BEGIN
    SELECT raise(ABORT,'Incorrect old.y value passed to trigger!')
     WHERE old.y != new.y;
    /* ^^^ This trigger will fire and cause the ABORT if the problem has
    ** not been fixed, or if there is a regression. */
  END;
  INSERT INTO t2(x, y) SELECT x, y FROM t1
   WHERE true
   ON CONFLICT (x) DO UPDATE SET y = excluded.y;
} {}

finish_test

Changes to test/vacuum-into.test.

22
23
24
25
26
27
28
29





30
31
32
33
34
35


















36
37
38
39
40
41
42
  omit_test vacuum.test {Compiled with SQLITE_OMIT_VACUUM}
  finish_test
  return
}

forcedelete out.db
do_execsql_test vacuum-into-100 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);





  WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
  INSERT INTO t1(a,b) SELECT x, randomblob(600) FROM c;
  CREATE INDEX t1b ON t1(b);
  DELETE FROM t1 WHERE a%2;
  SELECT count(*), sum(a), sum(length(b)) FROM t1;
} {50 2550 30000}


















do_execsql_test vacuum-into-110 {
  VACUUM main INTO 'out.db';
} {}
sqlite3 db2 out.db
do_test vacuum-into-120 {
  db2 eval {SELECT count(*), sum(a), sum(length(b)) FROM t1}
} {50 2550 30000}







|
>
>
>
>
>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







22
23
24
25
26
27
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
  omit_test vacuum.test {Compiled with SQLITE_OMIT_VACUUM}
  finish_test
  return
}

forcedelete out.db
do_execsql_test vacuum-into-100 {
  CREATE TABLE t1(
    a INTEGER PRIMARY KEY,
    b ANY,
    c INT AS (b+1),                          --- See "2024-04-09" block
    CHECK( typeof(b)!='integer' OR b>a-5 )   --- comment below
  );
  WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
  INSERT INTO t1(a,b) SELECT x, randomblob(600) FROM c;
  CREATE INDEX t1b ON t1(b);
  DELETE FROM t1 WHERE a%2;
  SELECT count(*), sum(a), sum(length(b)) FROM t1;
} {50 2550 30000}

# Update 2024-04-09 for forum post eec177d68fe7fa2c.
#
# VACUUM INTO is sensitive to tables holding both generated columns
# and CHECK constraints.  
#
# CHECK constraints are ignored for read-only databases in order to save
# memory (see check-in 34ddf02d3d21151b on 2014-05-21).  But the xfer
# optimization normally only works if CHECK constraints match between the
# source and destination tables.  So the xfer optimization was not
# working for VACUUM INTO when the source was a read-only database and the
# table held CHECK constraints.  But if the table has generated columns,
# then the xfer optimization is required or else VACUUM will raise an
# error.
#
# Fix this by ignoring CHECK constraints when determining whether or not
# the xfer optimization can run while doing VACUUM.

do_execsql_test vacuum-into-110 {
  VACUUM main INTO 'out.db';
} {}
sqlite3 db2 out.db
do_test vacuum-into-120 {
  db2 eval {SELECT count(*), sum(a), sum(length(b)) FROM t1}
} {50 2550 30000}
84
85
86
87
88
89
90





91
92
93
94
95





96
97
98
99
100
101
102
} 1
do_catchsql_test vacuum-into-420 {
  VACUUM INTO target2()
} {1 {no such function: target2}}

# The ability to VACUUM INTO a read-only database
db close





sqlite3 db test.db -readonly 1
forcedelete test.db2
do_execsql_test vacuum-into-500 {
  VACUUM INTO 'test.db2';
}





sqlite3 db2 test.db2
do_test vacuum-into-510 {
  db2 eval {SELECT name FROM sqlite_master ORDER BY 1}
} {t1 t1b t2}
db2 close
db close








>
>
>
>
>





>
>
>
>
>







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
} 1
do_catchsql_test vacuum-into-420 {
  VACUUM INTO target2()
} {1 {no such function: target2}}

# The ability to VACUUM INTO a read-only database
db close
if {$tcl_platform(platform)=="windows"} {
  file attributes test.db -readonly 1
} else {
  file attributes test.db -permissions 292  ;# 292 == 0444
}
sqlite3 db test.db -readonly 1
forcedelete test.db2
do_execsql_test vacuum-into-500 {
  VACUUM INTO 'test.db2';
}
if {$tcl_platform(platform)=="windows"} {
  file attributes test.db -readonly 0
} else {
  file attributes test.db -permissions 420   ;# 420 = 0644
}
sqlite3 db2 test.db2
do_test vacuum-into-510 {
  db2 eval {SELECT name FROM sqlite_master ORDER BY 1}
} {t1 t1b t2}
db2 close
db close