/ Check-in [977fc44e]
Login

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

Overview
Comment:Merge the read-only shadow table and defensive mode enhancments from trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | apple-osx
Files: files | file ages | folders
SHA3-256:977fc44e65f831d4c6184073f44708567081f358904dd76e8df5a82a17977469
User & Date: drh 2018-11-10 20:07:51
Context
2018-11-10
20:07
Merge the read-only shadow table and defensive mode enhancments from trunk. Leaf check-in: 977fc44e user: drh tags: apple-osx
18:23
Add support for read-only shadow tables on virtual tables. Added the SQLITE_DEFAULT_DEFENSIVE compile-time option that can put SQLite in defensive mode by default. check-in: 9c685171 user: drh tags: trunk
2018-11-09
23:45
Merge fixes from trunk. check-in: e3e9b85e user: drh tags: apple-osx
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

1307
1308
1309
1310
1311
1312
1313



1314
1315
1316
1317
1318
1319
1320

showshm$(TEXE):	$(TOP)/tool/showshm.c
	$(LTLINK) -o $@ $(TOP)/tool/showshm.c

changeset$(TEXE):	$(TOP)/ext/session/changeset.c sqlite3.lo
	$(LTLINK) -o $@ $(TOP)/ext/session/changeset.c sqlite3.lo $(TLIBS)




rollback-test$(TEXE):	$(TOP)/tool/rollback-test.c sqlite3.lo
	$(LTLINK) -o $@ $(TOP)/tool/rollback-test.c sqlite3.lo $(TLIBS)

atrc$(TEXX): $(TOP)/test/atrc.c sqlite3.lo
	$(LTLINK) -o $@ $(TOP)/test/atrc.c sqlite3.lo $(TLIBS)

LogEst$(TEXE):	$(TOP)/tool/logest.c sqlite3.h







>
>
>







1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323

showshm$(TEXE):	$(TOP)/tool/showshm.c
	$(LTLINK) -o $@ $(TOP)/tool/showshm.c

changeset$(TEXE):	$(TOP)/ext/session/changeset.c sqlite3.lo
	$(LTLINK) -o $@ $(TOP)/ext/session/changeset.c sqlite3.lo $(TLIBS)

changesetfuzz$(TEXE):	$(TOP)/ext/session/changesetfuzz.c sqlite3.lo
	$(LTLINK) -o $@ $(TOP)/ext/session/changesetfuzz.c sqlite3.lo $(TLIBS)

rollback-test$(TEXE):	$(TOP)/tool/rollback-test.c sqlite3.lo
	$(LTLINK) -o $@ $(TOP)/tool/rollback-test.c sqlite3.lo $(TLIBS)

atrc$(TEXX): $(TOP)/test/atrc.c sqlite3.lo
	$(LTLINK) -o $@ $(TOP)/test/atrc.c sqlite3.lo $(TLIBS)

LogEst$(TEXE):	$(TOP)/tool/logest.c sqlite3.h

Changes to Makefile.msc.

2444
2445
2446
2447
2448
2449
2450





2451
2452
2453
2454
2455
2456
2457
	$(LTLINK) $(NO_WARN)	$(TOP)\tool\showshm.c /link $(LDFLAGS) $(LTLINKOPTS)

changeset.exe:	$(TOP)\ext\session\changeset.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
		-DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 \
		$(TOP)\ext\session\changeset.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)






fts3view.exe:	$(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
		$(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)

rollback-test.exe:	$(TOP)\tool\rollback-test.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
		$(TOP)\tool\rollback-test.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)







>
>
>
>
>







2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
	$(LTLINK) $(NO_WARN)	$(TOP)\tool\showshm.c /link $(LDFLAGS) $(LTLINKOPTS)

changeset.exe:	$(TOP)\ext\session\changeset.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
		-DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 \
		$(TOP)\ext\session\changeset.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)

changesetfuzz.exe:	$(TOP)\ext\session\changesetfuzz.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
		-DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 \
		$(TOP)\ext\session\changesetfuzz.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)

fts3view.exe:	$(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
		$(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)

rollback-test.exe:	$(TOP)\tool\rollback-test.c $(SQLITE3C) $(SQLITE3H)
	$(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
		$(TOP)\tool\rollback-test.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)

Changes to ext/expert/sqlite3expert.c.

640
641
642
643
644
645
646

647
648
649
650
651
652
653
    0,                            /* xCommit - commit transaction */
    0,                            /* xRollback - rollback transaction */
    0,                            /* xFindFunction - function overloading */
    0,                            /* xRename - rename the table */
    0,                            /* xSavepoint */
    0,                            /* xRelease */
    0,                            /* xRollbackTo */

  };

  return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p);
}
/*
** End of virtual table implementation.
*************************************************************************/







>







640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
    0,                            /* xCommit - commit transaction */
    0,                            /* xRollback - rollback transaction */
    0,                            /* xFindFunction - function overloading */
    0,                            /* xRename - rename the table */
    0,                            /* xSavepoint */
    0,                            /* xRelease */
    0,                            /* xRollbackTo */
    0,                            /* xShadowName */
  };

  return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p);
}
/*
** End of virtual table implementation.
*************************************************************************/

Changes to ext/fts3/fts3.c.

3841
3842
3843
3844
3845
3846
3847
3848















3849
3850
3851
3852
3853
3854
3855
3856
3857
....
3866
3867
3868
3869
3870
3871
3872

3873
3874
3875
3876
3877
3878
3879
  UNUSED_PARAMETER(iSavepoint);
  assert( p->inTransaction );
  assert( p->mxSavepoint >= iSavepoint );
  TESTONLY( p->mxSavepoint = iSavepoint );
  sqlite3Fts3PendingTermsClear(p);
  return SQLITE_OK;
}
















static const sqlite3_module fts3Module = {
  /* iVersion      */ 2,
  /* xCreate       */ fts3CreateMethod,
  /* xConnect      */ fts3ConnectMethod,
  /* xBestIndex    */ fts3BestIndexMethod,
  /* xDisconnect   */ fts3DisconnectMethod,
  /* xDestroy      */ fts3DestroyMethod,
  /* xOpen         */ fts3OpenMethod,
  /* xClose        */ fts3CloseMethod,
................................................................................
  /* xCommit       */ fts3CommitMethod,
  /* xRollback     */ fts3RollbackMethod,
  /* xFindFunction */ fts3FindFunctionMethod,
  /* xRename */       fts3RenameMethod,
  /* xSavepoint    */ fts3SavepointMethod,
  /* xRelease      */ fts3ReleaseMethod,
  /* xRollbackTo   */ fts3RollbackToMethod,

};

/*
** This function is registered as the module destructor (called when an
** FTS3 enabled database connection is closed). It frees the memory
** allocated for the tokenizer hash table.
*/








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

|







 







>







3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
....
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
  UNUSED_PARAMETER(iSavepoint);
  assert( p->inTransaction );
  assert( p->mxSavepoint >= iSavepoint );
  TESTONLY( p->mxSavepoint = iSavepoint );
  sqlite3Fts3PendingTermsClear(p);
  return SQLITE_OK;
}

/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.
*/
static int fts3ShadowName(const char *zName){
  static const char *azName[] = {
    "content", "docsize", "segdir", "segments", "stat", 
  };
  unsigned int i;
  for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
    if( sqlite3_stricmp(zName, azName[i])==0 ) return 1;
  }
  return 0;
}

static const sqlite3_module fts3Module = {
  /* iVersion      */ 3,
  /* xCreate       */ fts3CreateMethod,
  /* xConnect      */ fts3ConnectMethod,
  /* xBestIndex    */ fts3BestIndexMethod,
  /* xDisconnect   */ fts3DisconnectMethod,
  /* xDestroy      */ fts3DestroyMethod,
  /* xOpen         */ fts3OpenMethod,
  /* xClose        */ fts3CloseMethod,
................................................................................
  /* xCommit       */ fts3CommitMethod,
  /* xRollback     */ fts3RollbackMethod,
  /* xFindFunction */ fts3FindFunctionMethod,
  /* xRename */       fts3RenameMethod,
  /* xSavepoint    */ fts3SavepointMethod,
  /* xRelease      */ fts3ReleaseMethod,
  /* xRollbackTo   */ fts3RollbackToMethod,
  /* xShadowName   */ fts3ShadowName,
};

/*
** This function is registered as the module destructor (called when an
** FTS3 enabled database connection is closed). It frees the memory
** allocated for the tokenizer hash table.
*/

Changes to ext/fts3/fts3_aux.c.

535
536
537
538
539
540
541
542

543
544
545
546
547
548
549
550
     0,                           /* xSync         */
     0,                           /* xCommit       */
     0,                           /* xRollback     */
     0,                           /* xFindFunction */
     0,                           /* xRename       */
     0,                           /* xSavepoint    */
     0,                           /* xRelease      */
     0                            /* xRollbackTo   */

  };
  int rc;                         /* Return code */

  rc = sqlite3_create_module(db, "fts4aux", &fts3aux_module, 0);
  return rc;
}

#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */







|
>








535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
     0,                           /* xSync         */
     0,                           /* xCommit       */
     0,                           /* xRollback     */
     0,                           /* xFindFunction */
     0,                           /* xRename       */
     0,                           /* xSavepoint    */
     0,                           /* xRelease      */
     0,                           /* xRollbackTo   */
     0                            /* xShadowName   */
  };
  int rc;                         /* Return code */

  rc = sqlite3_create_module(db, "fts4aux", &fts3aux_module, 0);
  return rc;
}

#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

Changes to ext/fts3/fts3_term.c.

357
358
359
360
361
362
363
364

365
366
367
368
369
370
371
372
373
     0,                           /* xSync         */
     0,                           /* xCommit       */
     0,                           /* xRollback     */
     0,                           /* xFindFunction */
     0,                           /* xRename       */
     0,                           /* xSavepoint    */
     0,                           /* xRelease      */
     0                            /* xRollbackTo   */

  };
  int rc;                         /* Return code */

  rc = sqlite3_create_module(db, "fts4term", &fts3term_module, 0);
  return rc;
}

#endif
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */







|
>









357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
     0,                           /* xSync         */
     0,                           /* xCommit       */
     0,                           /* xRollback     */
     0,                           /* xFindFunction */
     0,                           /* xRename       */
     0,                           /* xSavepoint    */
     0,                           /* xRelease      */
     0,                           /* xRollbackTo   */
     0                            /* xShadowName   */
  };
  int rc;                         /* Return code */

  rc = sqlite3_create_module(db, "fts4term", &fts3term_module, 0);
  return rc;
}

#endif
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

Changes to ext/fts3/fts3_tokenize_vtab.c.

439
440
441
442
443
444
445
446

447
448
449
450
451
452
453
454
     0,                           /* xSync         */
     0,                           /* xCommit       */
     0,                           /* xRollback     */
     0,                           /* xFindFunction */
     0,                           /* xRename       */
     0,                           /* xSavepoint    */
     0,                           /* xRelease      */
     0                            /* xRollbackTo   */

  };
  int rc;                         /* Return code */

  rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash);
  return rc;
}

#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */







|
>








439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
     0,                           /* xSync         */
     0,                           /* xCommit       */
     0,                           /* xRollback     */
     0,                           /* xFindFunction */
     0,                           /* xRename       */
     0,                           /* xSavepoint    */
     0,                           /* xRelease      */
     0,                           /* xRollbackTo   */
     0                            /* xShadowName   */
  };
  int rc;                         /* Return code */

  rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash);
  return rc;
}

#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

Changes to ext/fts5/fts5_main.c.

2640
2641
2642
2643
2644
2645
2646















2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
....
2666
2667
2668
2669
2670
2671
2672

2673
2674
2675
2676
2677
2678
2679
  int nArg,                       /* Number of args */
  sqlite3_value **apUnused        /* Function arguments */
){
  assert( nArg==0 );
  UNUSED_PARAM2(nArg, apUnused);
  sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
}
















static int fts5Init(sqlite3 *db){
  static const sqlite3_module fts5Mod = {
    /* iVersion      */ 2,
    /* xCreate       */ fts5CreateMethod,
    /* xConnect      */ fts5ConnectMethod,
    /* xBestIndex    */ fts5BestIndexMethod,
    /* xDisconnect   */ fts5DisconnectMethod,
    /* xDestroy      */ fts5DestroyMethod,
    /* xOpen         */ fts5OpenMethod,
    /* xClose        */ fts5CloseMethod,
................................................................................
    /* xCommit       */ fts5CommitMethod,
    /* xRollback     */ fts5RollbackMethod,
    /* xFindFunction */ fts5FindFunctionMethod,
    /* xRename       */ fts5RenameMethod,
    /* xSavepoint    */ fts5SavepointMethod,
    /* xRelease      */ fts5ReleaseMethod,
    /* xRollbackTo   */ fts5RollbackToMethod,

  };

  int rc;
  Fts5Global *pGlobal = 0;

  pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
  if( pGlobal==0 ){







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



|







 







>







2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
....
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
  int nArg,                       /* Number of args */
  sqlite3_value **apUnused        /* Function arguments */
){
  assert( nArg==0 );
  UNUSED_PARAM2(nArg, apUnused);
  sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
}

/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.
*/
static int fts5ShadowName(const char *zName){
  static const char *azName[] = {
    "config", "content", "data", "docsize", "idx"
  };
  unsigned int i;
  for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
    if( sqlite3_stricmp(zName, azName[i])==0 ) return 1;
  }
  return 0;
}

static int fts5Init(sqlite3 *db){
  static const sqlite3_module fts5Mod = {
    /* iVersion      */ 3,
    /* xCreate       */ fts5CreateMethod,
    /* xConnect      */ fts5ConnectMethod,
    /* xBestIndex    */ fts5BestIndexMethod,
    /* xDisconnect   */ fts5DisconnectMethod,
    /* xDestroy      */ fts5DestroyMethod,
    /* xOpen         */ fts5OpenMethod,
    /* xClose        */ fts5CloseMethod,
................................................................................
    /* xCommit       */ fts5CommitMethod,
    /* xRollback     */ fts5RollbackMethod,
    /* xFindFunction */ fts5FindFunctionMethod,
    /* xRename       */ fts5RenameMethod,
    /* xSavepoint    */ fts5SavepointMethod,
    /* xRelease      */ fts5ReleaseMethod,
    /* xRollbackTo   */ fts5RollbackToMethod,
    /* xShadowName   */ fts5ShadowName
  };

  int rc;
  Fts5Global *pGlobal = 0;

  pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
  if( pGlobal==0 ){

Changes to ext/fts5/fts5_test_tok.c.

467
468
469
470
471
472
473
474

475
476
477
478
479
480
481
482
     0,                           /* xSync         */
     0,                           /* xCommit       */
     0,                           /* xRollback     */
     0,                           /* xFindFunction */
     0,                           /* xRename       */
     0,                           /* xSavepoint    */
     0,                           /* xRelease      */
     0                            /* xRollbackTo   */

  };
  int rc;                         /* Return code */

  rc = sqlite3_create_module(db, "fts5tokenize", &fts5tok_module, (void*)pApi);
  return rc;
}

#endif /* defined(SQLITE_TEST) && defined(SQLITE_ENABLE_FTS5) */







|
>








467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
     0,                           /* xSync         */
     0,                           /* xCommit       */
     0,                           /* xRollback     */
     0,                           /* xFindFunction */
     0,                           /* xRename       */
     0,                           /* xSavepoint    */
     0,                           /* xRelease      */
     0,                           /* xRollbackTo   */
     0                            /* xShadowName   */
  };
  int rc;                         /* Return code */

  rc = sqlite3_create_module(db, "fts5tokenize", &fts5tok_module, (void*)pApi);
  return rc;
}

#endif /* defined(SQLITE_TEST) && defined(SQLITE_ENABLE_FTS5) */

Changes to ext/fts5/fts5_vocab.c.

751
752
753
754
755
756
757

758
759
760
761
762
763
764
    /* xCommit       */ 0,
    /* xRollback     */ 0,
    /* xFindFunction */ 0,
    /* xRename       */ 0,
    /* xSavepoint    */ 0,
    /* xRelease      */ 0,
    /* xRollbackTo   */ 0,

  };
  void *p = (void*)pGlobal;

  return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0);
}









>





<
<
751
752
753
754
755
756
757
758
759
760
761
762
763


    /* xCommit       */ 0,
    /* xRollback     */ 0,
    /* xFindFunction */ 0,
    /* xRename       */ 0,
    /* xSavepoint    */ 0,
    /* xRelease      */ 0,
    /* xRollbackTo   */ 0,
    /* xShadowName   */ 0
  };
  void *p = (void*)pGlobal;

  return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0);
}


Changes to ext/fts5/test/fts5aa.test.

405
406
407
408
409
410
411

412
413
414
415
416
417
418
  }
  set nRow
} {200}

do_execsql_test 15.0 {
  INSERT INTO t1(t1) VALUES('integrity-check');
}

do_execsql_test 15.1 {
  UPDATE t1_content SET c1 = 'xyz xyz xyz xyz xyz abc' WHERE rowid = 1;
}
do_catchsql_test 15.2 {
  INSERT INTO t1(t1) VALUES('integrity-check');
} {1 {database disk image is malformed}}








>







405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  }
  set nRow
} {200}

do_execsql_test 15.0 {
  INSERT INTO t1(t1) VALUES('integrity-check');
}
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 15.1 {
  UPDATE t1_content SET c1 = 'xyz xyz xyz xyz xyz abc' WHERE rowid = 1;
}
do_catchsql_test 15.2 {
  INSERT INTO t1(t1) VALUES('integrity-check');
} {1 {database disk image is malformed}}

Changes to ext/fts5/test/fts5connect.test.

240
241
242
243
244
245
246
247

  do_execsql_test 4.$tn.3 {
    INSERT INTO ft3(ft3) VALUES('integrity-check');
  }
}

finish_test








<
240
241
242
243
244
245
246


  do_execsql_test 4.$tn.3 {
    INSERT INTO ft3(ft3) VALUES('integrity-check');
  }
}

finish_test

Changes to ext/fts5/test/fts5corrupt.test.

37
38
39
40
41
42
43

44
45
46
47
48
49
50
51
52

53
54
55
56
57
58
59
..
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  fts5_level_segs t1
} {1}
db_save

do_execsql_test 1.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
set segid [lindex [fts5_level_segids t1] 0]


do_test 1.3 {
  execsql {
    DELETE FROM t1_data WHERE rowid = fts5_rowid('segment', $segid, 4);
  }
  catchsql { INSERT INTO t1(t1) VALUES('integrity-check') }
} {1 {database disk image is malformed}}

do_test 1.4 {
  db_restore_and_reopen

  execsql {
    UPDATE t1_data set block = X'00000000' || substr(block, 5) WHERE
    rowid = fts5_rowid('segment', $segid, 4);
  }
  catchsql { INSERT INTO t1(t1) VALUES('integrity-check') }
} {1 {database disk image is malformed}}

................................................................................
  INSERT INTO t3 VALUES('three o');
  INSERT INTO t3 VALUES('four e');
  INSERT INTO t3 VALUES('five o');
}
do_execsql_test 3.1 {
  SELECT * FROM t3 WHERE t3 MATCH 'o'
} {{one o} {three o} {five o}}

do_catchsql_test 3.1 {
  DELETE FROM t3_content WHERE rowid = 3;
  SELECT * FROM t3 WHERE t3 MATCH 'o';
} {1 {database disk image is malformed}}

finish_test







>









>







 







|






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
..
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  fts5_level_segs t1
} {1}
db_save

do_execsql_test 1.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
set segid [lindex [fts5_level_segids t1] 0]

sqlite3_db_config db DEFENSIVE 0
do_test 1.3 {
  execsql {
    DELETE FROM t1_data WHERE rowid = fts5_rowid('segment', $segid, 4);
  }
  catchsql { INSERT INTO t1(t1) VALUES('integrity-check') }
} {1 {database disk image is malformed}}

do_test 1.4 {
  db_restore_and_reopen
  sqlite3_db_config db DEFENSIVE 0
  execsql {
    UPDATE t1_data set block = X'00000000' || substr(block, 5) WHERE
    rowid = fts5_rowid('segment', $segid, 4);
  }
  catchsql { INSERT INTO t1(t1) VALUES('integrity-check') }
} {1 {database disk image is malformed}}

................................................................................
  INSERT INTO t3 VALUES('three o');
  INSERT INTO t3 VALUES('four e');
  INSERT INTO t3 VALUES('five o');
}
do_execsql_test 3.1 {
  SELECT * FROM t3 WHERE t3 MATCH 'o'
} {{one o} {three o} {five o}}
sqlite3_db_config db DEFENSIVE 0
do_catchsql_test 3.1 {
  DELETE FROM t3_content WHERE rowid = 3;
  SELECT * FROM t3 WHERE t3 MATCH 'o';
} {1 {database disk image is malformed}}

finish_test

Changes to ext/fts5/test/fts5corrupt2.test.

95
96
97
98
99
100
101

102
103
104
105
106
107
108
...
244
245
246
247
248
249
250

251
252
253
254
255
256
257
# Also tested is that "MATCH 'x*'" does not crash and sometimes reports
# corruption. It may not report the db as corrupt because truncating the
# final leaf to some sizes may create a valid leaf page.
#
set lrowid [db one {SELECT max(rowid) FROM t1_data WHERE (rowid & $mask)=0}] 
set nbyte [db one {SELECT length(block) FROM t1_data WHERE rowid=$lrowid}]
set all [db eval {SELECT rowid FROM t1}]

for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} {
  do_execsql_test 2.$i.1 {
    BEGIN;
      UPDATE t1_data SET block = substr(block, 1, $i) WHERE rowid=$lrowid;
  }

  do_catchsql_test 2.$i.2 {
................................................................................

    execsql ROLLBACK
  }
}

#--------------------------------------------------------------------
reset_db

do_execsql_test 6.1 {
  CREATE VIRTUAL TABLE x5 USING fts5(tt);
  INSERT INTO x5 VALUES('a');
  INSERT INTO x5 VALUES('a a');
  INSERT INTO x5 VALUES('a a a');
  INSERT INTO x5 VALUES('a a a a');








>







 







>







95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# Also tested is that "MATCH 'x*'" does not crash and sometimes reports
# corruption. It may not report the db as corrupt because truncating the
# final leaf to some sizes may create a valid leaf page.
#
set lrowid [db one {SELECT max(rowid) FROM t1_data WHERE (rowid & $mask)=0}] 
set nbyte [db one {SELECT length(block) FROM t1_data WHERE rowid=$lrowid}]
set all [db eval {SELECT rowid FROM t1}]
sqlite3_db_config db DEFENSIVE 0
for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} {
  do_execsql_test 2.$i.1 {
    BEGIN;
      UPDATE t1_data SET block = substr(block, 1, $i) WHERE rowid=$lrowid;
  }

  do_catchsql_test 2.$i.2 {
................................................................................

    execsql ROLLBACK
  }
}

#--------------------------------------------------------------------
reset_db
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 6.1 {
  CREATE VIRTUAL TABLE x5 USING fts5(tt);
  INSERT INTO x5 VALUES('a');
  INSERT INTO x5 VALUES('a a');
  INSERT INTO x5 VALUES('a a a');
  INSERT INTO x5 VALUES('a a a a');

Changes to ext/fts5/test/fts5corrupt3.test.

47
48
49
50
51
52
53

54
55
56
57
58
59
60
..
82
83
84
85
86
87
88

89
90
91
92
93
94
95
...
154
155
156
157
158
159
160

161
162
163
164
165
166
167
...
178
179
180
181
182
183
184

185
186
187
188
189
190
191
...
253
254
255
256
257
258
259

260
261
262
263
264
265
266
...
269
270
271
272
273
274
275

276
277
278
279
280
281
282
...
284
285
286
287
288
289
290

291
292
293
294
295
296
297
...
358
359
360
361
362
363
364

365
366
367
368
369
370
371
...
379
380
381
382
383
384
385

386
387
388
389
390
391
392
  set rowid [db one {
    SELECT max(rowid) FROM t1_data WHERE ((rowid>>31) & 0x0F)==1
  }]
  set L [db one {SELECT length(block) FROM t1_data WHERE rowid = $rowid}]
  set {} {}
} {} 


for {set i 0} {$i < $L} {incr i} {
  do_test 1.2.$i {
    catchsql {
      BEGIN;
      UPDATE t1_data SET block = substr(block, 1, $i) WHERE id = $rowid;
      INSERT INTO t1(t1) VALUES('integrity-check');
    }
................................................................................


#-------------------------------------------------------------------------
# Test that missing leaf pages are recognized as corruption.
#
reset_db
do_test 3.0 { create_t1 } {}


do_execsql_test 3.1 {
  SELECT count(*) FROM t1_data;
} {105}

proc do_3_test {tn} {
  set i 0
................................................................................

do_3_test 3.10

#-------------------------------------------------------------------------
# Test that segments that end unexpectedly are identified as corruption.
#
reset_db

do_test 4.0 {
  execsql { 
    CREATE VIRTUAL TABLE t1 USING fts5(x);
    INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
  }
  for {set i 0} {$i < 100} {incr i} {
    set rnd [expr int(rand() * 100)]
................................................................................
  set end [lindex $var end]
  if {$end<=$i} break
  lset var end [expr $end - $i]
  set struct [binary format c* $var]

  db close
  sqlite3 db test.db


  db eval {
    BEGIN;
    UPDATE t1_data SET block = $struct WHERE id=10;
  }
  do_test 4.1.$i {
    incr nErr [catch { db eval { SELECT rowid FROM t1 WHERE t1 MATCH 'x*' } }]
................................................................................
    catch { db eval ROLLBACK }
  }
}

#------------------------------------------------------------------------
#
reset_db

do_execsql_test 6.1.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(a);
  INSERT INTO t1 VALUES('bbbbb ccccc');
  SELECT quote(block) FROM t1_data WHERE rowid>100;
} {X'000000180630626262626201020201056363636363010203040A'}
do_execsql_test 6.1.1 {
  UPDATE t1_data SET block = 
................................................................................
}
do_catchsql_test 6.1.2 {
  INSERT INTO t1(t1) VALUES('integrity-check');
} {1 {database disk image is malformed}}

#-------
reset_db

do_execsql_test 6.2.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(a);
  INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
  INSERT INTO t1 VALUES('aa bb cc dd ee');
  SELECT pgno, quote(term) FROM t1_idx;
} {2 X'' 4 X'3064'}
do_execsql_test 6.2.1 {
................................................................................
}
do_catchsql_test 6.2.2 {
  INSERT INTO t1(t1) VALUES('integrity-check');
} {1 {database disk image is malformed}}

#-------
reset_db

do_execsql_test 6.3.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(a);
  INSERT INTO t1 VALUES('abc abcdef abcdefghi');
  SELECT quote(block) FROM t1_data WHERE id>100;
}    {X'0000001C043061626301020204036465660102030703676869010204040808'}
do_execsql_test 6.3.1 {
  BEGIN;
................................................................................
    INSERT INTO t5 VALUES( rnddoc(10000) );
    INSERT INTO t5 VALUES( rnddoc(10000) );
    INSERT INTO t5 VALUES( rnddoc(10000) );
    INSERT INTO t5(t5) VALUES('optimize');
  }
} {}


do_test 7.1 {
  foreach i [db eval { SELECT rowid FROM t5_data WHERE rowid>100 }] {
    db eval BEGIN  
    db eval {DELETE FROM t5_data WHERE rowid = $i}
    set r [catchsql { INSERT INTO t5(t5) VALUES('integrity-check')} ]
    if {$r != "1 {database disk image is malformed}"} { error $r }
    db eval ROLLBACK  
................................................................................
#
reset_db
do_execsql_test 8.1 {
  CREATE VIRTUAL TABLE t1 USING fts5(x, y);
  INSERT INTO t1 VALUES('one', 'two');
}


do_test 9.1.1 {
  set    blob "12345678"    ;# cookie
  append blob "0105"        ;# 1 level, total of 5 segments
  append blob "06"          ;# write counter
  append blob "0002"        ;# first level has 0 segments merging, 2 other.
  append blob "450108"      ;# first segment
  execsql "REPLACE INTO t1_data VALUES(10, X'$blob')"







>







 







>







 







>







 







>







 







>







 







>







 







>







 







>







 







>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
..
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
...
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
...
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
  set rowid [db one {
    SELECT max(rowid) FROM t1_data WHERE ((rowid>>31) & 0x0F)==1
  }]
  set L [db one {SELECT length(block) FROM t1_data WHERE rowid = $rowid}]
  set {} {}
} {} 

sqlite3_db_config db DEFENSIVE 0
for {set i 0} {$i < $L} {incr i} {
  do_test 1.2.$i {
    catchsql {
      BEGIN;
      UPDATE t1_data SET block = substr(block, 1, $i) WHERE id = $rowid;
      INSERT INTO t1(t1) VALUES('integrity-check');
    }
................................................................................


#-------------------------------------------------------------------------
# Test that missing leaf pages are recognized as corruption.
#
reset_db
do_test 3.0 { create_t1 } {}
sqlite3_db_config db DEFENSIVE 0

do_execsql_test 3.1 {
  SELECT count(*) FROM t1_data;
} {105}

proc do_3_test {tn} {
  set i 0
................................................................................

do_3_test 3.10

#-------------------------------------------------------------------------
# Test that segments that end unexpectedly are identified as corruption.
#
reset_db
sqlite3_db_config db DEFENSIVE 0
do_test 4.0 {
  execsql { 
    CREATE VIRTUAL TABLE t1 USING fts5(x);
    INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
  }
  for {set i 0} {$i < 100} {incr i} {
    set rnd [expr int(rand() * 100)]
................................................................................
  set end [lindex $var end]
  if {$end<=$i} break
  lset var end [expr $end - $i]
  set struct [binary format c* $var]

  db close
  sqlite3 db test.db
  sqlite3_db_config db DEFENSIVE 0

  db eval {
    BEGIN;
    UPDATE t1_data SET block = $struct WHERE id=10;
  }
  do_test 4.1.$i {
    incr nErr [catch { db eval { SELECT rowid FROM t1 WHERE t1 MATCH 'x*' } }]
................................................................................
    catch { db eval ROLLBACK }
  }
}

#------------------------------------------------------------------------
#
reset_db
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 6.1.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(a);
  INSERT INTO t1 VALUES('bbbbb ccccc');
  SELECT quote(block) FROM t1_data WHERE rowid>100;
} {X'000000180630626262626201020201056363636363010203040A'}
do_execsql_test 6.1.1 {
  UPDATE t1_data SET block = 
................................................................................
}
do_catchsql_test 6.1.2 {
  INSERT INTO t1(t1) VALUES('integrity-check');
} {1 {database disk image is malformed}}

#-------
reset_db
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 6.2.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(a);
  INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
  INSERT INTO t1 VALUES('aa bb cc dd ee');
  SELECT pgno, quote(term) FROM t1_idx;
} {2 X'' 4 X'3064'}
do_execsql_test 6.2.1 {
................................................................................
}
do_catchsql_test 6.2.2 {
  INSERT INTO t1(t1) VALUES('integrity-check');
} {1 {database disk image is malformed}}

#-------
reset_db
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 6.3.0 {
  CREATE VIRTUAL TABLE t1 USING fts5(a);
  INSERT INTO t1 VALUES('abc abcdef abcdefghi');
  SELECT quote(block) FROM t1_data WHERE id>100;
}    {X'0000001C043061626301020204036465660102030703676869010204040808'}
do_execsql_test 6.3.1 {
  BEGIN;
................................................................................
    INSERT INTO t5 VALUES( rnddoc(10000) );
    INSERT INTO t5 VALUES( rnddoc(10000) );
    INSERT INTO t5 VALUES( rnddoc(10000) );
    INSERT INTO t5(t5) VALUES('optimize');
  }
} {}

sqlite3_db_config db DEFENSIVE 0
do_test 7.1 {
  foreach i [db eval { SELECT rowid FROM t5_data WHERE rowid>100 }] {
    db eval BEGIN  
    db eval {DELETE FROM t5_data WHERE rowid = $i}
    set r [catchsql { INSERT INTO t5(t5) VALUES('integrity-check')} ]
    if {$r != "1 {database disk image is malformed}"} { error $r }
    db eval ROLLBACK  
................................................................................
#
reset_db
do_execsql_test 8.1 {
  CREATE VIRTUAL TABLE t1 USING fts5(x, y);
  INSERT INTO t1 VALUES('one', 'two');
}

sqlite3_db_config db DEFENSIVE 0
do_test 9.1.1 {
  set    blob "12345678"    ;# cookie
  append blob "0105"        ;# 1 level, total of 5 segments
  append blob "06"          ;# write counter
  append blob "0002"        ;# first level has 0 segments merging, 2 other.
  append blob "450108"      ;# first segment
  execsql "REPLACE INTO t1_data VALUES(10, X'$blob')"

Changes to ext/fts5/test/fts5first.test.

89
90
91
92
93
94
95
96
  SELECT * FROM x2('a + b');
} {1 {fts5: phrase queries are not supported (detail!=full)}}

do_catchsql_test 3.3 {
  SELECT * FROM x2('^a');
} {1 {fts5: phrase queries are not supported (detail!=full)}}
finish_test








<
89
90
91
92
93
94
95

  SELECT * FROM x2('a + b');
} {1 {fts5: phrase queries are not supported (detail!=full)}}

do_catchsql_test 3.3 {
  SELECT * FROM x2('^a');
} {1 {fts5: phrase queries are not supported (detail!=full)}}
finish_test

Changes to ext/fts5/test/fts5integrity.test.

67
68
69
70
71
72
73

74
75
76
77
78
79
80
  INSERT INTO aa(zz) VALUES('a');
  SELECT length(sz) FROM aa_docsize;
} {1 1 1 1 1}
do_execsql_test 4.1 { 
  INSERT INTO aa(aa) VALUES('integrity-check'); 
}


do_catchsql_test 4.2 { 
  BEGIN;
    UPDATE aa_docsize SET sz = X'44' WHERE rowid = 3;
    INSERT INTO aa(aa) VALUES('integrity-check'); 
} {1 {database disk image is malformed}}

do_catchsql_test 4.3 { 







>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  INSERT INTO aa(zz) VALUES('a');
  SELECT length(sz) FROM aa_docsize;
} {1 1 1 1 1}
do_execsql_test 4.1 { 
  INSERT INTO aa(aa) VALUES('integrity-check'); 
}

sqlite3_db_config db DEFENSIVE 0
do_catchsql_test 4.2 { 
  BEGIN;
    UPDATE aa_docsize SET sz = X'44' WHERE rowid = 3;
    INSERT INTO aa(aa) VALUES('integrity-check'); 
} {1 {database disk image is malformed}}

do_catchsql_test 4.3 { 

Changes to ext/fts5/test/fts5rank.test.

159
160
161
162
163
164
165
166
}

do_execsql_test 5.1 {
  SELECT rowid FROM ttt('word') WHERE rowid BETWEEN 30 AND 40 ORDER BY rank;
} {30 31 32 33 34 35 36 37 38 39 40}

finish_test








<
159
160
161
162
163
164
165

}

do_execsql_test 5.1 {
  SELECT rowid FROM ttt('word') WHERE rowid BETWEEN 30 AND 40 ORDER BY rank;
} {30 31 32 33 34 35 36 37 38 39 40}

finish_test

Changes to ext/fts5/test/fts5rebuild.test.

35
36
37
38
39
40
41

42
43
44
45
46
47
48
  INSERT INTO f1(f1) VALUES('rebuild');
} {}

do_execsql_test 1.4 {
  INSERT INTO f1(f1) VALUES('integrity-check');
} {}


do_execsql_test 1.5 {
  DELETE FROM f1_data;
} {}

do_catchsql_test 1.6 {
  INSERT INTO f1(f1) VALUES('integrity-check');
} {1 {database disk image is malformed}}







>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  INSERT INTO f1(f1) VALUES('rebuild');
} {}

do_execsql_test 1.4 {
  INSERT INTO f1(f1) VALUES('integrity-check');
} {}

sqlite3_db_config db DEFENSIVE 0
do_execsql_test 1.5 {
  DELETE FROM f1_data;
} {}

do_catchsql_test 1.6 {
  INSERT INTO f1(f1) VALUES('integrity-check');
} {1 {database disk image is malformed}}

Changes to ext/fts5/test/fts5rowid.test.

66
67
68
69
70
71
72

73
74
75
76
77
78
79
  DELETE FROM x1 WHERE (rowid%2);
}

set res [db one {SELECT count(*) FROM x1_data}]
do_execsql_test 2.3 {
  SELECT count(fts5_decode(rowid, block)) FROM x1_data;
} $res

do_execsql_test 2.4 {
  UPDATE x1_data SET block = X'';
  SELECT count(fts5_decode(rowid, block)) FROM x1_data;
} $res

do_execsql_test 2.5 {
  INSERT INTO x1(x1, rank) VALUES('pgsz', 1024);







>







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  DELETE FROM x1 WHERE (rowid%2);
}

set res [db one {SELECT count(*) FROM x1_data}]
do_execsql_test 2.3 {
  SELECT count(fts5_decode(rowid, block)) FROM x1_data;
} $res
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 2.4 {
  UPDATE x1_data SET block = X'';
  SELECT count(fts5_decode(rowid, block)) FROM x1_data;
} $res

do_execsql_test 2.5 {
  INSERT INTO x1(x1, rank) VALUES('pgsz', 1024);

Changes to ext/fts5/test/fts5version.test.

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
  SELECT * FROM t1_config WHERE k='version'
} {version 4}

do_execsql_test 1.3 {
  SELECT rowid FROM t1 WHERE t1 MATCH 'a';
} {1}


do_execsql_test 1.4 {
  UPDATE t1_config set v=5 WHERE k='version';
} 

do_test 1.5 {
  db close
  sqlite3 db test.db
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'a' }
} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}}

................................................................................
do_test 1.6 {
  db close
  sqlite3 db test.db
  catchsql { INSERT INTO t1 VALUES('x y z') }
} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}}

do_test 1.7 {

  execsql { DELETE FROM t1_config WHERE k='version' }
  db close
  sqlite3 db test.db
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'a' }
} {1 {invalid fts5 file format (found 0, expected 4) - run 'rebuild'}}


finish_test







>


|







 







>








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
  SELECT * FROM t1_config WHERE k='version'
} {version 4}

do_execsql_test 1.3 {
  SELECT rowid FROM t1 WHERE t1 MATCH 'a';
} {1}

sqlite3_db_config db DEFENSIVE 0
do_execsql_test 1.4 {
  UPDATE t1_config set v=5 WHERE k='version';
}

do_test 1.5 {
  db close
  sqlite3 db test.db
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'a' }
} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}}

................................................................................
do_test 1.6 {
  db close
  sqlite3 db test.db
  catchsql { INSERT INTO t1 VALUES('x y z') }
} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}}

do_test 1.7 {
  sqlite3_db_config db DEFENSIVE 0
  execsql { DELETE FROM t1_config WHERE k='version' }
  db close
  sqlite3 db test.db
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'a' }
} {1 {invalid fts5 file format (found 0, expected 4) - run 'rebuild'}}


finish_test

Changes to ext/fts5/test/fts5vocab.test.

416
417
418
419
420
421
422

423
424
425
426
427
428
429
...
477
478
479
480
481
482
483
484
  i a 1 1 i b 1 1 i c 1 1
}]
if {[detail_is_none]} { set resc [row_to_col $resr] }

do_execsql_test 8.1.1 { SELECT * FROM x1_r; } $resr
do_execsql_test 8.1.2 { SELECT * FROM x1_c } $resc


do_execsql_test 8.2 {
  PRAGMA writable_schema = 1;
  UPDATE sqlite_master 
  SET sql = 'CREATE VIRTUAL TABLE x1 USING fts5(a, detail=%DETAIL%)'
  WHERE name = 'x1';
}
db close
................................................................................
  set e2 [db eval { EXPLAIN SELECT * FROM rrr ORDER BY term DESC }]
  expr [lsearch $e2 SorterSort]<0
} 0



finish_test








>







 







<
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
...
478
479
480
481
482
483
484

  i a 1 1 i b 1 1 i c 1 1
}]
if {[detail_is_none]} { set resc [row_to_col $resr] }

do_execsql_test 8.1.1 { SELECT * FROM x1_r; } $resr
do_execsql_test 8.1.2 { SELECT * FROM x1_c } $resc

sqlite3_db_config db DEFENSIVE 0
do_execsql_test 8.2 {
  PRAGMA writable_schema = 1;
  UPDATE sqlite_master 
  SET sql = 'CREATE VIRTUAL TABLE x1 USING fts5(a, detail=%DETAIL%)'
  WHERE name = 'x1';
}
db close
................................................................................
  set e2 [db eval { EXPLAIN SELECT * FROM rrr ORDER BY term DESC }]
  expr [lsearch $e2 SorterSort]<0
} 0



finish_test

Changes to ext/fts5/test/fts5vocab2.test.

202
203
204
205
206
207
208
209
do_execsql_test 3.5 {
  DELETE FROM t1;
  SELECT * FROM v1;
} {
}

finish_test








<
202
203
204
205
206
207
208

do_execsql_test 3.5 {
  DELETE FROM t1;
  SELECT * FROM v1;
} {
}

finish_test

Changes to ext/misc/amatch.c.

1469
1470
1471
1472
1473
1474
1475
1476

1477
1478
1479
1480
1481
1482
1483
  0,                      /* xSync */
  0,                      /* xCommit */
  0,                      /* xRollback */
  0,                      /* xFindMethod */
  0,                      /* xRename */
  0,                      /* xSavepoint */
  0,                      /* xRelease */
  0                       /* xRollbackTo */

};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

/*
** Register the amatch virtual table
*/







|
>







1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
  0,                      /* xSync */
  0,                      /* xCommit */
  0,                      /* xRollback */
  0,                      /* xFindMethod */
  0,                      /* xRename */
  0,                      /* xSavepoint */
  0,                      /* xRelease */
  0,                      /* xRollbackTo */
  0                       /* xShadowName */
};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

/*
** Register the amatch virtual table
*/

Changes to ext/misc/btreeinfo.c.

407
408
409
410
411
412
413

414
415
416
417
418
419
420
    0,                           /* xCommit */
    0,                           /* xRollback */
    0,                           /* xFindMethod */
    0,                           /* xRename */
    0,                           /* xSavepoint */
    0,                           /* xRelease */
    0,                           /* xRollbackTo */

  };
  return sqlite3_create_module(db, "sqlite_btreeinfo", &binfo_module, 0);
}

#ifdef _WIN32
__declspec(dllexport)
#endif







>







407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
    0,                           /* xCommit */
    0,                           /* xRollback */
    0,                           /* xFindMethod */
    0,                           /* xRename */
    0,                           /* xSavepoint */
    0,                           /* xRelease */
    0,                           /* xRollbackTo */
    0                            /* xShadowName */
  };
  return sqlite3_create_module(db, "sqlite_btreeinfo", &binfo_module, 0);
}

#ifdef _WIN32
__declspec(dllexport)
#endif

Changes to ext/misc/closure.c.

934
935
936
937
938
939
940
941

942
943
944
945
946
947
948
  0,                      /* xSync */
  0,                      /* xCommit */
  0,                      /* xRollback */
  0,                      /* xFindMethod */
  0,                      /* xRename */
  0,                      /* xSavepoint */
  0,                      /* xRelease */
  0                       /* xRollbackTo */

};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

/*
** Register the closure virtual table
*/







|
>







934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
  0,                      /* xSync */
  0,                      /* xCommit */
  0,                      /* xRollback */
  0,                      /* xFindMethod */
  0,                      /* xRename */
  0,                      /* xSavepoint */
  0,                      /* xRelease */
  0,                      /* xRollbackTo */
  0                       /* xShadowName */
};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

/*
** Register the closure virtual table
*/

Changes to ext/misc/completion.c.

464
465
466
467
468
469
470
471

472
473
474
475
476
477
478
  0,                         /* xSync */
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0                          /* xRollbackTo */

};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

int sqlite3CompletionVtabInit(sqlite3 *db){
  int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_VIRTUALTABLE







|
>







464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
  0,                         /* xSync */
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0,                         /* xRollbackTo */
  0                          /* xShadowName */
};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

int sqlite3CompletionVtabInit(sqlite3 *db){
  int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_VIRTUALTABLE

Changes to ext/misc/explain.c.

276
277
278
279
280
281
282

283
284
285
286
287
288
289
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0,                         /* xRollbackTo */

};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

int sqlite3ExplainVtabInit(sqlite3 *db){
  int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_VIRTUALTABLE







>







276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0,                         /* xRollbackTo */
  0,                         /* xShadowName */
};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

int sqlite3ExplainVtabInit(sqlite3 *db){
  int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_VIRTUALTABLE

Changes to ext/misc/fileio.c.

884
885
886
887
888
889
890
891

892
893
894
895
896
897
898
    0,                         /* xSync */
    0,                         /* xCommit */
    0,                         /* xRollback */
    0,                         /* xFindMethod */
    0,                         /* xRename */
    0,                         /* xSavepoint */
    0,                         /* xRelease */
    0                          /* xRollbackTo */

  };

  int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
  return rc;
}
#else         /* SQLITE_OMIT_VIRTUALTABLE */
# define fsdirRegister(x) SQLITE_OK







|
>







884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
    0,                         /* xSync */
    0,                         /* xCommit */
    0,                         /* xRollback */
    0,                         /* xFindMethod */
    0,                         /* xRename */
    0,                         /* xSavepoint */
    0,                         /* xRelease */
    0,                         /* xRollbackTo */
    0,                         /* xShadowName */
  };

  int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
  return rc;
}
#else         /* SQLITE_OMIT_VIRTUALTABLE */
# define fsdirRegister(x) SQLITE_OK

Changes to ext/misc/json1.c.

2384
2385
2386
2387
2388
2389
2390
2391

2392
2393
2394
2395
2396
2397
2398
....
2411
2412
2413
2414
2415
2416
2417
2418

2419
2420
2421
2422
2423
2424
2425
  0,                         /* xSync */
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0                          /* xRollbackTo */

};

/* The methods of the json_tree virtual table. */
static sqlite3_module jsonTreeModule = {
  0,                         /* iVersion */
  0,                         /* xCreate */
  jsonEachConnect,           /* xConnect */
................................................................................
  0,                         /* xSync */
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0                          /* xRollbackTo */

};
#endif /* SQLITE_OMIT_VIRTUALTABLE */

/****************************************************************************
** The following routines are the only publically visible identifiers in this
** file.  Call the following routines in order to register the various SQL
** functions and the virtual table implemented by this file.







|
>







 







|
>







2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
....
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
  0,                         /* xSync */
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0,                         /* xRollbackTo */
  0                          /* xShadowName */
};

/* The methods of the json_tree virtual table. */
static sqlite3_module jsonTreeModule = {
  0,                         /* iVersion */
  0,                         /* xCreate */
  jsonEachConnect,           /* xConnect */
................................................................................
  0,                         /* xSync */
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0,                         /* xRollbackTo */
  0                          /* xShadowName */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */

/****************************************************************************
** The following routines are the only publically visible identifiers in this
** file.  Call the following routines in order to register the various SQL
** functions and the virtual table implemented by this file.

Changes to ext/misc/memstat.c.

391
392
393
394
395
396
397

398
399
400
401
402
403
404
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0,                         /* xRollbackTo */

};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

int sqlite3MemstatVtabInit(sqlite3 *db){
  int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_VIRTUALTABLE







>







391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0,                         /* xRollbackTo */
  0,                         /* xShadowName */
};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

int sqlite3MemstatVtabInit(sqlite3 *db){
  int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_VIRTUALTABLE

Changes to ext/misc/stmt.c.

262
263
264
265
266
267
268

269
270
271
272
273
274
275
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0,                         /* xRollbackTo */

};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

int sqlite3StmtVtabInit(sqlite3 *db){
  int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_VIRTUALTABLE







>







262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0,                         /* xRollbackTo */
  0,                         /* xShadowName */
};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

int sqlite3StmtVtabInit(sqlite3 *db){
  int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_VIRTUALTABLE

Changes to ext/misc/templatevtab.c.

244
245
246
247
248
249
250
251

252
253
254
255
256
257
258
  /* xSync       */ 0,
  /* xCommit     */ 0,
  /* xRollback   */ 0,
  /* xFindMethod */ 0,
  /* xRename     */ 0,
  /* xSavepoint  */ 0,
  /* xRelease    */ 0,
  /* xRollbackTo */ 0

};


#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_templatevtab_init(







|
>







244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
  /* xSync       */ 0,
  /* xCommit     */ 0,
  /* xRollback   */ 0,
  /* xFindMethod */ 0,
  /* xRename     */ 0,
  /* xSavepoint  */ 0,
  /* xRelease    */ 0,
  /* xRollbackTo */ 0,
  /* xShadowName */ 0
};


#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_templatevtab_init(

Changes to ext/misc/unionvtab.c.

1346
1347
1348
1349
1350
1351
1352
1353

1354
1355
1356
1357
1358
1359
1360
    0,                            /* xSync */
    0,                            /* xCommit */
    0,                            /* xRollback */
    0,                            /* xFindMethod */
    0,                            /* xRename */
    0,                            /* xSavepoint */
    0,                            /* xRelease */
    0                             /* xRollbackTo */

  };
  int rc;

  rc = sqlite3_create_module(db, "unionvtab", &unionModule, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_module(db, "swarmvtab", &unionModule, (void*)db);
  }







|
>







1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
    0,                            /* xSync */
    0,                            /* xCommit */
    0,                            /* xRollback */
    0,                            /* xFindMethod */
    0,                            /* xRename */
    0,                            /* xSavepoint */
    0,                            /* xRelease */
    0,                            /* xRollbackTo */
    0                             /* xShadowName */
  };
  int rc;

  rc = sqlite3_create_module(db, "unionvtab", &unionModule, 0);
  if( rc==SQLITE_OK ){
    rc = sqlite3_create_module(db, "swarmvtab", &unionModule, (void*)db);
  }

Changes to ext/misc/vtablog.c.

488
489
490
491
492
493
494

495
496
497
498
499
500
501
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0,                         /* xRollbackTo */

};

#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_vtablog_init(
  sqlite3 *db, 







>







488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
  0,                         /* xSavepoint */
  0,                         /* xRelease */
  0,                         /* xRollbackTo */
  0,                         /* xShadowName */
};

#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_vtablog_init(
  sqlite3 *db, 

Changes to ext/rbu/rbu1.test.

666
667
668
669
670
671
672
673

  catch { db close }
  eval $destroy_vfs
}


finish_test








<
666
667
668
669
670
671
672


  catch { db close }
  eval $destroy_vfs
}


finish_test

Changes to ext/rbu/rbu10.test.

181
182
183
184
185
186
187
188
    INSERT INTO data_t3 VALUES(1, 'abc', '-6.0', 0);
  }
  list [catch { apply_rbu $rbu } msg] $msg
} {0 SQLITE_DONE}


finish_test








<
181
182
183
184
185
186
187

    INSERT INTO data_t3 VALUES(1, 'abc', '-6.0', 0);
  }
  list [catch { apply_rbu $rbu } msg] $msg
} {0 SQLITE_DONE}


finish_test

Changes to ext/rbu/rbu11.test.

191
192
193
194
195
196
197
198
  rbu step
} {SQLITE_ERROR}
do_test 4.7.2 {
  list [catch {rbu close} msg] $msg
} {1 {SQLITE_ERROR - rbu_state mismatch error}}

finish_test








<
191
192
193
194
195
196
197

  rbu step
} {SQLITE_ERROR}
do_test 4.7.2 {
  list [catch {rbu close} msg] $msg
} {1 {SQLITE_ERROR - rbu_state mismatch error}}

finish_test

Changes to ext/rbu/rbu12.test.

228
229
230
231
232
233
234
235
  do_test 2.$tn.6 {
    list [sql1 {PRAGMA data_version}] [sql2 {PRAGMA data_version}]
  } [list $V1 $V2]

}

finish_test








<
228
229
230
231
232
233
234

  do_test 2.$tn.6 {
    list [sql1 {PRAGMA data_version}] [sql2 {PRAGMA data_version}]
  } [list $V1 $V2]

}

finish_test

Changes to ext/rbu/rbu13.test.

58
59
60
61
62
63
64
65
do_execsql_test 1.4 {
  SELECT count(*) FROM t1 WHERE
  a == ( (b<<6) + (c<<5) + (d<<4) + (e<<3) + (f<<2) + (g<<1) + (h<<0) )
} {128}


finish_test








<
58
59
60
61
62
63
64

do_execsql_test 1.4 {
  SELECT count(*) FROM t1 WHERE
  a == ( (b<<6) + (c<<5) + (d<<4) + (e<<3) + (f<<2) + (g<<1) + (h<<0) )
} {128}


finish_test

Changes to ext/rbu/rbu14.test.

88
89
90
91
92
93
94
95
  } {4 5 6 50 50 50}

  integrity_check $tn.4
}


finish_test








<
88
89
90
91
92
93
94

  } {4 5 6 50 50 50}

  integrity_check $tn.4
}


finish_test

Changes to ext/rbu/rbu3.test.

199
200
201
202
203
204
205
206
207
do_test 5.3 {
  expr {[file size test.db-wal] > (1024 * 1200)}
} 1

do_test 6.1 { sqlite3rbu_internal_test } {}

finish_test









<
<
199
200
201
202
203
204
205


do_test 5.3 {
  expr {[file size test.db-wal] > (1024 * 1200)}
} 1

do_test 6.1 { sqlite3rbu_internal_test } {}

finish_test


Changes to ext/rbu/rbu5.test.

296
297
298
299
300
301
302
303
304
305
306

    db close
  }
}


finish_test











<
<
<
<
296
297
298
299
300
301
302





    db close
  }
}


finish_test




Changes to ext/rbu/rbu6.test.

96
97
98
99
100
101
102
103
  do_execsql_test 1.$nStep.5 {
    SELECT * FROM t1;
  } {1 t1 5 hello}
}


finish_test








<
96
97
98
99
100
101
102

  do_execsql_test 1.$nStep.5 {
    SELECT * FROM t1;
  } {1 t1 5 hello}
}


finish_test

Changes to ext/rbu/rbu7.test.

102
103
104
105
106
107
108
109
110
    2 2 d
    3 1 e
    3 2 f
  }
}

finish_test









<
<
102
103
104
105
106
107
108


    2 2 d
    3 1 e
    3 2 f
  }
}

finish_test


Changes to ext/rbu/rbu8.test.

68
69
70
71
72
73
74
75
  {}   2 2
  _iii 3 three-III
}
integrity_check 1.3.3


finish_test








<
68
69
70
71
72
73
74

  {}   2 2
  _iii 3 three-III
}
integrity_check 1.3.3


finish_test

Changes to ext/rbu/rbu9.test.

121
122
123
124
125
126
127
128
  }
  
  integrity_check 2.$tn.4
}


finish_test








<
121
122
123
124
125
126
127

  }
  
  integrity_check 2.$tn.4
}


finish_test

Changes to ext/rbu/rbuA.test.

76
77
78
79
80
81
82
83

do_test 2.2 {
  list [catch { rbu close } msg] $msg
} {1 {SQLITE_ERROR - cannot update wal mode database}}


finish_test








<
76
77
78
79
80
81
82


do_test 2.2 {
  list [catch { rbu close } msg] $msg
} {1 {SQLITE_ERROR - cannot update wal mode database}}


finish_test

Changes to ext/rbu/rbuB.test.

55
56
57
58
59
60
61
62
} {1 2 3 4 5 6 7 8 9}

db close
sqlite3_shutdown
test_sqlite3_log 
sqlite3_initialize
finish_test








<
55
56
57
58
59
60
61

} {1 2 3 4 5 6 7 8 9}

db close
sqlite3_shutdown
test_sqlite3_log 
sqlite3_initialize
finish_test

Changes to ext/rbu/rbuC.test.

135
136
137
138
139
140
141
142
  
  integrity_check 3.$tn.4
}



finish_test








<
135
136
137
138
139
140
141

  
  integrity_check 3.$tn.4
}



finish_test

Changes to ext/rbu/rbucollate.test.

56
57
58
59
60
61
62
63
  }
  rbu close
  db eval { SELECT * FROM t1 }
} {a one 1 b two 2 c three 3}

#forcedelete testrbu.db
finish_test








<
56
57
58
59
60
61
62

  }
  rbu close
  db eval { SELECT * FROM t1 }
} {a one 1 b two 2 c three 3}

#forcedelete testrbu.db
finish_test

Changes to ext/rbu/rbucrash.test.

141
142
143
144
145
146
147
148
for {set nPre 0} {$nPre < $rbu_num_steps} {incr nPre} {
  for {set is 1} {$is <= ($rbu_num_steps - $nPre)} {incr is} {
    do_rbu_crash_test 2.pre=$nPre.step=$is $nPre $is
  }
}

finish_test








<
141
142
143
144
145
146
147

for {set nPre 0} {$nPre < $rbu_num_steps} {incr nPre} {
  for {set is 1} {$is <= ($rbu_num_steps - $nPre)} {incr is} {
    do_rbu_crash_test 2.pre=$nPre.step=$is $nPre $is
  }
}

finish_test

Changes to ext/rbu/rbucrash2.test.

99
100
101
102
103
104
105
106
      sqlite3rbu rbu test.db test.db2
    }
    rbu close
  }
}

finish_test








<
99
100
101
102
103
104
105

      sqlite3rbu rbu test.db test.db2
    }
    rbu close
  }
}

finish_test

Changes to ext/rbu/rbudiff.test.

296
297
298
299
300
301
302
303
    db close
    db2 close
  }
}


finish_test








<
296
297
298
299
300
301
302

    db close
    db2 close
  }
}


finish_test

Changes to ext/rbu/rbudor.test.

52
53
54
55
56
57
58
59
} {SQLITE_DONE}

do_execsql_test 1.4 {
  SELECT * FROM t1 
} [list 1 $bigA 2 $bigB]

finish_test








<
52
53
54
55
56
57
58

} {SQLITE_DONE}

do_execsql_test 1.4 {
  SELECT * FROM t1 
} [list 1 $bigA 2 $bigB]

finish_test

Changes to ext/rbu/rbufault.test.

230
231
232
233
234
235
236
237
        }
      }
    }
  }
}

finish_test








<
230
231
232
233
234
235
236

        }
      }
    }
  }
}

finish_test

Changes to ext/rbu/rbufault2.test.

51
52
53
54
55
56
57
58
      {1 {SQLITE_NOMEM - out of memory}} 
}




finish_test








<
51
52
53
54
55
56
57

      {1 {SQLITE_NOMEM - out of memory}} 
}




finish_test

Changes to ext/rbu/rbufault3.test.

91
92
93
94
95
96
97
98
  } -test {
    eval [list faultsim_test_result {0 SQLITE_OK} {*}$::errlist]
  }

}

finish_test








<
91
92
93
94
95
96
97

  } -test {
    eval [list faultsim_test_result {0 SQLITE_OK} {*}$::errlist]
  }

}

finish_test

Changes to ext/rbu/rbufault4.test.

59
60
61
62
63
64
65
66
    if {$rc!="ok"} { error "Got $rc instead of ok!" }
  }
}



finish_test








<
59
60
61
62
63
64
65

    if {$rc!="ok"} { error "Got $rc instead of ok!" }
  }
}



finish_test

Changes to ext/rbu/rbufts.test.

127
128
129
130
131
132
133
134
    INSERT INTO data_ft VALUES('7 8 9', 1, 'x');
  } } msg] $msg]
} {1 {SQLITE_ERROR - SQL logic error]}}



finish_test








<
127
128
129
130
131
132
133

    INSERT INTO data_ft VALUES('7 8 9', 1, 'x');
  } } msg] $msg]
} {1 {SQLITE_ERROR - SQL logic error]}}



finish_test

Changes to ext/rbu/rbumulti.test.

168
169
170
171
172
173
174
175
    sqlite3rbu_destroy_vfs myrbu
  }

}


finish_test








<
168
169
170
171
172
173
174

    sqlite3rbu_destroy_vfs myrbu
  }

}


finish_test

Changes to ext/rbu/rbuprogress.test.

412
413
414
415
416
417
418
419
      do_sp_test 5.$tn.$bReopen.$tn2.1 $bReopen test.db rbu.db $R($tn)
    }
  }
}


finish_test








<
412
413
414
415
416
417
418

      do_sp_test 5.$tn.$bReopen.$tn2.1 $bReopen test.db rbu.db $R($tn)
    }
  }
}


finish_test

Changes to ext/rbu/rburesume.test.

247
248
249
250
251
252
253
254
      PRAGMA integrity_check;
    }
  } {60 ok}
  db2 close
}

finish_test








<
247
248
249
250
251
252
253

      PRAGMA integrity_check;
    }
  } {60 ok}
  db2 close
}

finish_test

Changes to ext/rbu/rbusave.test.

98
99
100
101
102
103
104
105

do_execsql_test 1.5 {
  SELECT * FROM t1;
  SELECT * FROM t2;
} {1 one 1 3 3 3 4 4 4 1 one 1 3 3 3 4 4 4}

finish_test








<
98
99
100
101
102
103
104


do_execsql_test 1.5 {
  SELECT * FROM t1;
  SELECT * FROM t2;
} {1 one 1 3 3 3 4 4 4 1 one 1 3 3 3 4 4 4}

finish_test

Changes to ext/rbu/rbusplit.test.

88
89
90
91
92
93
94
95
    1 1 1 2 2 2 3 3 3 4 4 4
    5 5 5 6 6 6 7 7 7 8 8 8
    9 9 9
  }
}

finish_test








<
88
89
90
91
92
93
94

    1 1 1 2 2 2 3 3 3 4 4 4
    5 5 5 6 6 6 7 7 7 8 8 8
    9 9 9
  }
}

finish_test

Changes to ext/rbu/rbutemplimit.test.

122
123
124
125
126
127
128
129
  setup_databases
  unset -nocomplain ::A
  step_rbu_cachesize test.db test.db2 1000 10 1400000
} {1 SQLITE_FULL}
do_test 1.6.2 { info commands rbu } {}

finish_test








<
122
123
124
125
126
127
128

  setup_databases
  unset -nocomplain ::A
  step_rbu_cachesize test.db test.db2 1000 10 1400000
} {1 SQLITE_FULL}
do_test 1.6.2 { info commands rbu } {}

finish_test

Changes to ext/rbu/rbuvacuum.test.

393
394
395
396
397
398
399
400

  while {[rbu step]=="SQLITE_OK"} {}
  list [catch { rbu close } msg] $msg
} {0 SQLITE_DONE}

catch { db close }
finish_test








<
393
394
395
396
397
398
399


  while {[rbu step]=="SQLITE_OK"} {}
  list [catch { rbu close } msg] $msg
} {0 SQLITE_DONE}

catch { db close }
finish_test

Changes to ext/rbu/rbuvacuum2.test.

228
229
230
231
232
233
234
235
  sqlite3rbu_vacuum rbu test.db test.db2
  while {[rbu step]!="SQLITE_DONE"} { rbu step }
  rbu close
  execsql { PRAGMA integrity_check }
} {ok}

finish_test








<
228
229
230
231
232
233
234

  sqlite3rbu_vacuum rbu test.db test.db2
  while {[rbu step]!="SQLITE_DONE"} { rbu step }
  rbu close
  execsql { PRAGMA integrity_check }
} {ok}

finish_test

Changes to ext/repair/test/checkindex01.test.

343
344
345
346
347
348
349
350
351
}
do_index_check_test 7.3 t7i3 {
  {} 1,1 {} 3,3
}
do_index_check_test 7.4 t7i4 {
  {} 1,1 {} 3,3
}









<
<
343
344
345
346
347
348
349


}
do_index_check_test 7.3 t7i3 {
  {} 1,1 {} 3,3
}
do_index_check_test 7.4 t7i4 {
  {} 1,1 {} 3,3
}


Changes to ext/rtree/geopoly.c.

1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
....
1744
1745
1746
1747
1748
1749
1750

1751
1752
1753
1754
1755
1756
1757
    return SQLITE_INDEX_CONSTRAINT_FUNCTION+1;
  }
  return 0;
}


static sqlite3_module geopolyModule = {
  2,                          /* iVersion */
  geopolyCreate,              /* xCreate - create a table */
  geopolyConnect,             /* xConnect - connect to an existing table */
  geopolyBestIndex,           /* xBestIndex - Determine search strategy */
  rtreeDisconnect,            /* xDisconnect - Disconnect from a table */
  rtreeDestroy,               /* xDestroy - Drop a table */
  rtreeOpen,                  /* xOpen - open a cursor */
  rtreeClose,                 /* xClose - close a cursor */
................................................................................
  rtreeEndTransaction,        /* xCommit - commit transaction */
  rtreeEndTransaction,        /* xRollback - rollback transaction */
  geopolyFindFunction,        /* xFindFunction - function overloading */
  rtreeRename,                /* xRename - rename the table */
  rtreeSavepoint,             /* xSavepoint */
  0,                          /* xRelease */
  0,                          /* xRollbackTo */

};

static int sqlite3_geopoly_init(sqlite3 *db){
  int rc = SQLITE_OK;
  static const struct {
    void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
    signed char nArg;







|







 







>







1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
....
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
    return SQLITE_INDEX_CONSTRAINT_FUNCTION+1;
  }
  return 0;
}


static sqlite3_module geopolyModule = {
  3,                          /* iVersion */
  geopolyCreate,              /* xCreate - create a table */
  geopolyConnect,             /* xConnect - connect to an existing table */
  geopolyBestIndex,           /* xBestIndex - Determine search strategy */
  rtreeDisconnect,            /* xDisconnect - Disconnect from a table */
  rtreeDestroy,               /* xDestroy - Drop a table */
  rtreeOpen,                  /* xOpen - open a cursor */
  rtreeClose,                 /* xClose - close a cursor */
................................................................................
  rtreeEndTransaction,        /* xCommit - commit transaction */
  rtreeEndTransaction,        /* xRollback - rollback transaction */
  geopolyFindFunction,        /* xFindFunction - function overloading */
  rtreeRename,                /* xRename - rename the table */
  rtreeSavepoint,             /* xSavepoint */
  0,                          /* xRelease */
  0,                          /* xRollbackTo */
  rtreeShadowName             /* xShadowName */
};

static int sqlite3_geopoly_init(sqlite3 *db){
  int rc = SQLITE_OK;
  static const struct {
    void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
    signed char nArg;

Changes to ext/rtree/rtree.c.

3322
3323
3324
3325
3326
3327
3328
















3329
3330
3331
3332
3333
3334
3335
3336
3337
....
3346
3347
3348
3349
3350
3351
3352

3353
3354
3355
3356
3357
3358
3359
    }
    sqlite3_free(zSql);
  }

  return rc;
}

















static sqlite3_module rtreeModule = {
  2,                          /* iVersion */
  rtreeCreate,                /* xCreate - create a table */
  rtreeConnect,               /* xConnect - connect to an existing table */
  rtreeBestIndex,             /* xBestIndex - Determine search strategy */
  rtreeDisconnect,            /* xDisconnect - Disconnect from a table */
  rtreeDestroy,               /* xDestroy - Drop a table */
  rtreeOpen,                  /* xOpen - open a cursor */
  rtreeClose,                 /* xClose - close a cursor */
................................................................................
  rtreeEndTransaction,        /* xCommit - commit transaction */
  rtreeEndTransaction,        /* xRollback - rollback transaction */
  0,                          /* xFindFunction - function overloading */
  rtreeRename,                /* xRename - rename the table */
  rtreeSavepoint,             /* xSavepoint */
  0,                          /* xRelease */
  0,                          /* xRollbackTo */

};

static int rtreeSqlInit(
  Rtree *pRtree, 
  sqlite3 *db, 
  const char *zDb, 
  const char *zPrefix, 







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

|







 







>







3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
....
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
    }
    sqlite3_free(zSql);
  }

  return rc;
}


/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.
*/
static int rtreeShadowName(const char *zName){
  static const char *azName[] = {
    "node", "parent", "rowid"
  };
  unsigned int i;
  for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
    if( sqlite3_stricmp(zName, azName[i])==0 ) return 1;
  }
  return 0;
}

static sqlite3_module rtreeModule = {
  3,                          /* iVersion */
  rtreeCreate,                /* xCreate - create a table */
  rtreeConnect,               /* xConnect - connect to an existing table */
  rtreeBestIndex,             /* xBestIndex - Determine search strategy */
  rtreeDisconnect,            /* xDisconnect - Disconnect from a table */
  rtreeDestroy,               /* xDestroy - Drop a table */
  rtreeOpen,                  /* xOpen - open a cursor */
  rtreeClose,                 /* xClose - close a cursor */
................................................................................
  rtreeEndTransaction,        /* xCommit - commit transaction */
  rtreeEndTransaction,        /* xRollback - rollback transaction */
  0,                          /* xFindFunction - function overloading */
  rtreeRename,                /* xRename - rename the table */
  rtreeSavepoint,             /* xSavepoint */
  0,                          /* xRelease */
  0,                          /* xRollbackTo */
  rtreeShadowName             /* xShadowName */
};

static int rtreeSqlInit(
  Rtree *pRtree, 
  sqlite3 *db, 
  const char *zDb, 
  const char *zPrefix, 

Changes to ext/rtree/rtree8.test.

97
98
99
100
101
102
103

104
105
106
107
108
109
110
...
117
118
119
120
121
122
123

124
125
126
127
128
129
130
# The following block of tests - rtree8-2.* - test a couple of database
# corruption cases. In this case things are not corrupted at the b-tree
# level, but the contents of the various tables used internally by an
# r-tree table are inconsistent.
#
populate_t1 50
do_execsql_test rtree8-2.1.1 { SELECT max(nodeno) FROM t1_node } {5}

do_execsql_test rtree8-2.1.2 { DELETE FROM t1_node } {}
for {set i 1} {$i <= 50} {incr i} {
  do_catchsql_test rtree8-2.1.3.$i { 
    SELECT * FROM t1 WHERE id = $i 
  } {1 {database disk image is malformed}}
}
do_catchsql_test rtree8-2.1.4 { 
................................................................................
do_execsql_test rtree8-2.1.6 { 
  DROP TABLE t1;
  CREATE VIRTUAL TABLE t1 USING rtree_i32(id, x1, x2);
} {}


populate_t1 50

do_execsql_test rtree8-2.2.1 {
  DELETE FROM t1_parent
} {}
do_catchsql_test rtree8-2.2.2 {
  DELETE FROM t1 WHERE id=25
} {1 {database disk image is malformed}}
do_execsql_test rtree8-2.2.3 { 







>







 







>







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# The following block of tests - rtree8-2.* - test a couple of database
# corruption cases. In this case things are not corrupted at the b-tree
# level, but the contents of the various tables used internally by an
# r-tree table are inconsistent.
#
populate_t1 50
do_execsql_test rtree8-2.1.1 { SELECT max(nodeno) FROM t1_node } {5}
sqlite3_db_config db DEFENSIVE 0
do_execsql_test rtree8-2.1.2 { DELETE FROM t1_node } {}
for {set i 1} {$i <= 50} {incr i} {
  do_catchsql_test rtree8-2.1.3.$i { 
    SELECT * FROM t1 WHERE id = $i 
  } {1 {database disk image is malformed}}
}
do_catchsql_test rtree8-2.1.4 { 
................................................................................
do_execsql_test rtree8-2.1.6 { 
  DROP TABLE t1;
  CREATE VIRTUAL TABLE t1 USING rtree_i32(id, x1, x2);
} {}


populate_t1 50
sqlite3_db_config db DEFENSIVE 0
do_execsql_test rtree8-2.2.1 {
  DELETE FROM t1_parent
} {}
do_catchsql_test rtree8-2.2.2 {
  DELETE FROM t1 WHERE id=25
} {1 {database disk image is malformed}}
do_execsql_test rtree8-2.2.3 { 

Changes to ext/rtree/rtreeA.test.

32
33
34
35
36
37
38

39
40
41
42
43
44
45
...
242
243
244
245
246
247
248

249
250
251
252
253
254
255
256
257
258
259
260
261
  execsql BEGIN
  for {set i 0} {$i < 500} {incr i} {
    set x2 [expr $i+5]
    set y2 [expr $i+5]
    execsql { INSERT INTO t1 VALUES($i, $i, $x2, $i, $y2) }
  }
  execsql COMMIT

}

proc truncate_node {nodeno nTrunc} {
  set blob [db one {SELECT data FROM t1_node WHERE nodeno=$nodeno}]
  if {$nTrunc<0} {set nTrunc "end-$nTrunc"}
  set blob [string range $blob 0 $nTrunc]
  db eval { UPDATE t1_node SET data = $blob WHERE nodeno=$nodeno }
................................................................................

#-------------------------------------------------------------------------
# Truncated blobs in the _node table.
#
create_t1
populate_t1
sqlite3 db test.db

do_execsql_test rtreeA-7.100 { 
  UPDATE t1_node SET data=x'' WHERE rowid=1;
} {}
do_catchsql_test rtreeA-7.110 {
  SELECT * FROM t1 WHERE x1>0 AND x1<100 AND x2>0 AND x2<100;
} {1 {undersize RTree blobs in "t1_node"}}
do_test rtreeA-7.120 {
  sqlite3_extended_errcode db
} {SQLITE_CORRUPT_VTAB}


finish_test








>







 







>












<
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

  execsql BEGIN
  for {set i 0} {$i < 500} {incr i} {
    set x2 [expr $i+5]
    set y2 [expr $i+5]
    execsql { INSERT INTO t1 VALUES($i, $i, $x2, $i, $y2) }
  }
  execsql COMMIT
  sqlite3_db_config db DEFENSIVE 0
}

proc truncate_node {nodeno nTrunc} {
  set blob [db one {SELECT data FROM t1_node WHERE nodeno=$nodeno}]
  if {$nTrunc<0} {set nTrunc "end-$nTrunc"}
  set blob [string range $blob 0 $nTrunc]
  db eval { UPDATE t1_node SET data = $blob WHERE nodeno=$nodeno }
................................................................................

#-------------------------------------------------------------------------
# Truncated blobs in the _node table.
#
create_t1
populate_t1
sqlite3 db test.db
sqlite3_db_config db DEFENSIVE 0
do_execsql_test rtreeA-7.100 { 
  UPDATE t1_node SET data=x'' WHERE rowid=1;
} {}
do_catchsql_test rtreeA-7.110 {
  SELECT * FROM t1 WHERE x1>0 AND x1<100 AND x2>0 AND x2<100;
} {1 {undersize RTree blobs in "t1_node"}}
do_test rtreeA-7.120 {
  sqlite3_extended_errcode db
} {SQLITE_CORRUPT_VTAB}


finish_test

Changes to ext/rtree/rtreecheck.test.

57
58
59
60
61
62
63

64
65
66
67
68
69
70
...
108
109
110
111
112
113
114

115
116
117
118
119
120
121
...
136
137
138
139
140
141
142

143
144
145
146
147
148
149
...
151
152
153
154
155
156
157
158
    CREATE VIRTUAL TABLE r1 USING $module (id, x1, x2, y1, y2);
    INSERT INTO r1 VALUES(1,  5, 5, 5, 5);  --  3
    INSERT INTO r1 VALUES(2,  6, 6, 6, 6);  --  9
    INSERT INTO r1 VALUES(3,  7, 7, 7, 7);  -- 15
    INSERT INTO r1 VALUES(4,  8, 8, 8, 8);  -- 21
    INSERT INTO r1 VALUES(5,  9, 9, 9, 9);  -- 27
  "

}

setup_simple_db
do_execsql_test 2.1 { 
  SELECT rtreecheck('r1') 
} {ok}

................................................................................

do_execsql_test 3.1 { 
  CREATE VIRTUAL TABLE r2 USING rtree_i32(id, x1, x2);
  INSERT INTO r2 VALUES(2, -1*(1<<31), -1*(1<<31)+5);
  SELECT rtreecheck('r2') 
} {ok}


do_execsql_test 3.2 {
  BEGIN;
    UPDATE r2_node SET data = X'123456';
    SELECT rtreecheck('r2')!="ok";
} {1}

do_execsql_test 3.3 {
................................................................................
do_execsql_test 5.0 {
  CREATE VIRTUAL TABLE r3 USING rtree_i32(id, x1, x2, y1, y2);
  WITH x(i) AS (
    SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<1000
  )
  INSERT INTO r3 SELECT i, i, i, i, i FROM x;
}

do_execsql_test 5.1 {
  BEGIN;
    UPDATE r3_node SET data = set_int32(data, 3, 5000);
    UPDATE r3_node SET data = set_int32(data, 4, 5000);
    SELECT rtreecheck('r3')=='ok'
} 0
do_execsql_test 5.2 {
................................................................................
  BEGIN;
    UPDATE r3_node SET data = set_int32(data, 3, 0);
    UPDATE r3_node SET data = set_int32(data, 4, 0);
    SELECT rtreecheck('r3')=='ok'
} 0

finish_test








>







 







>







 







>







 







<
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
...
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
...
154
155
156
157
158
159
160

    CREATE VIRTUAL TABLE r1 USING $module (id, x1, x2, y1, y2);
    INSERT INTO r1 VALUES(1,  5, 5, 5, 5);  --  3
    INSERT INTO r1 VALUES(2,  6, 6, 6, 6);  --  9
    INSERT INTO r1 VALUES(3,  7, 7, 7, 7);  -- 15
    INSERT INTO r1 VALUES(4,  8, 8, 8, 8);  -- 21
    INSERT INTO r1 VALUES(5,  9, 9, 9, 9);  -- 27
  "
  sqlite3_db_config db DEFENSIVE 0
}

setup_simple_db
do_execsql_test 2.1 { 
  SELECT rtreecheck('r1') 
} {ok}

................................................................................

do_execsql_test 3.1 { 
  CREATE VIRTUAL TABLE r2 USING rtree_i32(id, x1, x2);
  INSERT INTO r2 VALUES(2, -1*(1<<31), -1*(1<<31)+5);
  SELECT rtreecheck('r2') 
} {ok}

sqlite3_db_config db DEFENSIVE 0
do_execsql_test 3.2 {
  BEGIN;
    UPDATE r2_node SET data = X'123456';
    SELECT rtreecheck('r2')!="ok";
} {1}

do_execsql_test 3.3 {
................................................................................
do_execsql_test 5.0 {
  CREATE VIRTUAL TABLE r3 USING rtree_i32(id, x1, x2, y1, y2);
  WITH x(i) AS (
    SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<1000
  )
  INSERT INTO r3 SELECT i, i, i, i, i FROM x;
}
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 5.1 {
  BEGIN;
    UPDATE r3_node SET data = set_int32(data, 3, 5000);
    UPDATE r3_node SET data = set_int32(data, 4, 5000);
    SELECT rtreecheck('r3')=='ok'
} 0
do_execsql_test 5.2 {
................................................................................
  BEGIN;
    UPDATE r3_node SET data = set_int32(data, 3, 0);
    UPDATE r3_node SET data = set_int32(data, 4, 0);
    SELECT rtreecheck('r3')=='ok'
} 0

finish_test

Added ext/session/changesetfuzz.c.

















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
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
557
558
559
560
561
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
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
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
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
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
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
/*
** 2018-11-01
**
** 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.
**
*************************************************************************
** This file contains code to implement the "changesetfuzz" command 
** line utility for fuzzing changeset blobs without corrupting them.
*/


/************************************************************************
** USAGE:
**
** This program may be invoked in two ways:
**
**   changesetfuzz INPUT
**   changesetfuzz INPUT SEED N
**
** Argument INPUT must be the name of a file containing a binary changeset.
** In the first form above, this program outputs a human-readable version
** of the same changeset. This is chiefly for debugging.
**
** As well as changesets, this program can also dump and fuzz patchsets.
** The term "changeset" is used for both patchsets and changesets from this
** point on.
**
** In the second form, arguments SEED and N must both be integers. In this
** case, this program writes N binary changesets to disk. Each output
** changeset is a slightly modified - "fuzzed" - version of the input. 
** The output changesets are written to files name "INPUT-$n", where $n is 
** an integer between 0 and N-1, inclusive. Output changesets are always
** well-formed. Parameter SEED is used to seed the PRNG - any two 
** invocations of this program with the same SEED and input changeset create
** the same N output changesets.
**
** The ways in which an input changeset may be fuzzed are as follows:
**
**   1. Any two values within the changeset may be exchanged.
**
**   2. Any TEXT, BLOB, INTEGER or REAL value within the changeset 
**      may have a single bit of its content flipped.
**
**   3. Any value within a changeset may be replaced by a pseudo-randomly
**      generated value.
**
** The above operations never set a PRIMARY KEY column to NULL. Nor do they
** set any value to "undefined", or replace any "undefined" value with
** another. Any such operation risks producing a changeset that is not 
** well-formed.
**
**   4. A single change may be duplicated.
**
**   5. A single change may be removed, so long as this does not mean that
**      there are zero changes following a table-header within the changeset.
**
**   6. A single change may have its type (INSERT, DELETE, UPDATE) changed.
**      If an INSERT is changed to a DELETE (or vice versa), the type is
**      simply changed - no other modifications are required. If an INSERT
**      or DELETE is changed to an UPDATE, then the single record is duplicated
**      (as both the old.* and new.* records of the new UPDATE change). If an
**      UPDATE is changed to a DELETE or INSERT, the new.* record is discarded
**      and any "undefined" fields replaced with pseudo-randomly generated
**      values.
**
**   7. An UPDATE change that modifies N table columns may be modified so
**      that it updates N-1 columns, so long as (N>1).
**
**   8. The "indirect" flag may be toggled for any change.
**
** Entire group of changes may also be operated on:
**
**   9. Duplicate an existing group.
**
**  10. Remove an existing group.
**
**  11. The positions of two groups may be exchanged.
**
** There are also schema changes:
**
**  12. A non-PK column may be added to a table. In this case a NULL 
**      value is appended to all records.
**
**  13. A PK column may be added to a table. In this case a non-NULL 
**      value is appended to all INSERT, DELETE and UPDATE old.* records.
**      An "undefined" is appended to new.* UPDATE records.
**
**  14. A column may be removed from a table, provided that it is not the
**      only PRIMARY KEY column in the table. In this case the corresponding
**      field is removed from all records. In cases where this leaves an UPDATE
**      with no non-PK, non-undefined fields, the entire change is removed.
*/

#include "sqlite3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>

#define FUZZ_VALUE_SUB       1    /* Replace one value with a copy of another */
#define FUZZ_VALUE_MOD       2    /* Modify content by 1 bit */
#define FUZZ_VALUE_RND       3    /* Replace with pseudo-random value */

#define FUZZ_CHANGE_DUP      4    /* Duplicate an existing change */
#define FUZZ_CHANGE_DEL      5    /* Completely remove one change */
#define FUZZ_CHANGE_TYPE     6    /* Change the type of one change */
#define FUZZ_CHANGE_FIELD    7    /* Change an UPDATE to modify fewer columns */
#define FUZZ_CHANGE_INDIRECT 8    /* Toggle the "indirect" flag of a change */

#define FUZZ_GROUP_DUP       9    /* Duplicate a change group */
#define FUZZ_GROUP_DEL      10    /* Delete an entire change group */
#define FUZZ_GROUP_SWAP     11    /* Exchange the position of two groups */

#define FUZZ_COLUMN_ADD     12     /* Add column to table definition */
#define FUZZ_COLUMN_ADDPK   13     /* Add PK column to table definition */
#define FUZZ_COLUMN_DEL     14     /* Remove column from table definition */



typedef unsigned char u8;
typedef sqlite3_uint64 u64;
typedef sqlite3_int64 i64;
typedef unsigned int u32;

/*
** Show a usage message on stderr then quit.
*/
static void usage(const char *argv0){
  fprintf(stderr, "Usage: %s FILENAME ?SEED N?\n", argv0);
  exit(1);
}

/*
** Read the content of a disk file into an in-memory buffer
*/
static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){
  FILE *f;
  int sz;
  void *pBuf;
  f = fopen(zFilename, "rb");
  if( f==0 ){
    fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename);
    exit(1);
  }
  fseek(f, 0, SEEK_END);
  sz = (int)ftell(f);
  rewind(f);
  pBuf = sqlite3_malloc( sz ? sz : 1 );
  if( pBuf==0 ){
    fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n",
            sz, zFilename);
    exit(1);
  }
  if( sz>0 ){
    if( fread(pBuf, sz, 1, f)!=1 ){
      fprintf(stderr, "cannot read all %d bytes of \"%s\"\n", sz, zFilename);
      exit(1);
    }
    fclose(f);
  }
  *pSz = sz;
  *ppBuf = pBuf;
}

/* 
** Write the contents of buffer pBuf, size nBuf bytes, into file zFilename
** on disk. zFilename, if it already exists, is clobbered.
*/
static void fuzzWriteFile(const char *zFilename, void *pBuf, int nBuf){
  FILE *f;
  f = fopen(zFilename, "wb");
  if( f==0 ){
    fprintf(stderr, "cannot open \"%s\" for writing\n", zFilename);
    exit(1);
  }
  if( fwrite(pBuf, nBuf, 1, f)!=1 ){
    fprintf(stderr, "cannot write to \"%s\"\n", zFilename);
    exit(1);
  }
  fclose(f);
}

static int fuzzCorrupt(){
  return SQLITE_CORRUPT;
}

/*************************************************************************
** The following block is a copy of the implementation of SQLite function
** sqlite3_randomness. This version has two important differences:
**
**   1. It always uses the same seed. So the sequence of random data output
**      is the same for every run of the program.
**
**   2. It is not threadsafe.
*/
static struct sqlite3PrngType {
  unsigned char i, j;             /* State variables */
  unsigned char s[256];           /* State variables */
} sqlite3Prng = {
    0xAF, 0x28,
  {
    0x71, 0xF5, 0xB4, 0x6E, 0x80, 0xAB, 0x1D, 0xB8, 
    0xFB, 0xB7, 0x49, 0xBF, 0xFF, 0x72, 0x2D, 0x14, 
    0x79, 0x09, 0xE3, 0x78, 0x76, 0xB0, 0x2C, 0x0A, 
    0x8E, 0x23, 0xEE, 0xDF, 0xE0, 0x9A, 0x2F, 0x67, 
    0xE1, 0xBE, 0x0E, 0xA7, 0x08, 0x97, 0xEB, 0x77, 
    0x78, 0xBA, 0x9D, 0xCA, 0x49, 0x4C, 0x60, 0x9A, 
    0xF6, 0xBD, 0xDA, 0x7F, 0xBC, 0x48, 0x58, 0x52, 
    0xE5, 0xCD, 0x83, 0x72, 0x23, 0x52, 0xFF, 0x6D, 
    0xEF, 0x0F, 0x82, 0x29, 0xA0, 0x83, 0x3F, 0x7D, 
    0xA4, 0x88, 0x31, 0xE7, 0x88, 0x92, 0x3B, 0x9B, 
    0x3B, 0x2C, 0xC2, 0x4C, 0x71, 0xA2, 0xB0, 0xEA, 
    0x36, 0xD0, 0x00, 0xF1, 0xD3, 0x39, 0x17, 0x5D, 
    0x2A, 0x7A, 0xE4, 0xAD, 0xE1, 0x64, 0xCE, 0x0F, 
    0x9C, 0xD9, 0xF5, 0xED, 0xB0, 0x22, 0x5E, 0x62, 
    0x97, 0x02, 0xA3, 0x8C, 0x67, 0x80, 0xFC, 0x88, 
    0x14, 0x0B, 0x15, 0x10, 0x0F, 0xC7, 0x40, 0xD4, 
    0xF1, 0xF9, 0x0E, 0x1A, 0xCE, 0xB9, 0x1E, 0xA1, 
    0x72, 0x8E, 0xD7, 0x78, 0x39, 0xCD, 0xF4, 0x5D, 
    0x2A, 0x59, 0x26, 0x34, 0xF2, 0x73, 0x0B, 0xA0, 
    0x02, 0x51, 0x2C, 0x03, 0xA3, 0xA7, 0x43, 0x13, 
    0xE8, 0x98, 0x2B, 0xD2, 0x53, 0xF8, 0xEE, 0x91, 
    0x7D, 0xE7, 0xE3, 0xDA, 0xD5, 0xBB, 0xC0, 0x92, 
    0x9D, 0x98, 0x01, 0x2C, 0xF9, 0xB9, 0xA0, 0xEB, 
    0xCF, 0x32, 0xFA, 0x01, 0x49, 0xA5, 0x1D, 0x9A, 
    0x76, 0x86, 0x3F, 0x40, 0xD4, 0x89, 0x8F, 0x9C, 
    0xE2, 0xE3, 0x11, 0x31, 0x37, 0xB2, 0x49, 0x28, 
    0x35, 0xC0, 0x99, 0xB6, 0xD0, 0xBC, 0x66, 0x35, 
    0xF7, 0x83, 0x5B, 0xD7, 0x37, 0x1A, 0x2B, 0x18, 
    0xA6, 0xFF, 0x8D, 0x7C, 0x81, 0xA8, 0xFC, 0x9E, 
    0xC4, 0xEC, 0x80, 0xD0, 0x98, 0xA7, 0x76, 0xCC, 
    0x9C, 0x2F, 0x7B, 0xFF, 0x8E, 0x0E, 0xBB, 0x90, 
    0xAE, 0x13, 0x06, 0xF5, 0x1C, 0x4E, 0x52, 0xF7
  }
};

/* 
** Generate and return single random byte 
*/
static unsigned char fuzzRandomByte(void){
  unsigned char t;
  sqlite3Prng.i++;
  t = sqlite3Prng.s[sqlite3Prng.i];
  sqlite3Prng.j += t;
  sqlite3Prng.s[sqlite3Prng.i] = sqlite3Prng.s[sqlite3Prng.j];
  sqlite3Prng.s[sqlite3Prng.j] = t;
  t += sqlite3Prng.s[sqlite3Prng.i];
  return sqlite3Prng.s[t];
}

/*
** Return N random bytes.
*/
static void fuzzRandomBlob(int nBuf, unsigned char *zBuf){
  int i;
  for(i=0; i<nBuf; i++){
    zBuf[i] = fuzzRandomByte();
  }
}

/*
** Return a random integer between 0 and nRange (not inclusive).
*/
static unsigned int fuzzRandomInt(unsigned int nRange){
  unsigned int ret;
  assert( nRange>0 );
  fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
  return (ret % nRange);
}

static u64 fuzzRandomU64(){
  u64 ret;
  fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
  return ret;
}

static void fuzzRandomSeed(unsigned int iSeed){
  int i;
  for(i=0; i<256; i+=4){
    sqlite3Prng.s[i] ^= ((iSeed >> 24) & 0xFF);
    sqlite3Prng.s[i+1] ^= ((iSeed >> 16) & 0xFF);
    sqlite3Prng.s[i+2] ^= ((iSeed >>  8) & 0xFF);
    sqlite3Prng.s[i+3] ^= ((iSeed >>  0) & 0xFF);
  }
}
/*
** End of code for generating pseudo-random values.
*************************************************************************/

typedef struct FuzzChangeset FuzzChangeset;
typedef struct FuzzChangesetGroup FuzzChangesetGroup;
typedef struct FuzzChange FuzzChange;

/* 
** Object containing partially parsed changeset.
*/
struct FuzzChangeset {
  int bPatchset;                  /* True for a patchset */
  FuzzChangesetGroup **apGroup;   /* Array of groups in changeset */
  int nGroup;                     /* Number of items in list pGroup */
  u8 **apVal;                     /* Array of all values in changeset */
  int nVal;                       /* Number of used slots in apVal[] */
  int nChange;                    /* Number of changes in changeset */
  int nUpdate;                    /* Number of UPDATE changes in changeset */
};

/* 
** There is one object of this type for each change-group (table header)
** in the input changeset.
*/
struct FuzzChangesetGroup {
  const char *zTab;               /* Name of table */
  int nCol;                       /* Number of columns in table */
  u8 *aPK;                        /* PK array for this table */
  u8 *aChange;                    /* Buffer containing array of changes */
  int szChange;                   /* Size of buffer aChange[] in bytes */
  int nChange;                    /* Number of changes in buffer aChange[] */
};

/*
** Description of a fuzz change to be applied to a changeset.
*/
struct FuzzChange {
  int eType;                      /* One of the FUZZ_* constants above */
  int iChange;                    /* Change or UPDATE to modify */
  int iGroup;                     /* Group to modify */
  int iDelete;                    /* Field to remove (FUZZ_COLUMN_DEL) */
  u8 *pSub1;                      /* Replace this value with pSub2 */
  u8 *pSub2;                      /* And this one with pSub1 */
  u8 aSub[128];                   /* Buffer for substitute value */
  int iCurrent;                   /* Current change number */
};

/*
** Allocate and return nByte bytes of zeroed memory.
*/
static void *fuzzMalloc(int nByte){
  void *pRet = sqlite3_malloc(nByte);
  if( pRet ){
    memset(pRet, 0, nByte);
  }
  return pRet;
}

/*
** Free the buffer indicated by the first argument. This function is used
** to free buffers allocated by fuzzMalloc().
*/
static void fuzzFree(void *p){
  sqlite3_free(p);
}

/*
** Argument p points to a buffer containing an SQLite varint that, assuming the
** input is not corrupt, may be between 0 and 0x7FFFFFFF, inclusive. Before
** returning, this function sets (*pnVal) to the value of that varint, and
** returns the number of bytes of space that it takes up.
*/
static int fuzzGetVarint(u8 *p, int *pnVal){
  int i;
  sqlite3_uint64 nVal = 0;
  for(i=0; i<9; i++){
    nVal = (nVal<<7) + (p[i] & 0x7F);
    if( (p[i] & 0x80)==0 ){
      i++;
      break;
    }
  }
  *pnVal = (int)nVal;
  return i;
}

/*
** Write value nVal into the buffer indicated by argument p as an SQLite
** varint. nVal is guaranteed to be between 0 and (2^21-1), inclusive.
** Return the number of bytes written to buffer p.
*/
static int fuzzPutVarint(u8 *p, int nVal){
  assert( nVal>0 && nVal<2097152 );
  if( nVal<128 ){
    p[0] = nVal;
    return 1;
  }
  if( nVal<16384 ){
    p[0] = ((nVal >> 7) & 0x7F) | 0x80;
    p[1] = (nVal & 0x7F);
    return 2;
  }

  p[0] = ((nVal >> 14) & 0x7F) | 0x80;
  p[1] = ((nVal >> 7) & 0x7F) | 0x80;
  p[2] = (nVal & 0x7F);
  return 3;
}

/*
** Read a 64-bit big-endian integer value from buffer aRec[]. Return
** the value read.
*/
static i64 fuzzGetI64(u8 *aRec){
  return (i64)(
      (((u64)aRec[0]) << 56)
    + (((u64)aRec[1]) << 48)
    + (((u64)aRec[2]) << 40)
    + (((u64)aRec[3]) << 32)
    + (((u64)aRec[4]) << 24)
    + (((u64)aRec[5]) << 16)
    + (((u64)aRec[6]) <<  8)
    + (((u64)aRec[7]) <<  0)
  );
}

/*
** Write value iVal to buffer aRec[] as an unsigned 64-bit big-endian integer.
*/
static void fuzzPutU64(u8 *aRec, u64 iVal){
  aRec[0] = (iVal>>56) & 0xFF;
  aRec[1] = (iVal>>48) & 0xFF;
  aRec[2] = (iVal>>40) & 0xFF;
  aRec[3] = (iVal>>32) & 0xFF;
  aRec[4] = (iVal>>24) & 0xFF;
  aRec[5] = (iVal>>16) & 0xFF;
  aRec[6] = (iVal>> 8) & 0xFF;
  aRec[7] = (iVal)     & 0xFF;
}

/*
** Parse a single table-header from the input. Allocate a new change-group
** object with the results. Return SQLITE_OK if successful, or an error code
** otherwise.
*/
static int fuzzParseHeader(
  FuzzChangeset *pParse,          /* Changeset parse object */
  u8 **ppHdr,                     /* IN/OUT: Iterator */
  u8 *pEnd,                       /* 1 byte past EOF */
  FuzzChangesetGroup **ppGrp      /* OUT: New change-group object */
){
  int rc = SQLITE_OK;
  FuzzChangesetGroup *pGrp;
  u8 cHdr = (pParse->bPatchset ? 'P' : 'T');

  assert( pEnd>(*ppHdr) );
  pGrp = (FuzzChangesetGroup*)fuzzMalloc(sizeof(FuzzChangesetGroup));
  if( !pGrp ){
    rc = SQLITE_NOMEM;
  }else{
    u8 *p = *ppHdr;
    if( p[0]!=cHdr ){
      rc = fuzzCorrupt();
    }else{
      p++;
      p += fuzzGetVarint(p, &pGrp->nCol);
      pGrp->aPK = p;
      p += pGrp->nCol;
      pGrp->zTab = (const char*)p;
      p = &p[strlen(p)+1];

      if( p>=pEnd ){
        rc = fuzzCorrupt();
      }
    }
    *ppHdr = p;
  }

  if( rc!=SQLITE_OK ){
    fuzzFree(pGrp);
    pGrp = 0;
  }

  *ppGrp = pGrp;
  return rc;
}

/*
** Argument p points to a buffer containing a single changeset-record value. 
** This function attempts to determine the size of the value in bytes. If
** successful, it sets (*pSz) to the size and returns SQLITE_OK. Or, if the
** buffer does not contain a valid value, SQLITE_CORRUPT is returned and
** the final value of (*pSz) is undefined.
*/
static int fuzzChangeSize(u8 *p, int *pSz){
  u8 eType = p[0];
  switch( eType ){
    case 0x00:                    /* undefined */
    case 0x05:                    /* null */
      *pSz = 1;
      break;

    case 0x01:                    /* integer */
    case 0x02:                    /* real */
      *pSz = 9;
      break;

    case 0x03:                    /* text */
    case 0x04: {                  /* blob */
      int nTxt;
      int sz;
      sz = fuzzGetVarint(&p[1], &nTxt);
      *pSz = 1 + sz + nTxt;
      break;
    }

    default:
      return fuzzCorrupt();
  }
  return SQLITE_OK;
}

/*
** When this function is called, (*ppRec) points to the start of a 
** record in a changeset being parsed. This function adds entries
** to the pParse->apVal[] array for all values and advances (*ppRec) 
** to one byte past the end of the record. Argument pEnd points to
** one byte past the end of the input changeset.
**
** Argument bPkOnly is true if the record being parsed is part of
** a DELETE record in a patchset. In this case, all non-primary-key
** fields have been omitted from the record.
**
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
*/
static int fuzzParseRecord(
  u8 **ppRec,                     /* IN/OUT: Iterator */
  u8 *pEnd,                       /* One byte after end of input data */
  FuzzChangeset *pParse,          /* Changeset parse context */
  int bPkOnly                     /* True if non-PK fields omitted */
){
  int rc = SQLITE_OK;
  FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
  int i;
  u8 *p = *ppRec;

  for(i=0; rc==SQLITE_OK && i<pGrp->nCol; i++){
    if( bPkOnly==0 || pGrp->aPK[i] ){
      int sz;
      if( p>=pEnd ) break;
      if( (pParse->nVal & (pParse->nVal-1))==0 ){
        int nNew = pParse->nVal ? pParse->nVal*2 : 4;
        u8 **apNew = (u8**)sqlite3_realloc(pParse->apVal, nNew*sizeof(u8*));
        if( apNew==0 ) return SQLITE_NOMEM;
        pParse->apVal = apNew;
      }
      pParse->apVal[pParse->nVal++] = p;
      rc = fuzzChangeSize(p, &sz);
      p += sz;
    }
  }

  if( rc==SQLITE_OK && i<pGrp->nCol ){
    rc = fuzzCorrupt();
  }

  *ppRec = p;
  return rc;
}

/*
** Parse the array of changes starting at (*ppData) and add entries for
** all values to the pParse->apVal[] array. Argument pEnd points to one byte
** past the end of the input changeset. If successful, set (*ppData) to point
** to one byte past the end of the change array and return SQLITE_OK.
** Otherwise, return an SQLite error code. The final value of (*ppData) is
** undefined in this case.
*/
static int fuzzParseChanges(u8 **ppData, u8 *pEnd, FuzzChangeset *pParse){
  u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
  FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
  int rc = SQLITE_OK;
  u8 *p = *ppData;

  pGrp->aChange = p;
  while( rc==SQLITE_OK && p<pEnd && p[0]!=cHdr ){
    u8 eOp = p[0];
    u8 bIndirect = p[1];

    p += 2;
    if( eOp==SQLITE_UPDATE ){
      pParse->nUpdate++;
      if( pParse->bPatchset==0 ){
        rc = fuzzParseRecord(&p, pEnd, pParse, 0);
      }
    }else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_DELETE ){
      rc = fuzzCorrupt();
    }
    if( rc==SQLITE_OK ){
      int bPkOnly = (eOp==SQLITE_DELETE && pParse->bPatchset);
      rc = fuzzParseRecord(&p, pEnd, pParse, bPkOnly);
    }
    pGrp->nChange++;
    pParse->nChange++;
  }
  pGrp->szChange = p - pGrp->aChange;

  *ppData = p;
  return rc;
}

/*
** Parse the changeset stored in buffer pChangeset (nChangeset bytes in
** size). If successful, write the results into (*pParse) and return
** SQLITE_OK. Or, if an error occurs, return an SQLite error code. The
** final state of (*pParse) is undefined in this case.
*/
static int fuzzParseChangeset(
  u8 *pChangeset,                 /* Buffer containing changeset */
  int nChangeset,                 /* Size of buffer in bytes */
  FuzzChangeset *pParse           /* OUT: Results of parse */
){
  u8 *pEnd = &pChangeset[nChangeset];
  u8 *p = pChangeset;
  int rc = SQLITE_OK;

  memset(pParse, 0, sizeof(FuzzChangeset));
  if( nChangeset>0 ){
    pParse->bPatchset = (pChangeset[0]=='P');
  }

  while( rc==SQLITE_OK && p<pEnd ){
    FuzzChangesetGroup *pGrp = 0;

    /* Read a table-header from the changeset */
    rc = fuzzParseHeader(pParse, &p, pEnd, &pGrp);
    assert( (rc==SQLITE_OK)==(pGrp!=0) );

    /* If the table-header was successfully parsed, add the new change-group
    ** to the array and parse the associated changes. */
    if( rc==SQLITE_OK ){
      FuzzChangesetGroup **apNew = (FuzzChangesetGroup**)sqlite3_realloc(
          pParse->apGroup, sizeof(FuzzChangesetGroup*)*(pParse->nGroup+1)
      );
      if( apNew==0 ){
        rc = SQLITE_NOMEM;
      }else{
        apNew[pParse->nGroup] = pGrp;
        pParse->apGroup = apNew;
        pParse->nGroup++;
      }
      rc = fuzzParseChanges(&p, pEnd, pParse);
    }
  }

  return rc;
}

/*
** When this function is called, (*ppRec) points to the first byte of
** a record that is part of change-group pGrp. This function attempts
** to output a human-readable version of the record to stdout and advance
** (*ppRec) to point to the first byte past the end of the record before
** returning. If successful, SQLITE_OK is returned. Otherwise, an SQLite
** error code.
**
** If parameter bPkOnly is non-zero, then all non-primary-key fields have
** been omitted from the record. This occurs for records that are part
** of DELETE changes in patchsets.
*/
static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec, int bPKOnly){
  int rc = SQLITE_OK;
  u8 *p = *ppRec;
  int i;
  const char *zPre = " (";

  for(i=0; i<pGrp->nCol; i++){
    if( bPKOnly==0 || pGrp->aPK[i] ){
      u8 eType = p++[0];
      switch( eType ){
        case 0x00:                    /* undefined */
          printf("%sn/a", zPre);
          break;

        case 0x01: {                  /* integer */
          sqlite3_int64 iVal = 0;
          iVal = fuzzGetI64(p);
          printf("%s%lld", zPre, iVal);
          p += 8;
          break;
        }

        case 0x02: {                  /* real */
          sqlite3_int64 iVal = 0;
          double fVal = 0.0;
          iVal = fuzzGetI64(p);
          memcpy(&fVal, &iVal, 8);
          printf("%s%f", zPre, fVal);
          p += 8;
          break;
        }

        case 0x03:                    /* text */
        case 0x04: {                  /* blob */
          int nTxt;
          int sz;
          int i;
          p += fuzzGetVarint(p, &nTxt);
          printf("%s%s", zPre, eType==0x03 ? "'" : "X'");
          for(i=0; i<nTxt; i++){
            if( eType==0x03 ){
              printf("%c", p[i]);
            }else{
              char aHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
                               '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
              };
              printf("%c", aHex[ p[i]>>4 ]);
              printf("%c", aHex[ p[i] & 0x0F ]);
            }
          }
          printf("'");
          p += nTxt;
          break;
        }

        case 0x05:                    /* null */
          printf("%sNULL", zPre);
          break;
      }
      zPre = ", ";
    }
  }
  printf(")");

  *ppRec = p;
  return rc;
}

/*
** Print a human-readable version of the table-header and all changes in the
** change-group passed as the second argument.
*/
static void fuzzPrintGroup(FuzzChangeset *pParse, FuzzChangesetGroup *pGrp){
  int i;
  u8 *p;

  /* The table header */
  printf("TABLE:  %s nCol=%d aPK=", pGrp->zTab, pGrp->nCol);
  for(i=0; i<pGrp->nCol; i++){
    printf("%d", (int)pGrp->aPK[i]);
  }
  printf("\n");

  /* The array of changes */
  p = pGrp->aChange;
  for(i=0; i<pGrp->nChange; i++){
    u8 eType = p[0];
    u8 bIndirect = p[1];
    printf("%s (ind=%d):",
        (eType==SQLITE_INSERT) ? "INSERT" :
        (eType==SQLITE_DELETE ? "DELETE" : "UPDATE"),
        bIndirect
    );
    p += 2;

    if( pParse->bPatchset==0 && eType==SQLITE_UPDATE ){
      fuzzPrintRecord(pGrp, &p, 0);
    }
    fuzzPrintRecord(pGrp, &p, eType==SQLITE_DELETE && pParse->bPatchset);
    printf("\n");
  }
}

/*
** Initialize the object passed as the second parameter with details
** of the change that will be attempted (type of change, to which part of the
** changeset it applies etc.). If successful, return SQLITE_OK. Or, if an
** error occurs, return an SQLite error code. 
**
** If a negative value is returned, then the selected change would have
** produced a non-well-formed changeset. In this case the caller should
** call this function again.
*/
static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
  int iSub;

  memset(pChange, 0, sizeof(FuzzChange));
  pChange->eType = fuzzRandomInt(FUZZ_COLUMN_DEL) + 1;

  assert( pChange->eType==FUZZ_VALUE_SUB
       || pChange->eType==FUZZ_VALUE_MOD
       || pChange->eType==FUZZ_VALUE_RND
       || pChange->eType==FUZZ_CHANGE_DUP
       || pChange->eType==FUZZ_CHANGE_DEL
       || pChange->eType==FUZZ_CHANGE_TYPE
       || pChange->eType==FUZZ_CHANGE_FIELD
       || pChange->eType==FUZZ_CHANGE_INDIRECT
       || pChange->eType==FUZZ_GROUP_DUP
       || pChange->eType==FUZZ_GROUP_DEL
       || pChange->eType==FUZZ_GROUP_SWAP
       || pChange->eType==FUZZ_COLUMN_ADD
       || pChange->eType==FUZZ_COLUMN_ADDPK
       || pChange->eType==FUZZ_COLUMN_DEL
  );

  pChange->iGroup = fuzzRandomInt(pParse->nGroup);
  pChange->iChange = fuzzRandomInt(pParse->nChange);
  if( pChange->eType==FUZZ_CHANGE_FIELD ){
    if( pParse->nUpdate==0 ) return -1;
    pChange->iChange = fuzzRandomInt(pParse->nUpdate);
  }

  pChange->iDelete = -1;
  if( pChange->eType==FUZZ_COLUMN_DEL ){
    FuzzChangesetGroup *pGrp = pParse->apGroup[pChange->iGroup];
    int i;
    pChange->iDelete = fuzzRandomInt(pGrp->nCol);
    for(i=pGrp->nCol-1; i>=0; i--){
      if( pGrp->aPK[i] && pChange->iDelete!=i ) break;
    }
    if( i<0 ) return -1;
  }

  if( pChange->eType==FUZZ_GROUP_SWAP ){
    FuzzChangesetGroup *pGrp;
    int iGrp = pChange->iGroup;
    if( pParse->nGroup==1 ) return -1;
    while( iGrp==pChange->iGroup ){
      iGrp = fuzzRandomInt(pParse->nGroup);
    }
    pGrp = pParse->apGroup[pChange->iGroup];
    pParse->apGroup[pChange->iGroup] = pParse->apGroup[iGrp];
    pParse->apGroup[iGrp] = pGrp;
  }

  if( pChange->eType==FUZZ_VALUE_SUB 
   || pChange->eType==FUZZ_VALUE_MOD 
   || pChange->eType==FUZZ_VALUE_RND 
  ){
    iSub = fuzzRandomInt(pParse->nVal);
    pChange->pSub1 = pParse->apVal[iSub];
    if( pChange->eType==FUZZ_VALUE_SUB ){
      iSub = fuzzRandomInt(pParse->nVal);
      pChange->pSub2 = pParse->apVal[iSub];
    }else{
      pChange->pSub2 = pChange->aSub;
    }

    if( pChange->eType==FUZZ_VALUE_RND ){
      pChange->aSub[0] = (u8)(fuzzRandomInt(5) + 1);
      switch( pChange->aSub[0] ){
        case 0x01: {                  /* integer */
          u64 iVal = fuzzRandomU64();
          fuzzPutU64(&pChange->aSub[1], iVal);
          break;
        }

        case 0x02: {                  /* real */
          u64 iVal1 = fuzzRandomU64();
          u64 iVal2 = fuzzRandomU64();
          double d = (double)iVal1 / (double)iVal2;
          memcpy(&iVal1, &d, sizeof(iVal1));
          fuzzPutU64(&pChange->aSub[1], iVal1);
          break;
        }

        case 0x03:                    /* text */
        case 0x04: {                  /* blob */
          int nByte = fuzzRandomInt(48);
          pChange->aSub[1] = nByte;
          fuzzRandomBlob(nByte, &pChange->aSub[2]);
          if( pChange->aSub[0]==0x03 ){
            int i;
            for(i=0; i<nByte; i++){
              pChange->aSub[2+i] &= 0x7F;
            }
          }
          break;
        }
      }
    }
    if( pChange->eType==FUZZ_VALUE_MOD ){
      int sz;
      int iMod = -1;
      fuzzChangeSize(pChange->pSub1, &sz);
      memcpy(pChange->aSub, pChange->pSub1, sz);
      switch( pChange->aSub[0] ){
        case 0x01:
        case 0x02:
          iMod = fuzzRandomInt(8) + 1;
          break;

        case 0x03:                    /* text */
        case 0x04: {                  /* blob */
          int nByte;
          int iFirst = 1 + fuzzGetVarint(&pChange->aSub[1], &nByte);
          if( nByte>0 ){
            iMod = fuzzRandomInt(nByte) + iFirst;
          }
          break;
        }
      }

      if( iMod>=0 ){
        u8 mask = (1 << fuzzRandomInt(8 - (pChange->aSub[0]==0x03)));
        pChange->aSub[iMod] ^= mask;
      }
    }
  }

  return SQLITE_OK;
}

/*
** Copy a single change from the input to the output changeset, making
** any modifications specified by (*pFuzz).
*/
static int fuzzCopyChange(
  FuzzChangeset *pParse,
  int iGrp,
  FuzzChange *pFuzz,
  u8 **pp, u8 **ppOut             /* IN/OUT: Input and output pointers */
){
  int bPS = pParse->bPatchset;
  FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
  u8 *p = *pp;
  u8 *pOut = *ppOut;
  u8 eType = p++[0];
  int iRec;
  int nRec = ((eType==SQLITE_UPDATE && !bPS) ? 2 : 1);
  int iUndef = -1;
  int nUpdate = 0;

  u8 eNew = eType;
  if( pFuzz->iCurrent==pFuzz->iChange && pFuzz->eType==FUZZ_CHANGE_TYPE ){
    switch( eType ){
      case SQLITE_INSERT:
        eNew = SQLITE_DELETE;
        break;
      case SQLITE_DELETE:
        eNew = SQLITE_UPDATE;
        break;
      case SQLITE_UPDATE:
        eNew = SQLITE_INSERT;
        break;
    }
  }

  if( pFuzz->iCurrent==pFuzz->iChange 
   && pFuzz->eType==FUZZ_CHANGE_FIELD && eType==SQLITE_UPDATE
  ){
    int sz;
    int i;
    int nDef = 0;
    u8 *pCsr = p+1;
    for(i=0; i<pGrp->nCol; i++){
      if( pCsr[0] && pGrp->aPK[i]==0 ) nDef++;
      fuzzChangeSize(pCsr, &sz);
      pCsr += sz;
    }
    if( nDef<=1 ) return -1;
    nDef = fuzzRandomInt(nDef);
    pCsr = p+1;
    for(i=0; i<pGrp->nCol; i++){
      if( pCsr[0] && pGrp->aPK[i]==0 ){
        if( nDef==0 ) iUndef = i;
        nDef--;
      }
      fuzzChangeSize(pCsr, &sz);
      pCsr += sz;
    }
  }

  /* Copy the change type and indirect flag. If the fuzz mode is
  ** FUZZ_CHANGE_INDIRECT, and the current change is the one selected for
  ** fuzzing, invert the indirect flag.  */
  *(pOut++) = eNew;
  if( pFuzz->eType==FUZZ_CHANGE_INDIRECT && pFuzz->iCurrent==pFuzz->iChange ){
    *(pOut++) = !(*(p++));
  }else{
    *(pOut++) = *(p++);
  }

  for(iRec=0; iRec<nRec; iRec++){
    int i;

    /* Copy the next record from the output to the input.
    */
    for(i=0; i<pGrp->nCol; i++){
      int sz;
      u8 *pCopy = p;

      /* If this is a patchset, and the input is a DELETE, then the only
      ** fields present are the PK fields. So, if this is not a PK, skip to 
      ** the next column. If the current fuzz is FUZZ_CHANGE_TYPE, then
      ** write a randomly selected value to the output.  */
      if( bPS && eType==SQLITE_DELETE && pGrp->aPK[i]==0 ){
        if( eType!=eNew ){
          assert( eNew==SQLITE_UPDATE );
          do {
            pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
          }while( pCopy[0]==0x00 );
          fuzzChangeSize(pCopy, &sz);
          memcpy(pOut, pCopy, sz);
          pOut += sz;
        }
        continue;
      }

      if( p==pFuzz->pSub1 ){
        pCopy = pFuzz->pSub2;
      }else if( p==pFuzz->pSub2 ){
        pCopy = pFuzz->pSub1;
      }else if( i==iUndef ){
        pCopy = "\0";
      }

      if( pCopy[0]==0x00 && eNew!=eType && eType==SQLITE_UPDATE && iRec==0 ){
        while( pCopy[0]==0x00 ){
          pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
        }
      }else if( p[0]==0x00 && pCopy[0]!=0x00 ){
        return -1;
      }else{
        if( pGrp->aPK[i]>0 && pCopy[0]==0x05 ) return -1;
      }

      if( (pFuzz->iGroup!=iGrp || i!=pFuzz->iDelete)
       && (eNew==eType || eType!=SQLITE_UPDATE || iRec==0)
       && (eNew==eType || eNew!=SQLITE_DELETE || !bPS || pGrp->aPK[i])
      ){
        fuzzChangeSize(pCopy, &sz);
        memcpy(pOut, pCopy, sz);
        pOut += sz;
        nUpdate += (pGrp->aPK[i]==0 && pCopy[0]!=0x00);
      }

      fuzzChangeSize(p, &sz);
      p += sz;
    }

    if( iGrp==pFuzz->iGroup ){
      if( pFuzz->eType==FUZZ_COLUMN_ADD ){
        if( !bPS || eType!=SQLITE_DELETE ) *(pOut++) = 0x05;
      }else if( pFuzz->eType==FUZZ_COLUMN_ADDPK ){
        if( iRec==1 ){
          *(pOut++) = 0x00;
        }else{
          u8 *pNew;
          int szNew;
          do {
            pNew = pParse->apVal[fuzzRandomInt(pParse->nVal)];
          }while( pNew[0]==0x00 || pNew[0]==0x05 );
          fuzzChangeSize(pNew, &szNew);
          memcpy(pOut, pNew, szNew);
          pOut += szNew;
        }
      }
    }
  }

  if( pFuzz->iCurrent==pFuzz->iChange ){
    if( pFuzz->eType==FUZZ_CHANGE_DUP ){
      int nByte = pOut - (*ppOut);
      memcpy(pOut, *ppOut, nByte);
      pOut += nByte;
    }

    if( pFuzz->eType==FUZZ_CHANGE_DEL ){
      pOut = *ppOut;
    }
    if( eNew!=eType && eNew==SQLITE_UPDATE && !bPS ){
      int i;
      u8 *pCsr = (*ppOut) + 2;
      for(i=0; i<pGrp->nCol; i++){
        int sz;
        u8 *pCopy = pCsr;
        if( pGrp->aPK[i] ) pCopy = "\0";
        fuzzChangeSize(pCopy, &sz);
        memcpy(pOut, pCopy, sz);
        pOut += sz;
        fuzzChangeSize(pCsr, &sz);
        pCsr += sz;
      }
    }
  }

  /* If a column is being deleted from this group, and this change was an 
  ** UPDATE, and there are now no non-PK, non-undefined columns in the 
  ** change, remove it altogether. */
  if( pFuzz->eType==FUZZ_COLUMN_DEL && pFuzz->iGroup==iGrp 
   && eType==SQLITE_UPDATE && nUpdate==0 
  ){
    pOut = *ppOut;
  }

  *pp = p;
  *ppOut = pOut;
  pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD);
  return SQLITE_OK;
}

/*
** Fuzz the changeset parsed into object pParse and write the results 
** to file zOut on disk. Argument pBuf points to a buffer that is guaranteed
** to be large enough to hold the fuzzed changeset.
**
** Return SQLITE_OK if successful, or an SQLite error code if an error occurs.
*/
static int fuzzDoOneFuzz(
  const char *zOut,               /* Filename to write modified changeset to */
  u8 *pBuf,                       /* Buffer to use for modified changeset */
  FuzzChangeset *pParse           /* Parse of input changeset */
){
  FuzzChange change;
  int iGrp;
  int rc = -1;

  while( rc<0 ){
    u8 *pOut = pBuf;
    rc = fuzzSelectChange(pParse, &change);
    for(iGrp=0; rc==SQLITE_OK && iGrp<pParse->nGroup; iGrp++){
      FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
      int nTab = strlen(pGrp->zTab) + 1;
      int j;
      int nRep = 1;

      /* If this is the group to delete for a FUZZ_GROUP_DEL change, jump to
      ** the next group. Unless this is the only group in the changeset - in
      ** that case this change cannot be applied.
      **
      ** Or, if this is a FUZZ_GROUP_DUP, set nRep to 2 to output two
      ** copies of the group. */
      if( change.iGroup==iGrp ){
        if( change.eType==FUZZ_GROUP_DEL ){
          if( pParse->nGroup==1 ) rc = -1;
          continue;
        }
        else if( change.eType==FUZZ_GROUP_DUP ){
          nRep = 2;
        }
      }

      for(j=0; j<nRep; j++){
        int i;
        u8 *pSaved;
        u8 *p = pGrp->aChange;
        int nCol = pGrp->nCol;
        int iPKDel = 0;
        if( iGrp==change.iGroup ){
          if( change.eType==FUZZ_COLUMN_ADD 
           || change.eType==FUZZ_COLUMN_ADDPK 
          ){
            nCol++;
          }else if( change.eType==FUZZ_COLUMN_DEL ){
            nCol--;
            iPKDel = pGrp->aPK[change.iDelete];
          }
        }

        /* Output a table header */
        pOut++[0] = pParse->bPatchset ? 'P' : 'T';
        pOut += fuzzPutVarint(pOut, nCol);

        for(i=0; i<pGrp->nCol; i++){
          if( iGrp!=change.iGroup || i!=change.iDelete ){
            u8 v = pGrp->aPK[i];
            if( iPKDel && v>iPKDel ) v--;
            *(pOut++) = v;
          }
        }
        if( nCol>pGrp->nCol ){
          if( change.eType==FUZZ_COLUMN_ADD ){
            *(pOut++) = 0x00;
          }else{
            u8 max = 0;
            for(i=0; i<pGrp->nCol; i++){
              if( pGrp->aPK[i]>max ) max = pGrp->aPK[i];
            }
            *(pOut++) = max+1;
          }
        }
        memcpy(pOut, pGrp->zTab, nTab);
        pOut += nTab;

        /* Output the change array. */
        pSaved = pOut;
        for(i=0; rc==SQLITE_OK && i<pGrp->nChange; i++){
          rc = fuzzCopyChange(pParse, iGrp, &change, &p, &pOut);
        }
        if( pOut==pSaved ) rc = -1;
      }
    }
    if( rc==SQLITE_OK ){
      fuzzWriteFile(zOut, pBuf, pOut-pBuf);
    }
  }

  return rc;
}

int main(int argc, char **argv){
  int nRepeat = 0;                /* Number of output files */
  int iSeed = 0;                  /* Value of PRNG seed */
  const char *zInput;             /* Name of input file */
  void *pChangeset = 0;           /* Input changeset */
  int nChangeset = 0;             /* Size of input changeset in bytes */
  int i;                          /* Current output file */
  FuzzChangeset changeset;        /* Partially parsed changeset */
  int rc;
  u8 *pBuf = 0;

  if( argc!=4 && argc!=2 ) usage(argv[0]);
  zInput = argv[1];

  fuzzReadFile(zInput, &nChangeset, &pChangeset);
  rc = fuzzParseChangeset(pChangeset, nChangeset, &changeset);

  if( rc==SQLITE_OK ){
    if( argc==2 ){
      for(i=0; i<changeset.nGroup; i++){
        fuzzPrintGroup(&changeset, changeset.apGroup[i]);
      }
    }else{
      pBuf = (u8*)fuzzMalloc(nChangeset*2 + 1024);
      if( pBuf==0 ){
        rc = SQLITE_NOMEM;
      }else{
        iSeed = atoi(argv[2]);
        nRepeat = atoi(argv[3]);
        fuzzRandomSeed((unsigned int)iSeed);
        for(i=0; rc==SQLITE_OK && i<nRepeat; i++){
          char *zOut = sqlite3_mprintf("%s-%d", zInput, i);
          rc = fuzzDoOneFuzz(zOut, pBuf, &changeset);
          sqlite3_free(zOut);
        }
        fuzzFree(pBuf);
      }
    }
  }

  if( rc!=SQLITE_OK ){
    fprintf(stderr, "error while processing changeset: %d\n", rc);
  }

  return rc;
}

Added ext/session/changesetfuzz1.test.









































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# 2018 November 08
#
# 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.
#
#***********************************************************************
#

if {![info exists testdir]} {
  set testdir [file join [file dirname [info script]] .. .. test]
} 
source [file join [file dirname [info script]] session_common.tcl]
source $testdir/tester.tcl
ifcapable !session {finish_test; return}
set testprefix changesetfuzz1


set CF [test_find_binary changesetfuzz]
if {$CF==""} {
  finish_test
  return
}

proc writefile {zFile data} {
  set fd [open $zFile w]
  fconfigure $fd -translation binary -encoding binary
  puts -nonewline $fd $data
  close $fd
}

do_execsql_test 1.0 {
  CREATE TABLE t1(a, b, c, d, PRIMARY KEY(c, d));
  CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);

  INSERT INTO t1 VALUES ('one', 'two', 'three', 'four'), 
                        ('five', 'six', 'seven', 'eight'), 
                        ('nine', 'ten', 'eleven', 'twelve');
  INSERT INTO t2 VALUES (1, 2, 3), (4, 5, 6), (7, 8, 9);
}

set C [changeset_from_sql {
  INSERT INTO t2 VALUES(10, 11, 12);
  DELETE FROM t2 WHERE a=1;
  UPDATE t1 SET b='forty-five' WHERE a='one';
  UPDATE t1 SET a='twenty-nine', b='seventy' WHERE a='five';
}]
writefile c1.changeset $C

do_test 1.1 {
  for {set j 0} {$j < 200} {incr j} {
    forcecopy c1.changeset input.changeset
    for {set i 0} {$i < 6} {incr i} {
      exec $CF input.changeset $i 1
      exec $CF input.changeset-0
      forcecopy input.changeset-0 input.changeset
    }
  }
} {}

set P [patchset_from_sql {
  INSERT INTO t2 VALUES(13, 14, 15);
  DELETE FROM t2 WHERE a=4;
  UPDATE t1 SET b='thirteen' WHERE a='one';
  UPDATE t1 SET a='ninety-seven', b='twenty' WHERE a='five';
}]
writefile p1.patchset $P
do_test 1.2 {
  for {set j 0} {$j < 200} {incr j} {
    forcecopy p1.patchset input.patchset
    for {set i 0} {$i < 6} {incr i} {
      exec $CF input.patchset $i 1
      exec $CF input.patchset-0
      forcecopy input.patchset-0 input.patchset
    }
  }
} {}


finish_test

Changes to ext/session/sessionC.test.

191
192
193
194
195
196
197
198
    SELECT * FROM t3;
  }
} {1 1 3 3}



finish_test








<
191
192
193
194
195
196
197

    SELECT * FROM t3;
  }
} {1 1 3 3}



finish_test

Changes to ext/session/sessionD.test.

251
252
253
254
255
256
257
258
} {0 {}}
S delete
do_catchsql_test 4.5.2 {
  SELECT * FROM ixua.i8;
} {1 {no such table: ixua.i8}}

finish_test








<
251
252
253
254
255
256
257

} {0 {}}
S delete
do_catchsql_test 4.5.2 {
  SELECT * FROM ixua.i8;
} {1 {no such table: ixua.i8}}

finish_test

Changes to ext/session/sessionE.test.

107
108
109
110
111
112
113
114
115
  {INSERT t2 0 X. {} {i 7 i 8}}
}


S delete

finish_test









<
<
107
108
109
110
111
112
113


  {INSERT t2 0 X. {} {i 7 i 8}}
}


S delete

finish_test


Changes to ext/session/sessionF.test.

288
289
290
291
292
293
294
295
  }

  do_test 3.$tn { set res } [list {*}$result]
}


finish_test








<
288
289
290
291
292
293
294

  }

  do_test 3.$tn { set res } [list {*}$result]
}


finish_test

Changes to ext/session/sessionG.test.

244
245
246
247
248
249
250
251
  SELECT count(*) FROM t1 WHERE number_name(a+1) IS NOT b; 
} {0}

# db eval { SELECT * FROM t1 } { puts "$a || $b" }


finish_test








<
244
245
246
247
248
249
250

  SELECT count(*) FROM t1 WHERE number_name(a+1) IS NOT b; 
} {0}

# db eval { SELECT * FROM t1 } { puts "$a || $b" }


finish_test

Changes to ext/session/sessionH.test.

32
33
34
35
36
37
38
39
    INSERT INTO t1 SELECT 'abcde', randomblob(16), i FROM s;
  }
  compare_db db db2
} {}


finish_test








<
32
33
34
35
36
37
38

    INSERT INTO t1 SELECT 'abcde', randomblob(16), i FROM s;
  }
  compare_db db db2
} {}


finish_test

Changes to ext/session/sessionfault2.test.

278
279
280
281
282
283
284
285
} -test {
  catch { R delete } 
  faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
}


finish_test








<
278
279
280
281
282
283
284

} -test {
  catch { R delete } 
  faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
}


finish_test

Changes to ext/session/sessionrebase.test.

470
471
472
473
474
475
476
477
    R configure $::rebase
    expr [catch {R rebase $P}]==0
  } $rebasable

  catch { R delete }
}
finish_test








<
470
471
472
473
474
475
476

    R configure $::rebase
    expr [catch {R rebase $P}]==0
  } $rebasable

  catch { R delete }
}
finish_test

Changes to ext/session/sessionstat1.test.

304
305
306
307
308
309
310
311
    return "REPLACE"
  }
  sqlite3changeset_apply db2 $C xConflict
  execsql { SELECT * FROM sqlite_stat1 ORDER BY 1,2 } db2
} {t3 null 3}

finish_test








<
304
305
306
307
308
309
310

    return "REPLACE"
  }
  sqlite3changeset_apply db2 $C xConflict
  execsql { SELECT * FROM sqlite_stat1 ORDER BY 1,2 } db2
} {t3 null 3}

finish_test

Changes to ext/session/sessionwor.test.

50
51
52
53
54
55
56
57
do_iterator_test 1.3 t1 {
  DELETE FROM t1;
} {
  {DELETE t1 0 X. {t one t three} {}}
}

finish_test








<
50
51
52
53
54
55
56

do_iterator_test 1.3 t1 {
  DELETE FROM t1;
} {
  {DELETE t1 0 X. {t one t three} {}}
}

finish_test

Changes to main.mk.

998
999
1000
1001
1002
1003
1004




1005
1006
1007
1008
1009
1010
1011

showshm$(EXE):	$(TOP)/tool/showshm.c
	$(TCC) -o showshm$(EXE) $(TOP)/tool/showshm.c

changeset$(EXE):	$(TOP)/ext/session/changeset.c sqlite3.o
	$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o changeset$(EXE) \
		$(TOP)/ext/session/changeset.c sqlite3.o $(THREADLIB)





fts3view$(EXE):	$(TOP)/ext/fts3/tool/fts3view.c sqlite3.o
	$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o fts3view$(EXE) \
		$(TOP)/ext/fts3/tool/fts3view.c sqlite3.o $(THREADLIB)

rollback-test$(EXE):	$(TOP)/tool/rollback-test.c sqlite3.o
	$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o rollback-test$(EXE) \







>
>
>
>







998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015

showshm$(EXE):	$(TOP)/tool/showshm.c
	$(TCC) -o showshm$(EXE) $(TOP)/tool/showshm.c

changeset$(EXE):	$(TOP)/ext/session/changeset.c sqlite3.o
	$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o changeset$(EXE) \
		$(TOP)/ext/session/changeset.c sqlite3.o $(THREADLIB)

changesetfuzz$(EXE):	$(TOP)/ext/session/changesetfuzz.c sqlite3.o
	$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o changesetfuzz$(EXE) \
		$(TOP)/ext/session/changesetfuzz.c sqlite3.o $(THREADLIB)

fts3view$(EXE):	$(TOP)/ext/fts3/tool/fts3view.c sqlite3.o
	$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o fts3view$(EXE) \
		$(TOP)/ext/fts3/tool/fts3view.c sqlite3.o $(THREADLIB)

rollback-test$(EXE):	$(TOP)/tool/rollback-test.c sqlite3.o
	$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o rollback-test$(EXE) \

Changes to src/build.c.

1889
1890
1891
1892
1893
1894
1895


























1896
1897
1898
1899
1900
1901
1902
....
1928
1929
1930
1931
1932
1933
1934




1935
1936
1937
1938
1939
1940
1941
    assert( pPk->nColumn==j );
    assert( pTab->nCol==j );
  }else{
    pPk->nColumn = pTab->nCol;
  }
  recomputeColumnsNotIndexed(pPk);
}



























/*
** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement.
**
** The table structure that other action routines have been building
** is added to the internal hash tables, assuming no errors have
................................................................................

  if( pEnd==0 && pSelect==0 ){
    return;
  }
  assert( !db->mallocFailed );
  p = pParse->pNewTable;
  if( p==0 ) return;





  /* If the db->init.busy is 1 it means we are reading the SQL off the
  ** "sqlite_master" or "sqlite_temp_master" table on the disk.
  ** So do not write to the disk again.  Extract the root page number
  ** for the table from the db->init.newTnum field.  (The page number
  ** should have been put there by the sqliteOpenCb routine.)
  **







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







 







>
>
>
>







1889
1890
1891
1892
1893
1894
1895
1896
1897
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
....
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
    assert( pPk->nColumn==j );
    assert( pTab->nCol==j );
  }else{
    pPk->nColumn = pTab->nCol;
  }
  recomputeColumnsNotIndexed(pPk);
}

/*
** Return true if zName is a shadow table name in the current database
** connection.
**
** zName is temporarily modified while this routine is running, but is
** restored to its original value prior to this routine returning.
*/
static int isShadowTableName(sqlite3 *db, char *zName){
  char *zTail;                  /* Pointer to the last "_" in zName */
  Table *pTab;                  /* Table that zName is a shadow of */
  Module *pMod;                 /* Module for the virtual table */

  zTail = strrchr(zName, '_');
  if( zTail==0 ) return 0;
  *zTail = 0;
  pTab = sqlite3FindTable(db, zName, 0);
  *zTail = '_';
  if( pTab==0 ) return 0;
  if( !IsVirtual(pTab) ) return 0;
  pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
  if( pMod==0 ) return 0;
  if( pMod->pModule->iVersion<3 ) return 0;
  if( pMod->pModule->xShadowName==0 ) return 0;
  return pMod->pModule->xShadowName(zTail+1);
}

/*
** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement.
**
** The table structure that other action routines have been building
** is added to the internal hash tables, assuming no errors have
................................................................................

  if( pEnd==0 && pSelect==0 ){
    return;
  }
  assert( !db->mallocFailed );
  p = pParse->pNewTable;
  if( p==0 ) return;

  if( pSelect==0 && isShadowTableName(db, p->zName) ){
    p->tabFlags |= TF_Shadow;
  }

  /* If the db->init.busy is 1 it means we are reading the SQL off the
  ** "sqlite_master" or "sqlite_temp_master" table on the disk.
  ** So do not write to the disk again.  Extract the root page number
  ** for the table from the db->init.newTnum field.  (The page number
  ** should have been put there by the sqliteOpenCb routine.)
  **

Changes to src/dbpage.c.

403
404
405
406
407
408
409

410
411
412
413
414
415
    0,                            /* xCommit */
    0,                            /* xRollback */
    0,                            /* xFindMethod */
    0,                            /* xRename */
    0,                            /* xSavepoint */
    0,                            /* xRelease */
    0,                            /* xRollbackTo */

  };
  return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
}
#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
#endif /* SQLITE_ENABLE_DBSTAT_VTAB */







>






403
404
405
406
407
408
409
410
411
412
413
414
415
416
    0,                            /* xCommit */
    0,                            /* xRollback */
    0,                            /* xFindMethod */
    0,                            /* xRename */
    0,                            /* xSavepoint */
    0,                            /* xRelease */
    0,                            /* xRollbackTo */
    0                             /* xShadowName */
  };
  return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
}
#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
#endif /* SQLITE_ENABLE_DBSTAT_VTAB */

Changes to src/dbstat.c.

716
717
718
719
720
721
722

723
724
725
726
727
728
    0,                            /* xCommit */
    0,                            /* xRollback */
    0,                            /* xFindMethod */
    0,                            /* xRename */
    0,                            /* xSavepoint */
    0,                            /* xRelease */
    0,                            /* xRollbackTo */

  };
  return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
}
#elif defined(SQLITE_ENABLE_DBSTAT_VTAB)
int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
#endif /* SQLITE_ENABLE_DBSTAT_VTAB */







>






716
717
718
719
720
721
722
723
724
725
726
727
728
729
    0,                            /* xCommit */
    0,                            /* xRollback */
    0,                            /* xFindMethod */
    0,                            /* xRename */
    0,                            /* xSavepoint */
    0,                            /* xRelease */
    0,                            /* xRollbackTo */
    0                             /* xShadowName */
  };
  return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
}
#elif defined(SQLITE_ENABLE_DBSTAT_VTAB)
int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
#endif /* SQLITE_ENABLE_DBSTAT_VTAB */

Changes to src/delete.c.

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
    pTab->nTabRef++;
  }
  if( sqlite3IndexedByLookup(pParse, pItem) ){
    pTab = 0;
  }
  return pTab;
}
































/*
** Check to make sure the given table is writable.  If it is not
** writable, generate an error message and return 1.  If it is
** writable return 0;
*/
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
  /* A table is not writable under the following circumstances:
  **
  **   1) It is a virtual table and no implementation of the xUpdate method
  **      has been provided, or
  **   2) It is a system table (i.e. sqlite_master), this call is not
  **      part of a nested parse and writable_schema pragma has not 
  **      been specified.
  **
  ** In either case leave an error message in pParse and return non-zero.
  */
  if( ( IsVirtual(pTab) 
     && sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 )
   || ( (pTab->tabFlags & TF_Readonly)!=0
     && sqlite3WritableSchema(pParse->db)==0
     && pParse->nested==0)
  ){
    sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
    return 1;
  }

#ifndef SQLITE_OMIT_VIEW
  if( !viewOk && pTab->pSelect ){
    sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
    return 1;
  }
#endif
  return 0;







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







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



<







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















85
86
87

88
89
90
91
92
93
94
    pTab->nTabRef++;
  }
  if( sqlite3IndexedByLookup(pParse, pItem) ){
    pTab = 0;
  }
  return pTab;
}

/* Return true if table pTab is read-only.
**
** A table is read-only if any of the following are true:
**
**   1) It is a virtual table and no implementation of the xUpdate method
**      has been provided
**
**   2) It is a system table (i.e. sqlite_master), this call is not
**      part of a nested parse and writable_schema pragma has not 
**      been specified
**
**   3) The table is a shadow table, the database connection is in
**      defensive mode, and the current sqlite3_prepare()
**      is for a top-level SQL statement.
*/
static int tabIsReadOnly(Parse *pParse, Table *pTab){
  sqlite3 *db;
  if( IsVirtual(pTab) ){
    return sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0;
  }
  if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0;
  db = pParse->db;
  if( (pTab->tabFlags & TF_Readonly)!=0 ){
    return sqlite3WritableSchema(db)==0 && pParse->nested==0;
  }
  assert( pTab->tabFlags & TF_Shadow );
  return (db->flags & SQLITE_Defensive)!=0
           && db->nVdbeExec==0
           && db->pVtabCtx==0;
}

/*
** Check to make sure the given table is writable.  If it is not
** writable, generate an error message and return 1.  If it is
** writable return 0;
*/
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
  if( tabIsReadOnly(pParse, pTab) ){















    sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
    return 1;
  }

#ifndef SQLITE_OMIT_VIEW
  if( !viewOk && pTab->pSelect ){
    sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
    return 1;
  }
#endif
  return 0;

Changes to src/main.c.

3155
3156
3157
3158
3159
3160
3161



3162
3163
3164
3165
3166
3167
3168
                 | SQLITE_CellSizeCk
#endif
#if defined(SQLITE_ENABLE_FTS3_TOKENIZER)
                 | SQLITE_Fts3Tokenizer
#endif
#if defined(SQLITE_ENABLE_QPSG)
                 | SQLITE_EnableQPSG



#endif
      ;
  sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqlite3HashInit(&db->aModule);
#endif








>
>
>







3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
                 | SQLITE_CellSizeCk
#endif
#if defined(SQLITE_ENABLE_FTS3_TOKENIZER)
                 | SQLITE_Fts3Tokenizer
#endif
#if defined(SQLITE_ENABLE_QPSG)
                 | SQLITE_EnableQPSG
#endif
#if defined(SQLITE_DEFAULT_DEFENSIVE)
                 | SQLITE_Defensive
#endif
      ;
  sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqlite3HashInit(&db->aModule);
#endif

Changes to src/pragma.c.

2473
2474
2475
2476
2477
2478
2479
2480

2481
2482
2483
2484
2485
2486
2487
  0,                           /* xSync - sync transaction */
  0,                           /* xCommit - commit transaction */
  0,                           /* xRollback - rollback transaction */
  0,                           /* xFindFunction - function overloading */
  0,                           /* xRename - rename the table */
  0,                           /* xSavepoint */
  0,                           /* xRelease */
  0                            /* xRollbackTo */

};

/*
** Check to see if zTabName is really the name of a pragma.  If it is,
** then register an eponymous virtual table for that pragma and return
** a pointer to the Module object for the new virtual table.
*/







|
>







2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
  0,                           /* xSync - sync transaction */
  0,                           /* xCommit - commit transaction */
  0,                           /* xRollback - rollback transaction */
  0,                           /* xFindFunction - function overloading */
  0,                           /* xRename - rename the table */
  0,                           /* xSavepoint */
  0,                           /* xRelease */
  0,                           /* xRollbackTo */
  0                            /* xShadowName */
};

/*
** Check to see if zTabName is really the name of a pragma.  If it is,
** then register an eponymous virtual table for that pragma and return
** a pointer to the Module object for the new virtual table.
*/

Changes to src/sqlite.h.in.

2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173

2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
....
6319
6320
6321
6322
6323
6324
6325



6326
6327
6328
6329
6330
6331
6332
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
** </ol>
** Because resetting a database is destructive and irreversible, the
** process requires the use of this obscure API and multiple steps to help
** ensure that it does not happen by accident.
**
** <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
** <dd>The SQLITE_DBCONFIG_DEFENSIVE option actives or deactivates the
** "defensive" flag for a database connection.  When the defensive
** flag is enabled, some obscure features of SQLite are disabled in order
** to reduce the attack surface. Applications that run untrusted SQL
** can activate this flag to reduce the risk of zero-day exploits.
** <p>
** Features disabled by the defensive flag include:
** <ul>
** <li>The [PRAGMA writable_schema=ON] statement.
** <li>Writes to the [sqlite_dbpage] virtual table.

** </ul>
** New restrictions may be added in future releases.
** <p>
** To be clear: It should never be possible for hostile SQL to cause
** arbitrary memory reads, memory leaks, buffer overflows, assertion
** faults, arbitrary code execution, crashes, or other mischief, regardless
** of the value of the defensive flag.  Any occurrance of these problems
** is considered a serious bug and will be fixed promptly.  It is not
** necessary to enable the defensive flag in order to make SQLite secure
** against attack. The defensive flag merely provides an additional layer
** of defense against unknown vulnerabilities.
** </dd>
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME            1000 /* const char* */
#define SQLITE_DBCONFIG_LOOKASIDE             1001 /* void* int int */
#define SQLITE_DBCONFIG_ENABLE_FKEY           1002 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_TRIGGER        1003 /* int int* */
................................................................................
                       void **ppArg);
  int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
  /* The methods above are in version 1 of the sqlite_module object. Those 
  ** below are for version 2 and greater. */
  int (*xSavepoint)(sqlite3_vtab *pVTab, int);
  int (*xRelease)(sqlite3_vtab *pVTab, int);
  int (*xRollbackTo)(sqlite3_vtab *pVTab, int);



};

/*
** CAPI3REF: Virtual Table Indexing Information
** KEYWORDS: sqlite3_index_info
**
** The sqlite3_index_info structure and its substructures is used as part







|

|
|
|
<
<

|
|
>

<
<
<
<
<
<
<
<
<
<







 







>
>
>







2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168


2169
2170
2171
2172
2173










2174
2175
2176
2177
2178
2179
2180
....
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
** </ol>
** Because resetting a database is destructive and irreversible, the
** process requires the use of this obscure API and multiple steps to help
** ensure that it does not happen by accident.
**
** <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the
** "defensive" flag for a database connection.  When the defensive
** flag is enabled, language features that allow ordinary SQL to 
** deliberately corrupt the database file are disabled.  The disabled
** features include but are not limited to the following:


** <ul>
** <li> The [PRAGMA writable_schema=ON] statement.
** <li> Writes to the [sqlite_dbpage] virtual table.
** <li> Direct writes to shadow tables.
** </ul>










** </dd>
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME            1000 /* const char* */
#define SQLITE_DBCONFIG_LOOKASIDE             1001 /* void* int int */
#define SQLITE_DBCONFIG_ENABLE_FKEY           1002 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_TRIGGER        1003 /* int int* */
................................................................................
                       void **ppArg);
  int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
  /* The methods above are in version 1 of the sqlite_module object. Those 
  ** below are for version 2 and greater. */
  int (*xSavepoint)(sqlite3_vtab *pVTab, int);
  int (*xRelease)(sqlite3_vtab *pVTab, int);
  int (*xRollbackTo)(sqlite3_vtab *pVTab, int);
  /* The methods above are in versions 1 and 2 of the sqlite_module object.
  ** Those below are for version 3 and greater. */
  int (*xShadowName)(const char*);
};

/*
** CAPI3REF: Virtual Table Indexing Information
** KEYWORDS: sqlite3_index_info
**
** The sqlite3_index_info structure and its substructures is used as part

Changes to src/sqliteInt.h.

2013
2014
2015
2016
2017
2018
2019

2020
2021
2022
2023
2024
2025
2026
#define TF_HasStat1        0x0010    /* nRowLogEst set from sqlite_stat1 */
#define TF_WithoutRowid    0x0020    /* No rowid.  PRIMARY KEY is the key */
#define TF_NoVisibleRowid  0x0040    /* No user-visible "rowid" column */
#define TF_OOOHidden       0x0080    /* Out-of-Order hidden columns */
#define TF_StatsUsed       0x0100    /* Query planner decisions affected by
                                     ** Index.aiRowLogEst[] values */
#define TF_HasNotNull      0x0200    /* Contains NOT NULL constraints */


/*
** Test to see whether or not a table is a virtual table.  This is
** done as a macro so that it will be optimized out when virtual
** table support is omitted from the build.
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE







>







2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
#define TF_HasStat1        0x0010    /* nRowLogEst set from sqlite_stat1 */
#define TF_WithoutRowid    0x0020    /* No rowid.  PRIMARY KEY is the key */
#define TF_NoVisibleRowid  0x0040    /* No user-visible "rowid" column */
#define TF_OOOHidden       0x0080    /* Out-of-Order hidden columns */
#define TF_StatsUsed       0x0100    /* Query planner decisions affected by
                                     ** Index.aiRowLogEst[] values */
#define TF_HasNotNull      0x0200    /* Contains NOT NULL constraints */
#define TF_Shadow          0x0400    /* True for a shadow table */

/*
** Test to see whether or not a table is a virtual table.  This is
** done as a macro so that it will be optimized out when virtual
** table support is omitted from the build.
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE

Changes to src/vacuum.c.

162
163
164
165
166
167
168
169

170
171
172
173
174
175
176
  saved_flags = db->flags;
  saved_mDbFlags = db->mDbFlags;
  saved_nChange = db->nChange;
  saved_nTotalChange = db->nTotalChange;
  saved_mTrace = db->mTrace;
  db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
  db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
  db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows);

  db->mTrace = 0;

  zDbMain = db->aDb[iDb].zDbSName;
  pMain = db->aDb[iDb].pBt;
  isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));

  /* Attach the temporary database as 'vacuum_db'. The synchronous pragma







|
>







162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  saved_flags = db->flags;
  saved_mDbFlags = db->mDbFlags;
  saved_nChange = db->nChange;
  saved_nTotalChange = db->nTotalChange;
  saved_mTrace = db->mTrace;
  db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
  db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
  db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder
                   | SQLITE_Defensive | SQLITE_CountRows);
  db->mTrace = 0;

  zDbMain = db->aDb[iDb].zDbSName;
  pMain = db->aDb[iDb].pBt;
  isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));

  /* Attach the temporary database as 'vacuum_db'. The synchronous pragma

Changes to test/alter2.test.

60
61
62
63
64
65
66

67
68
69
70
71
72
73
..
87
88
89
90
91
92
93

94
95
96
97
98
99
100
# to the supplied value. This is 2 if the added column has a default that is
# NULL, or 3 otherwise. 
#
proc alter_table {tbl sql {file_format 2}} {
  sqlite3 dbat test.db
  set s [string map {' ''} $sql]
  set t [string map {' ''} $tbl]

  dbat eval [subst {
    PRAGMA writable_schema = 1;
    UPDATE sqlite_master SET sql = '$s' WHERE name = '$t' AND type = 'table';
    PRAGMA writable_schema = 0;
  }]
  dbat close
  set_file_format 2
................................................................................
  catchsql {SELECT substr('abcdefg',1,3)}
} {1 {bad function}}


#-----------------------------------------------------------------------
# Some basic tests to make sure short rows are handled.
#

do_test alter2-1.1 {
  execsql {
    CREATE TABLE abc(a, b);
    INSERT INTO abc VALUES(1, 2);
    INSERT INTO abc VALUES(3, 4);
    INSERT INTO abc VALUES(5, 6);
  }







>







 







>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# to the supplied value. This is 2 if the added column has a default that is
# NULL, or 3 otherwise. 
#
proc alter_table {tbl sql {file_format 2}} {
  sqlite3 dbat test.db
  set s [string map {' ''} $sql]
  set t [string map {' ''} $tbl]
  sqlite3_db_config dbat DEFENSIVE 0
  dbat eval [subst {
    PRAGMA writable_schema = 1;
    UPDATE sqlite_master SET sql = '$s' WHERE name = '$t' AND type = 'table';
    PRAGMA writable_schema = 0;
  }]
  dbat close
  set_file_format 2
................................................................................
  catchsql {SELECT substr('abcdefg',1,3)}
} {1 {bad function}}


#-----------------------------------------------------------------------
# Some basic tests to make sure short rows are handled.
#
sqlite3_db_config db DEFENSIVE 0
do_test alter2-1.1 {
  execsql {
    CREATE TABLE abc(a, b);
    INSERT INTO abc VALUES(1, 2);
    INSERT INTO abc VALUES(3, 4);
    INSERT INTO abc VALUES(5, 6);
  }

Changes to test/altercol.test.

549
550
551
552
553
554
555

556
557
558
559
560
561
562

do_execsql_test 13.1.3 {
  DROP TRIGGER tr1;
  CREATE INDEX x1i ON x1(i);
  SELECT sql FROM sqlite_master WHERE name='x1i';
} {{CREATE INDEX x1i ON x1(i)}}


do_execsql_test 13.1.4 {
  PRAGMA writable_schema = 1;
  UPDATE sqlite_master SET sql = 'CREATE INDEX x1i ON x1(j)' WHERE name='x1i';
} {}

do_catchsql_test 13.1.5 {
  ALTER TABLE x1 RENAME COLUMN t TO ttt;







>







549
550
551
552
553
554
555
556
557
558
559
560
561
562
563

do_execsql_test 13.1.3 {
  DROP TRIGGER tr1;
  CREATE INDEX x1i ON x1(i);
  SELECT sql FROM sqlite_master WHERE name='x1i';
} {{CREATE INDEX x1i ON x1(i)}}

sqlite3_db_config db DEFENSIVE 0
do_execsql_test 13.1.4 {
  PRAGMA writable_schema = 1;
  UPDATE sqlite_master SET sql = 'CREATE INDEX x1i ON x1(j)' WHERE name='x1i';
} {}

do_catchsql_test 13.1.5 {
  ALTER TABLE x1 RENAME COLUMN t TO ttt;

Changes to test/alterlegacy.test.

463
464
465
466
467
468
469
470
}
do_execsql_test 14.6 {
  ALTER TABLE t1 RENAME TO tt1;
}


finish_test








<
463
464
465
466
467
468
469

}
do_execsql_test 14.6 {
  ALTER TABLE t1 RENAME TO tt1;
}


finish_test

Changes to test/altertab.test.

501
502
503
504
505
506
507
508

do_execsql_test 15.5 {
  SELECT sql FROM sqlite_master WHERE name = 'y';
} {{CREATE VIEW y AS SELECT f2 AS f1 FROM x}}


finish_test








<
501
502
503
504
505
506
507


do_execsql_test 15.5 {
  SELECT sql FROM sqlite_master WHERE name = 'y';
} {{CREATE VIEW y AS SELECT f2 AS f1 FROM x}}


finish_test

Changes to test/altertab2.test.

83
84
85
86
87
88
89
90
  {CREATE TABLE c1(x REFERENCES "p3")}
  {CREATE TABLE c2(x, FOREIGN KEY (x) REFERENCES "p3")}
  {CREATE TABLE c3(x, FOREIGN KEY (x) REFERENCES "p3"(a))}
}


finish_test








<
83
84
85
86
87
88
89

  {CREATE TABLE c1(x REFERENCES "p3")}
  {CREATE TABLE c2(x, FOREIGN KEY (x) REFERENCES "p3")}
  {CREATE TABLE c3(x, FOREIGN KEY (x) REFERENCES "p3"(a))}
}


finish_test

Changes to test/analyze.test.

346
347
348
349
350
351
352

353
354
355
356
357
358
359
  } {t4i1 t4i2 t4}
}

# This test corrupts the database file so it must be the last test
# in the series.
#
do_test analyze-5.99 {

  execsql {
    PRAGMA writable_schema=on;
    UPDATE sqlite_master SET sql='nonsense' WHERE name='sqlite_stat1';
  }
  db close
  catch { sqlite3 db test.db }
  catchsql {







>







346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  } {t4i1 t4i2 t4}
}

# This test corrupts the database file so it must be the last test
# in the series.
#
do_test analyze-5.99 {
  sqlite3_db_config db DEFENSIVE 0
  execsql {
    PRAGMA writable_schema=on;
    UPDATE sqlite_master SET sql='nonsense' WHERE name='sqlite_stat1';
  }
  db close
  catch { sqlite3 db test.db }
  catchsql {

Changes to test/autoinc.test.

693
694
695
696
697
698
699

700
701
702
703
704
705
706
...
714
715
716
717
718
719
720

721
722
723
724
725
726
727
...
740
741
742
743
744
745
746

747
748
749
750
751
752
753
...
768
769
770
771
772
773
774

775
776
777
778
779
780
781
...
787
788
789
790
791
792
793

794
795
796
797
798
799
800
...
806
807
808
809
810
811
812

813
814
815
816
817
818
819
...
827
828
829
830
831
832
833

834
835
836
837
838
839
840
# 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'
................................................................................
  }} 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',
................................................................................
} else {
  set err {malformed database schema (sqlite_sequence) - near "VIRTUAL": syntax error}
}
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';
................................................................................
    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';
  }
................................................................................
  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';
................................................................................
  }} 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';
................................................................................
  }} 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';







>







 







>







 







>







 







>







 







>







 







>







 







>







693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
...
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
...
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
...
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
...
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
...
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
...
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
# 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
  sqlite3_db_config db DEFENSIVE 0
  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'
................................................................................
  }} msg]
  lappend res $msg
} {1 {database disk image is malformed}}
do_test autoinc-12.2 {
  db close
  forcedelete test.db
  sqlite3 db test.db
  sqlite3_db_config db DEFENSIVE 0
  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',
................................................................................
} else {
  set err {malformed database schema (sqlite_sequence) - near "VIRTUAL": syntax error}
}
do_test autoinc-12.3 {
  db close
  forcedelete test.db
  sqlite3 db test.db
  sqlite3_db_config db DEFENSIVE 0
  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';
................................................................................
    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'}]
  sqlite3_db_config db DEFENSIVE 0
  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';
  }
................................................................................
  lappend res $msg
} {1 {database disk image is malformed}}
breakpoint
do_test autoinc-12.5 {
  db close
  forcedelete test.db
  sqlite3 db test.db
  sqlite3_db_config db DEFENSIVE 0
  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';
................................................................................
  }} msg]
  lappend res $msg
} {1 {database disk image is malformed}}
do_test autoinc-12.6 {
  db close
  forcedelete test.db
  sqlite3 db test.db
  sqlite3_db_config db DEFENSIVE 0
  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';
................................................................................
  }} msg]
  lappend res $msg
} {0 ok}
do_test autoinc-12.7 {
  db close
  forcedelete test.db
  sqlite3 db test.db
  sqlite3_db_config db DEFENSIVE 0
  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';

Changes to test/bestindex5.test.

243
244
245
246
247
248
249
250
do_execsql_test 3.3 { SELECT rowid, * FROM t4 WHERE x!=245; } {}
do_execsql_test 3.4 { SELECT rowid, * FROM t4 WHERE x!='245'; } {}

do_execsql_test 3.5 { SELECT rowid, * FROM t4 WHERE rowid!=1 OR x!='245'; } {}


finish_test








<
243
244
245
246
247
248
249

do_execsql_test 3.3 { SELECT rowid, * FROM t4 WHERE x!=245; } {}
do_execsql_test 3.4 { SELECT rowid, * FROM t4 WHERE x!='245'; } {}

do_execsql_test 3.5 { SELECT rowid, * FROM t4 WHERE rowid!=1 OR x!='245'; } {}


finish_test

Changes to test/capi3.test.

737
738
739
740
741
742
743

744
745
746
747
748
749
750
...
755
756
757
758
759
760
761

762
763
764
765
766
767
768
    execsql {
      CREATE TABLE t1(a);
    }
    db close
  } {}
  do_test capi3-8.2 {
    sqlite3 db test.db

    execsql {
      PRAGMA writable_schema=ON;
      INSERT INTO sqlite_master VALUES(NULL,NULL,NULL,NULL,NULL);
    }
    db close
  } {}
  do_test capi3-8.3 {
................................................................................
  } {1 {malformed database schema (?)}}
  do_test capi3-8.4 {
    # Build a 5-field row record. The first field is a string 'table', and
    # subsequent fields are all NULL.
    db close
    forcedelete test.db test.db-journal
    sqlite3 db test.db

    execsql {
      CREATE TABLE t1(a);
      PRAGMA writable_schema=ON;
      INSERT INTO sqlite_master VALUES('table',NULL,NULL,NULL,NULL);
    }
    db close
  } {};







>







 







>







737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
...
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
    execsql {
      CREATE TABLE t1(a);
    }
    db close
  } {}
  do_test capi3-8.2 {
    sqlite3 db test.db
    sqlite3_db_config db DEFENSIVE 0
    execsql {
      PRAGMA writable_schema=ON;
      INSERT INTO sqlite_master VALUES(NULL,NULL,NULL,NULL,NULL);
    }
    db close
  } {}
  do_test capi3-8.3 {
................................................................................
  } {1 {malformed database schema (?)}}
  do_test capi3-8.4 {
    # Build a 5-field row record. The first field is a string 'table', and
    # subsequent fields are all NULL.
    db close
    forcedelete test.db test.db-journal
    sqlite3 db test.db
    sqlite3_db_config db DEFENSIVE 0
    execsql {
      CREATE TABLE t1(a);
      PRAGMA writable_schema=ON;
      INSERT INTO sqlite_master VALUES('table',NULL,NULL,NULL,NULL);
    }
    db close
  } {};

Changes to test/capi3c.test.

682
683
684
685
686
687
688

689
690
691
692
693
694
695
...
700
701
702
703
704
705
706

707
708
709
710
711
712
713
    execsql {
      CREATE TABLE t1(a);
    }
    db close
  } {}
  do_test capi3c-8.2 {
    sqlite3 db test.db

    execsql {
      PRAGMA writable_schema=ON;
      INSERT INTO sqlite_master VALUES(NULL,NULL,NULL,NULL,NULL);
    }
    db close
  } {}
  do_test capi3c-8.3 {
................................................................................
  } {1 {malformed database schema (?)}}
  do_test capi3c-8.4 {
    # Build a 5-field row record. The first field is a string 'table', and
    # subsequent fields are all NULL.
    db close
    forcedelete test.db test.db-journal
    sqlite3 db test.db

    execsql {
      CREATE TABLE t1(a);
      PRAGMA writable_schema=ON;
      INSERT INTO sqlite_master VALUES('table',NULL,NULL,NULL,NULL);
    }
    db close
  } {};







>







 







>







682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
...
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
    execsql {
      CREATE TABLE t1(a);
    }
    db close
  } {}
  do_test capi3c-8.2 {
    sqlite3 db test.db
    sqlite3_db_config db DEFENSIVE 0
    execsql {
      PRAGMA writable_schema=ON;
      INSERT INTO sqlite_master VALUES(NULL,NULL,NULL,NULL,NULL);
    }
    db close
  } {}
  do_test capi3c-8.3 {
................................................................................
  } {1 {malformed database schema (?)}}
  do_test capi3c-8.4 {
    # Build a 5-field row record. The first field is a string 'table', and
    # subsequent fields are all NULL.
    db close
    forcedelete test.db test.db-journal
    sqlite3 db test.db
    sqlite3_db_config db DEFENSIVE 0
    execsql {
      CREATE TABLE t1(a);
      PRAGMA writable_schema=ON;
      INSERT INTO sqlite_master VALUES('table',NULL,NULL,NULL,NULL);
    }
    db close
  } {};

Changes to test/corrupt.test.

128
129
130
131
132
133
134

135
136
137
138
139
140
141
  sqlite3 db test.db
  list
} {}
do_test corrupt-3.2 {
  set t1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1i1'}]
  set t1i1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1'}]
  set cookie [expr [execsql {PRAGMA schema_version}] + 1]

  execsql "
    PRAGMA writable_schema = 1;
    UPDATE sqlite_master SET rootpage = $t1_r WHERE name = 't1';
    UPDATE sqlite_master SET rootpage = $t1i1_r WHERE name = 't1i1';
    PRAGMA writable_schema = 0;
    PRAGMA schema_version = $cookie;
  "







>







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  sqlite3 db test.db
  list
} {}
do_test corrupt-3.2 {
  set t1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1i1'}]
  set t1i1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1'}]
  set cookie [expr [execsql {PRAGMA schema_version}] + 1]
  sqlite3_db_config db DEFENSIVE 0
  execsql "
    PRAGMA writable_schema = 1;
    UPDATE sqlite_master SET rootpage = $t1_r WHERE name = 't1';
    UPDATE sqlite_master SET rootpage = $t1i1_r WHERE name = 't1i1';
    PRAGMA writable_schema = 0;
    PRAGMA schema_version = $cookie;
  "

Changes to test/corrupt2.test.

129
130
131
132
133
134
135

136
137
138
139
140
141
142
...
261
262
263
264
265
266
267

268
269
270
271
272
273
274
do_test corrupt2-2.1 {

  forcedelete corrupt.db
  forcedelete corrupt.db-journal
  forcecopy test.db corrupt.db

  sqlite3 db2 corrupt.db 

  execsql "
    $::presql
    CREATE INDEX a1 ON abc(a);
    CREATE INDEX a2 ON abc(b);
    PRAGMA writable_schema = 1;
    UPDATE sqlite_master 
      SET name = 'a3', sql = 'CREATE INDEX a3' || substr(sql, 16, 10000)
................................................................................
  array set A $args

  catch {db close}
  forcedelete corrupt.db
  forcedelete corrupt.db-journal

  sqlite3 db corrupt.db 

  db eval $::presql
  eval $A(-tclprep)
  db eval $A(-sqlprep)
  db close

  eval $A(-corrupt)








>







 







>







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
do_test corrupt2-2.1 {

  forcedelete corrupt.db
  forcedelete corrupt.db-journal
  forcecopy test.db corrupt.db

  sqlite3 db2 corrupt.db 
  sqlite3_db_config db2 DEFENSIVE 0
  execsql "
    $::presql
    CREATE INDEX a1 ON abc(a);
    CREATE INDEX a2 ON abc(b);
    PRAGMA writable_schema = 1;
    UPDATE sqlite_master 
      SET name = 'a3', sql = 'CREATE INDEX a3' || substr(sql, 16, 10000)
................................................................................
  array set A $args

  catch {db close}
  forcedelete corrupt.db
  forcedelete corrupt.db-journal

  sqlite3 db corrupt.db 
  sqlite3_db_config db DEFENSIVE 0
  db eval $::presql
  eval $A(-tclprep)
  db eval $A(-sqlprep)
  db close

  eval $A(-corrupt)

Changes to test/corrupt5.test.

29
30
31
32
33
34
35

36
37
38
39
40
41
42
  finish_test
  return
}

# Create a database with a freelist containing at least two pages.
#
do_test corrupt5-1.1 {

  execsql {
    CREATE TABLE t1(a,b,c);
    CREATE INDEX i1 ON t1(a,b);
    PRAGMA writable_schema=ON;
    UPDATE sqlite_master SET name=NULL, sql=NULL WHERE name='i1';
  }
  db close







>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  finish_test
  return
}

# Create a database with a freelist containing at least two pages.
#
do_test corrupt5-1.1 {
  sqlite3_db_config db DEFENSIVE 0
  execsql {
    CREATE TABLE t1(a,b,c);
    CREATE INDEX i1 ON t1(a,b);
    PRAGMA writable_schema=ON;
    UPDATE sqlite_master SET name=NULL, sql=NULL WHERE name='i1';
  }
  db close

Changes to test/corruptI.test.

218
219
220
221
222
223
224

225
226
227
228
229
230
231
  PRAGMA auto_vacuum=0;
  CREATE TABLE t1(x PRIMARY KEY, y);
  INSERT INTO t1 VALUES('a', 'A');
  INSERT INTO t1 VALUES('b', 'A');
  INSERT INTO t1 VALUES('c', 'A');
  SELECT name FROM sqlite_master;
} {t1 sqlite_autoindex_t1_1}

do_execsql_test 7.1 {
  PRAGMA writable_schema = 1;
  DELETE FROM sqlite_master WHERE name = 'sqlite_autoindex_t1_1';
}
do_test 7.2 {
  db close
  sqlite3 db test.db







>







218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  PRAGMA auto_vacuum=0;
  CREATE TABLE t1(x PRIMARY KEY, y);
  INSERT INTO t1 VALUES('a', 'A');
  INSERT INTO t1 VALUES('b', 'A');
  INSERT INTO t1 VALUES('c', 'A');
  SELECT name FROM sqlite_master;
} {t1 sqlite_autoindex_t1_1}
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 7.1 {
  PRAGMA writable_schema = 1;
  DELETE FROM sqlite_master WHERE name = 'sqlite_autoindex_t1_1';
}
do_test 7.2 {
  db close
  sqlite3 db test.db

Changes to test/corruptK.test.

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
    PRAGMA page_size=1024;
    CREATE TABLE t1(a, b, c);
    CREATE TABLE t2(a, b, c);
    CREATE TABLE t3(a, b, c);
    CREATE TABLE t4(a, b, c);
    CREATE TABLE t5(a, b, c);
  }
  
  do_execsql_test 3.2 {
    UPDATE sqlite_dbpage SET data = hex2blob('
   000: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
   010: 04 00 01 01 20 40 20 20 00 00 3e d9 00 00 00 06 .... @  ..>.....
   020: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
   030: 0f 00 00 00 00 00 00 00 00 00 00 01 00 00 83 00 ................
   040: 00 00 00 00 00 00 00 00 00 00 00 00 00 38 00 00 .............8..







|







139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
    PRAGMA page_size=1024;
    CREATE TABLE t1(a, b, c);
    CREATE TABLE t2(a, b, c);
    CREATE TABLE t3(a, b, c);
    CREATE TABLE t4(a, b, c);
    CREATE TABLE t5(a, b, c);
  }
  sqlite3_db_config db DEFENSIVE 0
  do_execsql_test 3.2 {
    UPDATE sqlite_dbpage SET data = hex2blob('
   000: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
   010: 04 00 01 01 20 40 20 20 00 00 3e d9 00 00 00 06 .... @  ..>.....
   020: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
   030: 0f 00 00 00 00 00 00 00 00 00 00 01 00 00 83 00 ................
   040: 00 00 00 00 00 00 00 00 00 00 00 00 00 38 00 00 .............8..

Changes to test/countofview.test.

37
38
39
40
41
42
43
44
do_execsql_test 1.3 {
  select count(*) from (
    select c from t2 union all select f from t3
  )
} {3}

finish_test








<
37
38
39
40
41
42
43

do_execsql_test 1.3 {
  select count(*) from (
    select c from t2 union all select f from t3
  )
} {3}

finish_test

Changes to test/dbpage.test.

17
18
19
20
21
22
23

24
25
26
27
28
29
30
set testprefix dbpage

ifcapable !vtab||!compound {
  finish_test
  return
}


do_test 100 {
  execsql {
    PRAGMA auto_vacuum=0;
    PRAGMA page_size=4096;
    PRAGMA journal_mode=WAL;
  }
  execsql { 







>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
set testprefix dbpage

ifcapable !vtab||!compound {
  finish_test
  return
}

sqlite3_db_config db DEFENSIVE 0
do_test 100 {
  execsql {
    PRAGMA auto_vacuum=0;
    PRAGMA page_size=4096;
    PRAGMA journal_mode=WAL;
  }
  execsql { 

Changes to test/default.test.

102
103
104
105
106
107
108

109
110
111
112
113
114
115
# Do now allow bound parameters in new DEFAULT values. 
# Silently convert bound parameters to NULL in DEFAULT causes
# in the sqlite_master table, for backwards compatibility.
#
db close
forcedelete test.db
sqlite3 db test.db

do_execsql_test default-4.0 {
  CREATE TABLE t1(a TEXT, b TEXT DEFAULT(99));
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE TABLE t1(a TEXT, b TEXT DEFAULT(:xyz))';
} {}
db close 
sqlite3 db test.db







>







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# Do now allow bound parameters in new DEFAULT values. 
# Silently convert bound parameters to NULL in DEFAULT causes
# in the sqlite_master table, for backwards compatibility.
#
db close
forcedelete test.db
sqlite3 db test.db
sqlite3_db_config db DEFENSIVE 0
do_execsql_test default-4.0 {
  CREATE TABLE t1(a TEXT, b TEXT DEFAULT(99));
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE TABLE t1(a TEXT, b TEXT DEFAULT(:xyz))';
} {}
db close 
sqlite3 db test.db

Changes to test/e_fts3.test.

673
674
675
676
677
678
679

680
681
682
683
684
685
686
#
set DO_MALLOC_TEST 0
ddl_test   10.1.1 { CREATE VIRTUAL TABLE ta USING fts3 }
write_test 10.1.2 ta_content { 
  INSERT INTO ta VALUES('During a summer vacation in 1790') }
write_test 10.1.3 ta_content {
  INSERT INTO ta VALUES('Wordsworth went on a walking tour') }

write_test 10.1.4 ta_content { DELETE FROM ta_content WHERE rowid = 2 }
read_test  10.1.5 {
  SELECT * FROM ta WHERE ta MATCH 'summer'
} {{During a summer vacation in 1790}}
error_test 10.1.6 {
  SELECT * FROM ta WHERE ta MATCH 'walking'
} {database disk image is malformed}







>







673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
#
set DO_MALLOC_TEST 0
ddl_test   10.1.1 { CREATE VIRTUAL TABLE ta USING fts3 }
write_test 10.1.2 ta_content { 
  INSERT INTO ta VALUES('During a summer vacation in 1790') }
write_test 10.1.3 ta_content {
  INSERT INTO ta VALUES('Wordsworth went on a walking tour') }
sqlite3_db_config db DEFENSIVE 0
write_test 10.1.4 ta_content { DELETE FROM ta_content WHERE rowid = 2 }
read_test  10.1.5 {
  SELECT * FROM ta WHERE ta MATCH 'summer'
} {{During a summer vacation in 1790}}
error_test 10.1.6 {
  SELECT * FROM ta WHERE ta MATCH 'walking'
} {database disk image is malformed}

Changes to test/e_reindex.test.

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

# EVIDENCE-OF: R-52173-44778 The REINDEX command is used to delete and
# recreate indices from scratch.
#
#    Test this by corrupting some database indexes, running REINDEX, and
#    observing that the corruption is gone.
#

do_execsql_test e_reindex-1.1 {
  INSERT INTO t1 VALUES(1, 2);
  INSERT INTO t1 VALUES(3, 4);
  INSERT INTO t1 VALUES(5, 6);

  CREATE TABLE saved(a,b,c,d,e);
  INSERT INTO saved SELECT * FROM sqlite_master WHERE type = 'index';
  PRAGMA writable_schema = 1;
  DELETE FROM sqlite_master WHERE type = 'index';
} {}

db close
sqlite3 db test.db

do_execsql_test e_reindex-1.2 {
  DELETE FROM t1 WHERE a = 3;
  INSERT INTO t1 VALUES(7, 8);
  INSERT INTO t1 VALUES(9, 10);
  PRAGMA writable_schema = 1;
  INSERT INTO sqlite_master SELECT * FROM saved;
  DROP TABLE saved;







>













>







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

# EVIDENCE-OF: R-52173-44778 The REINDEX command is used to delete and
# recreate indices from scratch.
#
#    Test this by corrupting some database indexes, running REINDEX, and
#    observing that the corruption is gone.
#
sqlite3_db_config db DEFENSIVE 0
do_execsql_test e_reindex-1.1 {
  INSERT INTO t1 VALUES(1, 2);
  INSERT INTO t1 VALUES(3, 4);
  INSERT INTO t1 VALUES(5, 6);

  CREATE TABLE saved(a,b,c,d,e);
  INSERT INTO saved SELECT * FROM sqlite_master WHERE type = 'index';
  PRAGMA writable_schema = 1;
  DELETE FROM sqlite_master WHERE type = 'index';
} {}

db close
sqlite3 db test.db
sqlite3_db_config db DEFENSIVE 0
do_execsql_test e_reindex-1.2 {
  DELETE FROM t1 WHERE a = 3;
  INSERT INTO t1 VALUES(7, 8);
  INSERT INTO t1 VALUES(9, 10);
  PRAGMA writable_schema = 1;
  INSERT INTO sqlite_master SELECT * FROM saved;
  DROP TABLE saved;

Changes to test/fts3auto.test.

130
131
132
133
134
135
136

137
138
139
140
141
142
143

  return [expr $nRow*$pgsz]
}

#    fts3_zero_long_segments TABLE ?LIMIT?
#
proc fts3_zero_long_segments {tbl limit} {

  execsql " 
    UPDATE ${tbl}_segments 
    SET block = zeroblob(length(block)) 
    WHERE length(block)>$limit
  "
  return [db changes]
}







>







130
131
132
133
134
135
136
137
138
139
140
141
142
143
144

  return [expr $nRow*$pgsz]
}

#    fts3_zero_long_segments TABLE ?LIMIT?
#
proc fts3_zero_long_segments {tbl limit} {
  sqlite3_db_config db DEFENSIVE 0
  execsql " 
    UPDATE ${tbl}_segments 
    SET block = zeroblob(length(block)) 
    WHERE length(block)>$limit
  "
  return [db changes]
}

Changes to test/fts3corrupt.test.

19
20
21
22
23
24
25

26
27
28
29
30
31
32
set ::testprefix fts3corrupt


# Test that a doclist with a length field that indicates that the doclist
# extends past the end of the node on which it resides is correctly identified
# as database corruption.
#

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING fts3;
  INSERT INTO t1 VALUES('hello');
} {}
do_test fts3corrupt-1.1 {
  set blob [db one {SELECT root from t1_segdir}]
  set blob [binary format a7ca* $blob 24 [string range $blob 8 end]]







>







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
set ::testprefix fts3corrupt


# Test that a doclist with a length field that indicates that the doclist
# extends past the end of the node on which it resides is correctly identified
# as database corruption.
#
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING fts3;
  INSERT INTO t1 VALUES('hello');
} {}
do_test fts3corrupt-1.1 {
  set blob [db one {SELECT root from t1_segdir}]
  set blob [binary format a7ca* $blob 24 [string range $blob 8 end]]

Changes to test/fts3corrupt2.test.

45
46
47
48
49
50
51

52
53
54
55
56
57
58
   "ayjafsraz addjj agsj asejtziqws acatvhegu aoxdjqblsvv aekdmmbs aaobe"
   "abjjvzubkwt alczv ati awz auyxgcxeb aymjoym anqoukprtyt atwfhpmbooh"
   "ajfqz aethlgir aclcx aowlyvetby aproqm afjlqtkv anebfy akzrcpfrrvw"
   "aoledfotm aiwlfm aeejlaej anz abgbvk aktfn aayoh anpywgdvgz"
   "acvmldguld asdvz aqb aeomsyzyu aggylhprbdz asrfkwz auipybpsn agsnszzfb"
}


do_test fts3corrupt2-1.0 {
  execsql BEGIN
  execsql { CREATE VIRTUAL TABLE t2 USING FTS3(a, b); }
  execsql { INSERT INTO t2(t2) VALUES('nodesize=32') }
  foreach d $data {
    execsql { INSERT INTO t2 VALUES($d, $d) }
  }







>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
   "ayjafsraz addjj agsj asejtziqws acatvhegu aoxdjqblsvv aekdmmbs aaobe"
   "abjjvzubkwt alczv ati awz auyxgcxeb aymjoym anqoukprtyt atwfhpmbooh"
   "ajfqz aethlgir aclcx aowlyvetby aproqm afjlqtkv anebfy akzrcpfrrvw"
   "aoledfotm aiwlfm aeejlaej anz abgbvk aktfn aayoh anpywgdvgz"
   "acvmldguld asdvz aqb aeomsyzyu aggylhprbdz asrfkwz auipybpsn agsnszzfb"
}

sqlite3_db_config db DEFENSIVE 0
do_test fts3corrupt2-1.0 {
  execsql BEGIN
  execsql { CREATE VIRTUAL TABLE t2 USING FTS3(a, b); }
  execsql { INSERT INTO t2(t2) VALUES('nodesize=32') }
  foreach d $data {
    execsql { INSERT INTO t2 VALUES($d, $d) }
  }

Changes to test/fts3corrupt3.test.

29
30
31
32
33
34
35

36
37
38
39
40
41
42
    INSERT INTO t1 VALUES('one');
    INSERT INTO t1 VALUES('one');
  COMMIT;
}
do_execsql_test 1.1 {
  SELECT quote(root) from t1_segdir;
} {X'00036F6E6509010200010200010200'}

do_execsql_test 1.2 {
  UPDATE t1_segdir SET root = X'00036F6E650EFFFFFFFFFFFFFFFFFFFFFFFF0200';
}
do_catchsql_test 1.3 {
  SELECT rowid FROM t1 WHERE t1 MATCH 'one'
} {0 -1}








>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
    INSERT INTO t1 VALUES('one');
    INSERT INTO t1 VALUES('one');
  COMMIT;
}
do_execsql_test 1.1 {
  SELECT quote(root) from t1_segdir;
} {X'00036F6E6509010200010200010200'}
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 1.2 {
  UPDATE t1_segdir SET root = X'00036F6E650EFFFFFFFFFFFFFFFFFFFFFFFF0200';
}
do_catchsql_test 1.3 {
  SELECT rowid FROM t1 WHERE t1 MATCH 'one'
} {0 -1}

Changes to test/fts3corrupt4.test.

36
37
38
39
40
41
42

43
44
45
46
47
48
49
..
79
80
81
82
83
84
85

86
87
88
89
90
91
92
...
129
130
131
132
133
134
135

136
137
138
139
140
141
142
143
144
145
146
147
proc blob {a} { binary decode hex $a }
db func blob blob

do_execsql_test 1.1 {
  SELECT quote(root) FROM ft_segdir;
} {X'0005616261636B03010200030266740302020003046E646F6E03030200'}


do_execsql_test 1.2 {
  UPDATE ft_segdir SET root = blob(
    '0005616261636B03010200 FFFFFFFF0702 66740302020003046E646F6E03030200'
  );
}

do_catchsql_test 1.3 {
................................................................................
} {12 3}

do_execsql_test 2.2 {
  SELECT quote(block) FROM ft_segments WHERE blockid=2
} {X'00056162633130031F0200'}

db func blob blob

do_execsql_test 2.3.1 {
  UPDATE ft_segments SET block = 
    blob('00056162633130031F0200 FFFFFFFF07FF55 66740302020003046E646F6E03030200')
    WHERE blockid=2;
} {}
do_catchsql_test 2.3.2 {
  INSERT INTO ft(ft) VALUES('merge=1,4');
................................................................................
} {1 5}

do_execsql_test 3.1 {
  SELECT quote(root) FROM ft_segdir
} {X'0101056162633132040136030132030136'}

db func blob blob

do_execsql_test 3.2 {
  UPDATE ft_segdir 
  SET root = blob('0101056162633132FFFFFFFF070236030132030136');
}

do_catchsql_test 3.1 {
  SELECT * FROM ft WHERE ft MATCH 'abc20'
} {1 {database disk image is malformed}}

finish_test









>







 







>







 







>










<
<
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148


proc blob {a} { binary decode hex $a }
db func blob blob

do_execsql_test 1.1 {
  SELECT quote(root) FROM ft_segdir;
} {X'0005616261636B03010200030266740302020003046E646F6E03030200'}

sqlite3_db_config db DEFENSIVE 0
do_execsql_test 1.2 {
  UPDATE ft_segdir SET root = blob(
    '0005616261636B03010200 FFFFFFFF0702 66740302020003046E646F6E03030200'
  );
}

do_catchsql_test 1.3 {
................................................................................
} {12 3}

do_execsql_test 2.2 {
  SELECT quote(block) FROM ft_segments WHERE blockid=2
} {X'00056162633130031F0200'}

db func blob blob
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 2.3.1 {
  UPDATE ft_segments SET block = 
    blob('00056162633130031F0200 FFFFFFFF07FF55 66740302020003046E646F6E03030200')
    WHERE blockid=2;
} {}
do_catchsql_test 2.3.2 {
  INSERT INTO ft(ft) VALUES('merge=1,4');
................................................................................
} {1 5}

do_execsql_test 3.1 {
  SELECT quote(root) FROM ft_segdir
} {X'0101056162633132040136030132030136'}

db func blob blob
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 3.2 {
  UPDATE ft_segdir 
  SET root = blob('0101056162633132FFFFFFFF070236030132030136');
}

do_catchsql_test 3.1 {
  SELECT * FROM ft WHERE ft MATCH 'abc20'
} {1 {database disk image is malformed}}

finish_test


Changes to test/fts3cov.test.

85
86
87
88
89
90
91

92
93
94
95
96
97
98
...
401
402
403
404
405
406
407

408
409
410
411
412
413
414
  execsql {
    INSERT INTO t1(t1) VALUES('optimize');
    SELECT substr(hex(root), 1, 2) FROM t1_segdir;
  }
} {03}

# Test the "missing entry" case:

do_test fts3cov-2.2 {
  set root [db one {SELECT root FROM t1_segdir}]
  read_fts3varint [string range $root 1 end] left_child
  execsql { DELETE FROM t1_segments WHERE blockid = $left_child }
} {}
do_error_test fts3cov-2.3 {
  SELECT * FROM t1 WHERE t1 MATCH 'c*'
................................................................................
}
do_execsql_test 15.1 {
  SELECT rowid FROM t15 WHERE t15 MATCH '"abc* def2"'
} {1 2}

# Test a corruption case.
#

do_execsql_test 16.1 {
  CREATE VIRTUAL TABLE t16 USING fts4;
  INSERT INTO t16 VALUES('theoretical work to examine the relationship');
  INSERT INTO t16 VALUES('solution of our problems on the invisible');
  DELETE FROM t16_content WHERE rowid = 2;
}
do_catchsql_test 16.2 {







>







 







>







85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
...
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  execsql {
    INSERT INTO t1(t1) VALUES('optimize');
    SELECT substr(hex(root), 1, 2) FROM t1_segdir;
  }
} {03}

# Test the "missing entry" case:
sqlite3_db_config db DEFENSIVE 0
do_test fts3cov-2.2 {
  set root [db one {SELECT root FROM t1_segdir}]
  read_fts3varint [string range $root 1 end] left_child
  execsql { DELETE FROM t1_segments WHERE blockid = $left_child }
} {}
do_error_test fts3cov-2.3 {
  SELECT * FROM t1 WHERE t1 MATCH 'c*'
................................................................................
}
do_execsql_test 15.1 {
  SELECT rowid FROM t15 WHERE t15 MATCH '"abc* def2"'
} {1 2}

# Test a corruption case.
#
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 16.1 {
  CREATE VIRTUAL TABLE t16 USING fts4;
  INSERT INTO t16 VALUES('theoretical work to examine the relationship');
  INSERT INTO t16 VALUES('solution of our problems on the invisible');
  DELETE FROM t16_content WHERE rowid = 2;
}
do_catchsql_test 16.2 {

Changes to test/fts3d.test.

292
293
294
295
296
297
298

299
300
301
302
303
304
305
  execsql {
    SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
    SELECT level, idx FROM t1_segdir ORDER BY level, idx;
  }
} {{Index already optimal} 1 0}

# Even if we move things around, still does nothing.

do_test fts3d-5.1 {
  execsql {
    UPDATE t1_segdir SET level = 2 WHERE level = 1 AND idx = 0;
    SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
    SELECT level, idx FROM t1_segdir ORDER BY level, idx;
  }
} {{Index already optimal} 2 0}







>







292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
  execsql {
    SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
    SELECT level, idx FROM t1_segdir ORDER BY level, idx;
  }
} {{Index already optimal} 1 0}

# Even if we move things around, still does nothing.
sqlite3_db_config db DEFENSIVE 0
do_test fts3d-5.1 {
  execsql {
    UPDATE t1_segdir SET level = 2 WHERE level = 1 AND idx = 0;
    SELECT OPTIMIZE(t1) FROM t1 LIMIT 1;
    SELECT level, idx FROM t1_segdir ORDER BY level, idx;
  }
} {{Index already optimal} 2 0}

Changes to test/fts3defer.test.

55
56
57
58
59
60
61

62
63
64
65
66
67
68
...
221
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
  4  {SELECT snippet(t1) FROM t1 WHERE t1 MATCH '"a longer phrase"'}  
     {"an instance of <b>a</b> <b>longer</b> <b>phrase</b>"}
  5  {SELECT rowid FROM t1 WHERE t1 MATCH 'a dog'}                   {1}
}

do_select_tests 1.2 $tests


do_execsql_test 1.3 {
  SELECT count(*) FROM t1_segments WHERE length(block)>10000;
  UPDATE t1_segments 
    SET block = zeroblob(length(block)) 
    WHERE length(block)>10000;
} {1}

................................................................................
    foreach doc $data { execsql { INSERT INTO t1 VALUES($doc) } }
  }
  3 {
    set dmt_modes {0 1 2}
    execsql { CREATE VIRTUAL TABLE t1 USING FTS4 }
    foreach doc $data { execsql { INSERT INTO t1 VALUES($doc) } }
    add_empty_records 1000

    execsql $zero_long_doclists
  }
  4 {
    set dmt_modes 0
    execsql { CREATE VIRTUAL TABLE t1 USING FTS4 }
    foreach doc $data { execsql { INSERT INTO t1 VALUES($doc) } }
    add_empty_records 1000
    execsql "INSERT INTO t1(t1) VALUES('optimize')"

    execsql $zero_long_doclists
  }
  5 {
    set dmt_modes 0
    execsql { CREATE VIRTUAL TABLE t1 USING FTS4(matchinfo=fts3) }
    foreach doc $data { execsql { INSERT INTO t1 VALUES($doc) } }
    add_empty_records 1000

    execsql $zero_long_doclists
  }
} {

  execsql { DROP TABLE IF EXISTS t1 }
  eval $setup
  set ::testprefix fts3defer-2.$tn







>







 







>








>







>







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
...
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
  4  {SELECT snippet(t1) FROM t1 WHERE t1 MATCH '"a longer phrase"'}  
     {"an instance of <b>a</b> <b>longer</b> <b>phrase</b>"}
  5  {SELECT rowid FROM t1 WHERE t1 MATCH 'a dog'}                   {1}
}

do_select_tests 1.2 $tests

sqlite3_db_config db DEFENSIVE 0
do_execsql_test 1.3 {
  SELECT count(*) FROM t1_segments WHERE length(block)>10000;
  UPDATE t1_segments 
    SET block = zeroblob(length(block)) 
    WHERE length(block)>10000;
} {1}

................................................................................
    foreach doc $data { execsql { INSERT INTO t1 VALUES($doc) } }
  }
  3 {
    set dmt_modes {0 1 2}
    execsql { CREATE VIRTUAL TABLE t1 USING FTS4 }
    foreach doc $data { execsql { INSERT INTO t1 VALUES($doc) } }
    add_empty_records 1000
    sqlite3_db_config db DEFENSIVE 0
    execsql $zero_long_doclists
  }
  4 {
    set dmt_modes 0
    execsql { CREATE VIRTUAL TABLE t1 USING FTS4 }
    foreach doc $data { execsql { INSERT INTO t1 VALUES($doc) } }
    add_empty_records 1000
    execsql "INSERT INTO t1(t1) VALUES('optimize')"
    sqlite3_db_config db DEFENSIVE 0
    execsql $zero_long_doclists
  }
  5 {
    set dmt_modes 0
    execsql { CREATE VIRTUAL TABLE t1 USING FTS4(matchinfo=fts3) }
    foreach doc $data { execsql { INSERT INTO t1 VALUES($doc) } }
    add_empty_records 1000
    sqlite3_db_config db DEFENSIVE 0
    execsql $zero_long_doclists
  }
} {

  execsql { DROP TABLE IF EXISTS t1 }
  eval $setup
  set ::testprefix fts3defer-2.$tn

Changes to test/fts3defer2.test.

42
43
44
45
46
47
48

49
50
51
52
53
54
55
..
94
95
96
97
98
99
100

101
102
103
104
105
106
107
...
148
149
150
151
152
153
154

155
156
157
158
159
160
161
162
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1(t1) VALUES('optimize');
}

do_execsql_test 1.1.4 {
  SELECT count(*) FROM t1_segments WHERE length(block)>10000;
  UPDATE t1_segments SET block = zeroblob(length(block)) WHERE length(block)>10000;
} {2}

do_execsql_test 1.2.0 {
  SELECT content FROM t1 WHERE t1 MATCH 'f (e a)';
................................................................................
foreach {tn sql} {
  1 {}
  2 { INSERT INTO t2(t2) VALUES('optimize') }
  3 { UPDATE t2_segments SET block = zeroblob(length(block)) 
      WHERE length(block)>10000;
  }
} {

  execsql $sql

  do_execsql_test 2.2.$tn.1 {
    SELECT mit(matchinfo(t2, 'pcxnal')) FROM t2 WHERE t2 MATCH 'a b';
  } [list                                          \
    [list 2 1  1 54 54  1 3 3  54 372 8]        \
    [list 2 1  1 54 54  1 3 3  54 372 7]        \
................................................................................
foreach {tn sql} {
  1 {}
  2 { INSERT INTO t3(t3) VALUES('optimize') }
  3 { UPDATE t3_segments SET block = zeroblob(length(block)) 
      WHERE length(block)>10000;
  }
} {

  execsql $sql
  do_execsql_test 2.4.$tn {
    SELECT docid, mit(matchinfo(t3, 'pcxnal')) FROM t3 WHERE t3 MATCH '"a b c"';
  } {1 {1 1 1 4 4 11 912 6} 3 {1 1 1 4 4 11 912 6}}
}


finish_test







>







 







>







 







>








42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
..
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1(t1) VALUES('optimize');
}
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 1.1.4 {
  SELECT count(*) FROM t1_segments WHERE length(block)>10000;
  UPDATE t1_segments SET block = zeroblob(length(block)) WHERE length(block)>10000;
} {2}

do_execsql_test 1.2.0 {
  SELECT content FROM t1 WHERE t1 MATCH 'f (e a)';
................................................................................
foreach {tn sql} {
  1 {}
  2 { INSERT INTO t2(t2) VALUES('optimize') }
  3 { UPDATE t2_segments SET block = zeroblob(length(block)) 
      WHERE length(block)>10000;
  }
} {
  sqlite3_db_config db DEFENSIVE 0
  execsql $sql

  do_execsql_test 2.2.$tn.1 {
    SELECT mit(matchinfo(t2, 'pcxnal')) FROM t2 WHERE t2 MATCH 'a b';
  } [list                                          \
    [list 2 1  1 54 54  1 3 3  54 372 8]        \
    [list 2 1  1 54 54  1 3 3  54 372 7]        \
................................................................................
foreach {tn sql} {
  1 {}
  2 { INSERT INTO t3(t3) VALUES('optimize') }
  3 { UPDATE t3_segments SET block = zeroblob(length(block)) 
      WHERE length(block)>10000;
  }
} {
  sqlite3_db_config db DEFENSIVE 0
  execsql $sql
  do_execsql_test 2.4.$tn {
    SELECT docid, mit(matchinfo(t3, 'pcxnal')) FROM t3 WHERE t3 MATCH '"a b c"';
  } {1 {1 1 1 4 4 11 912 6} 3 {1 1 1 4 4 11 912 6}}
}


finish_test

Changes to test/fts3matchinfo.test.

274
275
276
277
278
279
280

281
282
283
284
285
286
287
...
335
336
337
338
339
340
341

342
343
344
345
346
347
348
...
388
389
390
391
392
393
394

395
396
397
398
399
400
401
do_matchinfo_test 4.3.4 t5 {t5 MATCH 'a a a'}       { s {3 1} }
do_matchinfo_test 4.3.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} }
do_matchinfo_test 4.3.6 t5 {t5 MATCH 'a OR b'}      { s {1 2 1 1} }

do_execsql_test 4.4.0.1 { INSERT INTO t5(t5) VALUES('optimize') }

ifcapable fts4_deferred {

  do_execsql_test 4.4.0.2 {
    UPDATE t5_segments 
    SET block = zeroblob(length(block)) 
    WHERE length(block)>10000;
  }
}

................................................................................
  CREATE VIRTUAL TABLE t9 USING fts4;
  INSERT INTO t9 VALUES(
    'this record is used to try to dectect corruption'
  );
  SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to';
} {{0 0 20 2 0 0 27 2}}


do_catchsql_test 6.2 {
  UPDATE t9_content SET c0content = 'this record is used to'; 
  SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to';
} {1 {database disk image is malformed}}

#-------------------------------------------------------------------------
# Test the outcome of matchinfo() when used within a query that does not
................................................................................
  execsql { INSERT INTO t11(t11) VALUES('optimize') }
} {}
do_execsql_test 8.3 {
  SELECT mit(matchinfo(t11, 'nxa')) FROM t11 WHERE t11 MATCH 'a*'
} {{204 1 3 3 0} {204 1 3 3 0} {204 1 3 3 0}}

# Corruption related tests.

do_execsql_test  8.4.1.1 { UPDATE t11_stat SET value = X'0000'; }
do_catchsql_test 8.5.1.2 {
  SELECT mit(matchinfo(t11, 'nxa')) FROM t11 WHERE t11 MATCH 'a*'
} {1 {database disk image is malformed}}

do_execsql_test  8.4.2.1 { UPDATE t11_stat SET value = X'00'; }
do_catchsql_test 8.5.2.2 {







>







 







>







 







>







274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
do_matchinfo_test 4.3.4 t5 {t5 MATCH 'a a a'}       { s {3 1} }
do_matchinfo_test 4.3.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} }
do_matchinfo_test 4.3.6 t5 {t5 MATCH 'a OR b'}      { s {1 2 1 1} }

do_execsql_test 4.4.0.1 { INSERT INTO t5(t5) VALUES('optimize') }

ifcapable fts4_deferred {
  sqlite3_db_config db DEFENSIVE 0
  do_execsql_test 4.4.0.2 {
    UPDATE t5_segments 
    SET block = zeroblob(length(block)) 
    WHERE length(block)>10000;
  }
}

................................................................................
  CREATE VIRTUAL TABLE t9 USING fts4;
  INSERT INTO t9 VALUES(
    'this record is used to try to dectect corruption'
  );
  SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to';
} {{0 0 20 2 0 0 27 2}}

sqlite3_db_config db DEFENSIVE 0
do_catchsql_test 6.2 {
  UPDATE t9_content SET c0content = 'this record is used to'; 
  SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to';
} {1 {database disk image is malformed}}

#-------------------------------------------------------------------------
# Test the outcome of matchinfo() when used within a query that does not
................................................................................
  execsql { INSERT INTO t11(t11) VALUES('optimize') }
} {}
do_execsql_test 8.3 {
  SELECT mit(matchinfo(t11, 'nxa')) FROM t11 WHERE t11 MATCH 'a*'
} {{204 1 3 3 0} {204 1 3 3 0} {204 1 3 3 0}}

# Corruption related tests.
sqlite3_db_config db DEFENSIVE 0
do_execsql_test  8.4.1.1 { UPDATE t11_stat SET value = X'0000'; }
do_catchsql_test 8.5.1.2 {
  SELECT mit(matchinfo(t11, 'nxa')) FROM t11 WHERE t11 MATCH 'a*'
} {1 {database disk image is malformed}}

do_execsql_test  8.4.2.1 { UPDATE t11_stat SET value = X'00'; }
do_catchsql_test 8.5.2.2 {

Changes to test/fts3misc.test.

156
157
158
159
160
161
162

163
164
165
166
167
168
169
  }
  do_execsql_test 4.1 {
    SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"'
  } {8000}
  do_execsql_test 4.2 {
    SELECT quote(value) from t4_stat where id=0
  } {X'C03EC0B204C0A608'}

  do_execsql_test 4.3 {
    UPDATE t4_stat SET value = X'C03EC0B204C0A60800' WHERE id=0;
  }
  do_catchsql_test 4.4 {
    SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"'
  } {1 {database disk image is malformed}}
  do_execsql_test 4.5 {







>







156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  }
  do_execsql_test 4.1 {
    SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"'
  } {8000}
  do_execsql_test 4.2 {
    SELECT quote(value) from t4_stat where id=0
  } {X'C03EC0B204C0A608'}
  sqlite3_db_config db DEFENSIVE 0
  do_execsql_test 4.3 {
    UPDATE t4_stat SET value = X'C03EC0B204C0A60800' WHERE id=0;
  }
  do_catchsql_test 4.4 {
    SELECT count(*) FROM t4 WHERE t4 MATCH '"a b c" OR "c a b"'
  } {1 {database disk image is malformed}}
  do_execsql_test 4.5 {

Changes to test/fts3query.test.

163
164
165
166
167
168
169

170
171
172
173
174
175
176
  illegal first argument to %s
} {
  1 "SELECT matchinfo(content) FROM t2 WHERE t2 MATCH 'history'" matchinfo
  2 "SELECT offsets(content) FROM t2 WHERE t2 MATCH 'history'"   offsets
  3 "SELECT snippet(content) FROM t2 WHERE t2 MATCH 'history'"   snippet
  4 "SELECT optimize(content) FROM t2 WHERE t2 MATCH 'history'"  optimize
}

do_execsql_test 5.4.0 { UPDATE t2_content SET c0content = X'1234' }
do_select_tests 5.4 -errorformat {
  illegal first argument to %s
} {
  1 "SELECT matchinfo(content) FROM t2 WHERE t2 MATCH 'history'" matchinfo
  2 "SELECT offsets(content) FROM t2 WHERE t2 MATCH 'history'"   offsets
  3 "SELECT snippet(content) FROM t2 WHERE t2 MATCH 'history'"   snippet







>







163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  illegal first argument to %s
} {
  1 "SELECT matchinfo(content) FROM t2 WHERE t2 MATCH 'history'" matchinfo
  2 "SELECT offsets(content) FROM t2 WHERE t2 MATCH 'history'"   offsets
  3 "SELECT snippet(content) FROM t2 WHERE t2 MATCH 'history'"   snippet
  4 "SELECT optimize(content) FROM t2 WHERE t2 MATCH 'history'"  optimize
}
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 5.4.0 { UPDATE t2_content SET c0content = X'1234' }
do_select_tests 5.4 -errorformat {
  illegal first argument to %s
} {
  1 "SELECT matchinfo(content) FROM t2 WHERE t2 MATCH 'history'" matchinfo
  2 "SELECT offsets(content) FROM t2 WHERE t2 MATCH 'history'"   offsets
  3 "SELECT snippet(content) FROM t2 WHERE t2 MATCH 'history'"   snippet

Changes to test/fts3snippet.test.

180
181
182
183
184
185
186

187
188
189
190
191
192
193
  do_offsets_test $T.2.1 {twohundred} [list 1 0 $off 10]

  set off [string first "onehundred " $numbers]
  do_offsets_test $T.2.2 {onehundred} \
    [list 0 0 $off 10 1 0 $off 10] [list 0 0 $off 10]

  # Test a corruption case:

  execsql { UPDATE ft_content SET c1b = 'hello world' WHERE c1b = $numbers }
  do_error_test $T.2.3 {
    SELECT offsets(ft) FROM ft WHERE ft MATCH 'onehundred'
  } {database disk image is malformed}
  
  ##########################################################################
  # Test the snippet function.







>







180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  do_offsets_test $T.2.1 {twohundred} [list 1 0 $off 10]

  set off [string first "onehundred " $numbers]
  do_offsets_test $T.2.2 {onehundred} \
    [list 0 0 $off 10 1 0 $off 10] [list 0 0 $off 10]

  # Test a corruption case:
  sqlite3_db_config db DEFENSIVE 0
  execsql { UPDATE ft_content SET c1b = 'hello world' WHERE c1b = $numbers }
  do_error_test $T.2.3 {
    SELECT offsets(ft) FROM ft WHERE ft MATCH 'onehundred'
  } {database disk image is malformed}
  
  ##########################################################################
  # Test the snippet function.

Changes to test/fts4check.test.

62
63
64
65
66
67
68

69
70
71
72
73
74
75
..
96
97
98
99
100
101
102

103
104
105
106
107
108
109
...
141
142
143
144
145
146
147

148
149
150
151
152
153
154
...
159
160
161
162
163
164
165

166
167
168
169
170
171
172
...
193
194
195
196
197
198
199

200
201
202
203
204
205
206
207
208
209
210
211
212
  }
  3 {
    DELETE FROM t1_segdir WHERE level=0 AND idx=(
      SELECT max(idx) FROM t1_segdir WHERE level=0
    );
  }
} {

  do_execsql_test  1.2.1.$tn "BEGIN; $disruption"
  do_catchsql_test 1.2.2.$tn {
    INSERT INTO t1 (t1) VALUES('integrity-check')
  } {1 {database disk image is malformed}}
  do_execsql_test  1.2.3.$tn "ROLLBACK"
}

................................................................................
  }
  3 {
    DELETE FROM t2_segdir WHERE level=0 AND idx=(
      SELECT max(idx) FROM t2_segdir WHERE level=1024
    );
  }
} {

  do_execsql_test  2.2.1.$tn "BEGIN; $disruption"
  do_catchsql_test 2.2.2.$tn {
    INSERT INTO t2 (t2) VALUES('integrity-check')
  } {1 {database disk image is malformed}}
  do_execsql_test  2.2.3.$tn "ROLLBACK"
}

................................................................................
  }
  2 {
    UPDATE t3_content SET langid=langid+1 WHERE rowid = (
      SELECT max(rowid) FROM t3_content
    )
  }
} {

  do_execsql_test  3.2.1.$tn "BEGIN; $disruption"
  do_catchsql_test 3.2.2.$tn {
    INSERT INTO t3 (t3) VALUES('integrity-check')
  } {1 {database disk image is malformed}}
  do_execsql_test  3.2.3.$tn "ROLLBACK"
}

................................................................................
#
do_execsql_test 4.0 {
  CREATE VIRTUAL TABLE t4 USING fts4(a, b, c, notindexed=b);
  INSERT INTO t4 VALUES('text one', 'text two', 'text three');
  INSERT INTO t4(t4) VALUES('integrity-check');
}


do_execsql_test 4.1 {
  PRAGMA writable_schema = 1;
  UPDATE sqlite_master 
    SET sql = 'CREATE VIRTUAL TABLE t4 USING fts4(a, b, c)' 
    WHERE name = 't4';
}

................................................................................
  INSERT INTO t5 VALUES('and the stockmen tell the story of his ride');
}

do_execsql_test 5.1 {
  INSERT INTO t5(t5) VALUES('integrity-check');
} {}


do_catchsql_test 5.2 {
  INSERT INTO t5_content VALUES(5, 'his hardy mountain pony');
  INSERT INTO t5(t5) VALUES('integrity-check');
} {1 {database disk image is malformed}}

do_execsql_test 5.3 ROLLBACK

do_execsql_test 5.4 {
  CREATE VIRTUAL TABLE t5 USING fts4(a, prefix="1,2,3");
  INSERT INTO t5(t5) VALUES('integrity-check');
} {}

finish_test







>







 







>







 







>







 







>







 







>













62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
..
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
...
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  }
  3 {
    DELETE FROM t1_segdir WHERE level=0 AND idx=(
      SELECT max(idx) FROM t1_segdir WHERE level=0
    );
  }
} {
  sqlite3_db_config db DEFENSIVE 0
  do_execsql_test  1.2.1.$tn "BEGIN; $disruption"
  do_catchsql_test 1.2.2.$tn {
    INSERT INTO t1 (t1) VALUES('integrity-check')
  } {1 {database disk image is malformed}}
  do_execsql_test  1.2.3.$tn "ROLLBACK"
}

................................................................................
  }
  3 {
    DELETE FROM t2_segdir WHERE level=0 AND idx=(
      SELECT max(idx) FROM t2_segdir WHERE level=1024
    );
  }
} {
  sqlite3_db_config db DEFENSIVE 0
  do_execsql_test  2.2.1.$tn "BEGIN; $disruption"
  do_catchsql_test 2.2.2.$tn {
    INSERT INTO t2 (t2) VALUES('integrity-check')
  } {1 {database disk image is malformed}}
  do_execsql_test  2.2.3.$tn "ROLLBACK"
}

................................................................................
  }
  2 {
    UPDATE t3_content SET langid=langid+1 WHERE rowid = (
      SELECT max(rowid) FROM t3_content
    )
  }
} {
  sqlite3_db_config db DEFENSIVE 0
  do_execsql_test  3.2.1.$tn "BEGIN; $disruption"
  do_catchsql_test 3.2.2.$tn {
    INSERT INTO t3 (t3) VALUES('integrity-check')
  } {1 {database disk image is malformed}}
  do_execsql_test  3.2.3.$tn "ROLLBACK"
}

................................................................................
#
do_execsql_test 4.0 {
  CREATE VIRTUAL TABLE t4 USING fts4(a, b, c, notindexed=b);
  INSERT INTO t4 VALUES('text one', 'text two', 'text three');
  INSERT INTO t4(t4) VALUES('integrity-check');
}

sqlite3_db_config db DEFENSIVE 0
do_execsql_test 4.1 {
  PRAGMA writable_schema = 1;
  UPDATE sqlite_master 
    SET sql = 'CREATE VIRTUAL TABLE t4 USING fts4(a, b, c)' 
    WHERE name = 't4';
}

................................................................................
  INSERT INTO t5 VALUES('and the stockmen tell the story of his ride');
}

do_execsql_test 5.1 {
  INSERT INTO t5(t5) VALUES('integrity-check');
} {}

sqlite3_db_config db DEFENSIVE 0
do_catchsql_test 5.2 {
  INSERT INTO t5_content VALUES(5, 'his hardy mountain pony');
  INSERT INTO t5(t5) VALUES('integrity-check');
} {1 {database disk image is malformed}}

do_execsql_test 5.3 ROLLBACK

do_execsql_test 5.4 {
  CREATE VIRTUAL TABLE t5 USING fts4(a, prefix="1,2,3");
  INSERT INTO t5(t5) VALUES('integrity-check');
} {}

finish_test

Changes to test/fts4growth.test.

21
22
23
24
25
26
27

28
29
30
31
32
33
34
ifcapable !fts3 {
  finish_test
  return
}

source $testdir/genesis.tcl


do_execsql_test 1.1 { CREATE VIRTUAL TABLE x1 USING fts3; }

do_test 1.2 {
  foreach L {
    {"See here, young man," said Mulga Bill, "from Walgett to the sea,}
    {From Conroy's Gap to Castlereagh, there's none can ride like me.}
    {I'm good all round at everything as everybody knows,}







>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
ifcapable !fts3 {
  finish_test
  return
}

source $testdir/genesis.tcl

sqlite3_db_config db DEFENSIVE 0
do_execsql_test 1.1 { CREATE VIRTUAL TABLE x1 USING fts3; }

do_test 1.2 {
  foreach L {
    {"See here, young man," said Mulga Bill, "from Walgett to the sea,}
    {From Conroy's Gap to Castlereagh, there's none can ride like me.}
    {I'm good all round at everything as everybody knows,}

Changes to test/fts4merge.test.

152
153
154
155
156
157
158

159
160
161
162
163
164
165
    } $expect
  }
  
  do_execsql_test 4.4.1 {
    SELECT quote(value) FROM t4_stat WHERE rowid=1
  } {X'0006'}
  

  do_execsql_test 4.4.2 {
    DELETE FROM t4_stat WHERE rowid=1;
    INSERT INTO t4(t4) VALUES('merge=1,12');
    SELECT level, group_concat(idx, ' ') FROM t4_segdir GROUP BY level;
  } "0 {0 1 2 3 4 5}                     1 0"
  
  







>







152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    } $expect
  }
  
  do_execsql_test 4.4.1 {
    SELECT quote(value) FROM t4_stat WHERE rowid=1
  } {X'0006'}
  
  sqlite3_db_config db DEFENSIVE 0
  do_execsql_test 4.4.2 {
    DELETE FROM t4_stat WHERE rowid=1;
    INSERT INTO t4(t4) VALUES('merge=1,12');
    SELECT level, group_concat(idx, ' ') FROM t4_segdir GROUP BY level;
  } "0 {0 1 2 3 4 5}                     1 0"
  
  

Changes to test/fts4opt.test.

33
34
35
36
37
38
39

40
41
42
43
44
45
46
# Argument $db is an open database handle. $tbl is the name of an FTS3/4
# table with the database. This command rearranges the contents of the
# %_segdir table so that all segments within each index are on the same
# level. This means that the 'merge' command can then be used for an
# incremental optimize routine.
#
proc prepare_for_optimize {db tbl} {

  $db eval [string map [list % $tbl] {
    BEGIN;
      CREATE TEMP TABLE tmp_segdir(
        level, idx, start_block, leaves_end_block, end_block, root
      );

      INSERT INTO temp.tmp_segdir 







>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# Argument $db is an open database handle. $tbl is the name of an FTS3/4
# table with the database. This command rearranges the contents of the
# %_segdir table so that all segments within each index are on the same
# level. This means that the 'merge' command can then be used for an
# incremental optimize routine.
#
proc prepare_for_optimize {db tbl} {
  sqlite3_db_config $db DEFENSIVE 0
  $db eval [string map [list % $tbl] {
    BEGIN;
      CREATE TEMP TABLE tmp_segdir(
        level, idx, start_block, leaves_end_block, end_block, root
      );

      INSERT INTO temp.tmp_segdir 

Changes to test/index.test.

622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
# tested somewhere.
do_test index-18.1 {
  catchsql {
    CREATE TABLE sqlite_t1(a, b, c);
  }
} {1 {object name reserved for internal use: sqlite_t1}}
do_test index-18.1.2 {
  sqlite3_db_config db DEFENSIVE 1
  catchsql {
    CREATE TABLE sqlite_t1(a, b, c);
  }
} {1 {object name reserved for internal use: sqlite_t1}}
sqlite3_db_config db DEFENSIVE 0
do_test index-18.2 {
  catchsql {







<







622
623
624
625
626
627
628

629
630
631
632
633
634
635
# tested somewhere.
do_test index-18.1 {
  catchsql {
    CREATE TABLE sqlite_t1(a, b, c);
  }
} {1 {object name reserved for internal use: sqlite_t1}}
do_test index-18.1.2 {

  catchsql {
    CREATE TABLE sqlite_t1(a, b, c);
  }
} {1 {object name reserved for internal use: sqlite_t1}}
sqlite3_db_config db DEFENSIVE 0
do_test index-18.2 {
  catchsql {

Changes to test/index3.test.

79
80
81
82
83
84
85

86
87
88
89
90
91
92
93
94
95



# This test corrupts the database file so it must be the last test
# in the series.
#
do_test index3-99.1 {

  execsql {
    PRAGMA writable_schema=on;
    UPDATE sqlite_master SET sql='nonsense' WHERE name='t1d'
  }
  db close
  catch { sqlite3 db test.db }
  catchsql { DROP INDEX t1c }
} {1 {malformed database schema (t1d)}}

finish_test







>










79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96



# This test corrupts the database file so it must be the last test
# in the series.
#
do_test index3-99.1 {
  sqlite3_db_config db DEFENSIVE 0
  execsql {
    PRAGMA writable_schema=on;
    UPDATE sqlite_master SET sql='nonsense' WHERE name='t1d'
  }
  db close
  catch { sqlite3 db test.db }
  catchsql { DROP INDEX t1c }
} {1 {malformed database schema (t1d)}}

finish_test

Changes to test/misc1.test.

655
656
657
658
659
660
661

662
663
664
665
666
667
668
...
670
671
672
673
674
675
676

677
678
679
680
681
682
683
684
685
686
687

688
689
690
691
692
693
694
  SELECT ""+3 FROM (SELECT ""+5);
} {3}

# 2015-04-19: NULL pointer dereference on a corrupt schema
#
db close
sqlite3 db :memory:

do_execsql_test misc1-23.1 {
  CREATE TABLE t1(x);
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE table t(d CHECK(T(#0)';
  BEGIN;
  CREATE TABLE t2(y);
  ROLLBACK;
................................................................................
} {}

# 2015-04-19:  Faulty assert() statement
#
db close
database_may_be_corrupt
sqlite3 db :memory:

do_catchsql_test misc1-23.2 {
  CREATE TABLE t1(x UNIQUE);
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE TABLE IF not EXISTS t(c)';
  BEGIN;
  CREATE TABLE t2(x);
  ROLLBACK;
  DROP TABLE F;
} {1 {no such table: F}}
db close
sqlite3 db :memory:

do_catchsql_test misc1-23.3 {
  CREATE TABLE t1(x UNIQUE);
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE table y(a TEXT, a TEXT)';
  BEGIN;
  CREATE TABLE t2(y);
  ROLLBACK;







>







 







>











>







655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
...
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
  SELECT ""+3 FROM (SELECT ""+5);
} {3}

# 2015-04-19: NULL pointer dereference on a corrupt schema
#
db close
sqlite3 db :memory:
sqlite3_db_config db DEFENSIVE 0
do_execsql_test misc1-23.1 {
  CREATE TABLE t1(x);
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE table t(d CHECK(T(#0)';
  BEGIN;
  CREATE TABLE t2(y);
  ROLLBACK;
................................................................................
} {}

# 2015-04-19:  Faulty assert() statement
#
db close
database_may_be_corrupt
sqlite3 db :memory:
sqlite3_db_config db DEFENSIVE 0
do_catchsql_test misc1-23.2 {
  CREATE TABLE t1(x UNIQUE);
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE TABLE IF not EXISTS t(c)';
  BEGIN;
  CREATE TABLE t2(x);
  ROLLBACK;
  DROP TABLE F;
} {1 {no such table: F}}
db close
sqlite3 db :memory:
sqlite3_db_config db DEFENSIVE 0
do_catchsql_test misc1-23.3 {
  CREATE TABLE t1(x UNIQUE);
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE table y(a TEXT, a TEXT)';
  BEGIN;
  CREATE TABLE t2(y);
  ROLLBACK;

Changes to test/misc4.test.

208
209
210
211
212
213
214

215
216
217
218
219
220
221
  }
} {1}

# 2015-05-15.  Error message formatting problem.
#
db close
sqlite3 db :memory:

do_catchsql_test misc4-7.1 {
  CREATE TABLE t7(x);
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE TABLE [M%s%s%s%s%s%s%s%s%s%s%s%s%s';
  VACUUM;
} {1 {unrecognized token: "[M%s%s%s%s%s%s%s%s%s%s%s%s%s"}}








>







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  }
} {1}

# 2015-05-15.  Error message formatting problem.
#
db close
sqlite3 db :memory:
sqlite3_db_config db DEFENSIVE 0
do_catchsql_test misc4-7.1 {
  CREATE TABLE t7(x);
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE TABLE [M%s%s%s%s%s%s%s%s%s%s%s%s%s';
  VACUUM;
} {1 {unrecognized token: "[M%s%s%s%s%s%s%s%s%s%s%s%s%s"}}

Changes to test/misc5.test.

586
587
588
589
590
591
592

593
594
595
596
597
598
599
} {1 {parser stack overflow}}

# Parser stack overflow is silently ignored when it occurs while parsing the
# schema and PRAGMA writable_schema is turned on.
#
do_test misc5-7.2 {
  sqlite3 db2 :memory:

  catchsql {
    CREATE TABLE t1(x UNIQUE);
    PRAGMA writable_schema=ON;
    UPDATE sqlite_master SET sql='CREATE table t(o CHECK(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((;VALUES(o)';
    BEGIN;
    CREATE TABLE t2(y);
    ROLLBACK;







>







586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
} {1 {parser stack overflow}}

# Parser stack overflow is silently ignored when it occurs while parsing the
# schema and PRAGMA writable_schema is turned on.
#
do_test misc5-7.2 {
  sqlite3 db2 :memory:
  sqlite3_db_config db2 DEFENSIVE 0
  catchsql {
    CREATE TABLE t1(x UNIQUE);
    PRAGMA writable_schema=ON;
    UPDATE sqlite_master SET sql='CREATE table t(o CHECK(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((;VALUES(o)';
    BEGIN;
    CREATE TABLE t2(y);
    ROLLBACK;

Changes to test/misc7.test.

430
431
432
433
434
435
436

437
438
439
440
441
442
443
      }
    } {0 32}
    
    # sqlite3_test_control_pending_page [expr ($::sqlite_pending_byte / 1024) + 1]
    set ::pending_byte_page [expr ($::sqlite_pending_byte / 1024) + 1]
    sqlite3_test_control_pending_byte $::sqlite_pending_byte 
    do_test misc7-17.3 {

      db eval {
        pragma writable_schema = true;
        UPDATE sqlite_master 
          SET rootpage = $pending_byte_page
          WHERE type = 'table' AND name = 't3';
      }
      execsql {







>







430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
      }
    } {0 32}
    
    # sqlite3_test_control_pending_page [expr ($::sqlite_pending_byte / 1024) + 1]
    set ::pending_byte_page [expr ($::sqlite_pending_byte / 1024) + 1]
    sqlite3_test_control_pending_byte $::sqlite_pending_byte 
    do_test misc7-17.3 {
      sqlite3_db_config db DEFENSIVE 0
      db eval {
        pragma writable_schema = true;
        UPDATE sqlite_master 
          SET rootpage = $pending_byte_page
          WHERE type = 'table' AND name = 't3';
      }
      execsql {

Changes to test/mjournal.test.

156
157
158
159
160
161
162
163
  BEGIN;
    INSERT INTO t1 VALUES(1);
    INSERT INTO t4 VALUES(1);
  COMMIT;
} {0}

finish_test








<
156
157
158
159
160
161
162

  BEGIN;
    INSERT INTO t1 VALUES(1);
    INSERT INTO t4 VALUES(1);
  COMMIT;
} {0}

finish_test

Changes to test/notnull.test.

602
603
604
605
606
607
608
609
do_uses_op_next_test notnull-6.7 "SELECT * FROM t7 WHERE a IS ?" 0
do_uses_op_next_test notnull-6.8 "SELECT * FROM t8 WHERE a IS ?" 0

do_uses_op_next_test notnull-6.9 "SELECT * FROM t8 WHERE a IS ?" 0
do_uses_op_next_test notnull-6.10 "SELECT * FROM t8 WHERE a IS ?" 0

finish_test








<
602
603
604
605
606
607
608

do_uses_op_next_test notnull-6.7 "SELECT * FROM t7 WHERE a IS ?" 0
do_uses_op_next_test notnull-6.8 "SELECT * FROM t8 WHERE a IS ?" 0

do_uses_op_next_test notnull-6.9 "SELECT * FROM t8 WHERE a IS ?" 0
do_uses_op_next_test notnull-6.10 "SELECT * FROM t8 WHERE a IS ?" 0

finish_test

Changes to test/pager1.test.

1881
1882
1883
1884
1885
1886
1887

1888
1889
1890
1891
1892
1893
1894
....
1933
1934
1935
1936
1937
1938
1939

1940
1941
1942
1943
1944
1945
1946
    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
  }
} {}
do_test pager1-18.2 {
  set root [db one "SELECT rootpage FROM sqlite_master"]
  set lockingpage [expr (0x10000/1024) + 1]

  execsql {
    PRAGMA writable_schema = 1;
    UPDATE sqlite_master SET rootpage = $lockingpage;
  }
  sqlite3 db2 test.db
  catchsql { SELECT count(*) FROM t1 } db2
} {1 {database disk image is malformed}}
................................................................................
  hexio_write test.db [expr ($pgno-1)*1024] 90000000
  sqlite3 db2 test.db
  catchsql { SELECT length(x||'') FROM t2 } db2
} {1 {database disk image is malformed}}
db2 close
do_test pager1-18.5 {
  sqlite3 db ""

  execsql {
    CREATE TABLE t1(a, b);
    CREATE TABLE t2(a, b);
    PRAGMA writable_schema = 1;
    UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1';
    PRAGMA writable_schema = 0;
    ALTER TABLE t1 RENAME TO x1;







>







 







>







1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
....
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
    INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
  }
} {}
do_test pager1-18.2 {
  set root [db one "SELECT rootpage FROM sqlite_master"]
  set lockingpage [expr (0x10000/1024) + 1]
  sqlite3_db_config db DEFENSIVE 0
  execsql {
    PRAGMA writable_schema = 1;
    UPDATE sqlite_master SET rootpage = $lockingpage;
  }
  sqlite3 db2 test.db
  catchsql { SELECT count(*) FROM t1 } db2
} {1 {database disk image is malformed}}
................................................................................
  hexio_write test.db [expr ($pgno-1)*1024] 90000000
  sqlite3 db2 test.db
  catchsql { SELECT length(x||'') FROM t2 } db2
} {1 {database disk image is malformed}}
db2 close
do_test pager1-18.5 {
  sqlite3 db ""
  sqlite3_db_config db DEFENSIVE 0
  execsql {
    CREATE TABLE t1(a, b);
    CREATE TABLE t2(a, b);
    PRAGMA writable_schema = 1;
    UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1';
    PRAGMA writable_schema = 0;
    ALTER TABLE t1 RENAME TO x1;

Changes to test/parser1.test.

24
25
26
27
28
29
30

31
32
33
34
35
36
37
} {1 {syntax error after column name "b"}}


# Verify that a legacy schema in the sqlite_master file is allowed to have
# COLLATE, ASC, and DESC keywords on the id list of a FK constraint, and that
# those keywords are silently ignored.
#

do_execsql_test parser1-1.2 {
  CREATE TABLE t1(
    a TEXT PRIMARY KEY,
    b TEXT,
    FOREIGN KEY(b) REFERENCES t1(a)
  );
  INSERT INTO t1 VALUES('abc',NULL),('xyz','abc');







>







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
} {1 {syntax error after column name "b"}}


# Verify that a legacy schema in the sqlite_master file is allowed to have
# COLLATE, ASC, and DESC keywords on the id list of a FK constraint, and that
# those keywords are silently ignored.
#
sqlite3_db_config db DEFENSIVE 0
do_execsql_test parser1-1.2 {
  CREATE TABLE t1(
    a TEXT PRIMARY KEY,
    b TEXT,
    FOREIGN KEY(b) REFERENCES t1(a)
  );
  INSERT INTO t1 VALUES('abc',NULL),('xyz','abc');

Changes to test/pragma.test.

493
494
495
496
497
498
499

500
501
502
503
504
505
506
    db eval {PRAGMA integrity_check}
  } {ok}
}

# Verify that PRAGMA integrity_check catches UNIQUE and NOT NULL
# constraint violations.
#

do_execsql_test pragma-3.20 {
  CREATE TABLE t1(a,b);
  CREATE INDEX t1a ON t1(a);
  INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(2,4),(NULL,5),(NULL,6);
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE UNIQUE INDEX t1a ON t1(a)'
   WHERE name='t1a';







>







493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
    db eval {PRAGMA integrity_check}
  } {ok}
}

# Verify that PRAGMA integrity_check catches UNIQUE and NOT NULL
# constraint violations.
#
sqlite3_db_config db DEFENSIVE 0
do_execsql_test pragma-3.20 {
  CREATE TABLE t1(a,b);
  CREATE INDEX t1a ON t1(a);
  INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(2,4),(NULL,5),(NULL,6);
  PRAGMA writable_schema=ON;
  UPDATE sqlite_master SET sql='CREATE UNIQUE INDEX t1a ON t1(a)'
   WHERE name='t1a';

Changes to test/resetdb.test.

61
62
63
64
65
66
67

68
69
70
71
72
73
74
...
121
122
123
124
125
126
127

128
129
130
131
132
133
134
...
224
225
226
227
228
229
230

231
232
233
234
235
236
237
    PRAGMA page_count;
  } db2
} {210 6000 ok delete 8}

do_test 200 {
  # Thoroughly corrupt the database file by overwriting the first
  # page with randomness.

  catchsql {
    UPDATE sqlite_dbpage SET data=randomblob(4096) WHERE pgno=1;
    PRAGMA quick_check;
  }
} {1 {unsupported file format}}
do_test 201 {
  catchsql {
................................................................................
    PRAGMA journal_mode;
    PRAGMA page_size;
    PRAGMA page_count;
  } db2
} {210 26000 ok wal 8192 12}

# Corrupt the database again

do_catchsql_test 320 {
  UPDATE sqlite_dbpage SET data=randomblob(8192) WHERE pgno=1;
  PRAGMA quick_check
} {1 {file is not a database}}

do_test 330 {
  catchsql {
................................................................................
} {19 ok}

if {[nonzero_reserved_bytes]} {
  finish_test
  return
}


do_execsql_test 710 {
  UPDATE sqlite_dbpage SET data=
    X'53514C69746520666F726D61742033000200030100402020000000000000001300000000000000000000000300000004000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000D00000003017C0001D801AC017C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E03061715110145696E6465787431626374310443524541544520494E4445582074316263204F4E20743128622C63292A0206171311013F696E64657874316174310343524541544520494E44455820743161204F4E20743128612926010617111101397461626C657431743102435245415445205441424C4520743128612C622C6329' WHERE pgno=1;
}

do_execsql_test 720 {
  PRAGMA integrity_check;







>







 







>







 







>







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
...
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
    PRAGMA page_count;
  } db2
} {210 6000 ok delete 8}

do_test 200 {
  # Thoroughly corrupt the database file by overwriting the first
  # page with randomness.
  sqlite3_db_config db DEFENSIVE 0
  catchsql {
    UPDATE sqlite_dbpage SET data=randomblob(4096) WHERE pgno=1;
    PRAGMA quick_check;
  }
} {1 {unsupported file format}}
do_test 201 {
  catchsql {
................................................................................
    PRAGMA journal_mode;
    PRAGMA page_size;
    PRAGMA page_count;
  } db2
} {210 26000 ok wal 8192 12}

# Corrupt the database again
sqlite3_db_config db DEFENSIVE 0
do_catchsql_test 320 {
  UPDATE sqlite_dbpage SET data=randomblob(8192) WHERE pgno=1;
  PRAGMA quick_check
} {1 {file is not a database}}

do_test 330 {
  catchsql {
................................................................................
} {19 ok}

if {[nonzero_reserved_bytes]} {
  finish_test
  return
}

sqlite3_db_config db DEFENSIVE 0
do_execsql_test 710 {
  UPDATE sqlite_dbpage SET data=
    X'53514C69746520666F726D61742033000200030100402020000000000000001300000000000000000000000300000004000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000D00000003017C0001D801AC017C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E03061715110145696E6465787431626374310443524541544520494E4445582074316263204F4E20743128622C63292A0206171311013F696E64657874316174310343524541544520494E44455820743161204F4E20743128612926010617111101397461626C657431743102435245415445205441424C4520743128612C622C6329' WHERE pgno=1;
}

do_execsql_test 720 {
  PRAGMA integrity_check;

Changes to test/shared8.test.

58
59
60
61
62
63
64

65
66
67
68
69
70
71
    INSERT INTO t1 VALUES(4, 4);
    CREATE VIEW v1 AS SELECT a, roman(b) FROM t1;
    SELECT * FROM v1;
  } db1
} {1 i 2 ii 3 iii 4 iv}

do_test 1.1 {

  execsql { 
    PRAGMA writable_schema = 1;
    DELETE FROM sqlite_master WHERE 1;
    PRAGMA writable_schema = 0;
    SELECT * FROM sqlite_master;
  } db1
} {}







>







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
    INSERT INTO t1 VALUES(4, 4);
    CREATE VIEW v1 AS SELECT a, roman(b) FROM t1;
    SELECT * FROM v1;
  } db1
} {1 i 2 ii 3 iii 4 iv}

do_test 1.1 {
  sqlite3_db_config db1 DEFENSIVE 0
  execsql { 
    PRAGMA writable_schema = 1;
    DELETE FROM sqlite_master WHERE 1;
    PRAGMA writable_schema = 0;
    SELECT * FROM sqlite_master;
  } db1
} {}

Changes to test/snapshot2.test.

234
235
236
237
238
239
240
241
  execsql { INSERT INTO t2 VALUES('jkl') } 
  execsql BEGIN db2
  list [catch { sqlite3_snapshot_open_blob db2 main $snap } msg] $msg
} {1 SQLITE_ERROR_SNAPSHOT}


finish_test








<
234
235
236
237
238
239
240

  execsql { INSERT INTO t2 VALUES('jkl') } 
  execsql BEGIN db2
  list [catch { sqlite3_snapshot_open_blob db2 main $snap } msg] $msg
} {1 SQLITE_ERROR_SNAPSHOT}


finish_test

Changes to test/snapshot3.test.

93
94
95
96
97
98
99
100

do_test 1.8 {
  execsql BEGIN db3
  list [catch { sqlite3_snapshot_open_blob db3 main $snap } msg] $msg
} {1 SQLITE_ERROR_SNAPSHOT}

finish_test








<
93
94
95
96
97
98
99


do_test 1.8 {
  execsql BEGIN db3
  list [catch { sqlite3_snapshot_open_blob db3 main $snap } msg] $msg
} {1 SQLITE_ERROR_SNAPSHOT}

finish_test

Changes to test/snapshot4.test.

68
69
70
71
72
73
74
75
  execsql {
    SELECT count(*) FROM t1
  } 
} {100}


finish_test








<
68
69
70
71
72
73
74

  execsql {
    SELECT count(*) FROM t1
  } 
} {100}


finish_test

Changes to test/snapshot_up.test.

177
178
179
180
181
182
183
184
  set ::res
} {1 SQLITE_BUSY}

sqlite3_snapshot_free $::snap1
sqlite3_snapshot_free $::snap2

finish_test








<
177
178
179
180
181
182
183

  set ::res
} {1 SQLITE_BUSY}

sqlite3_snapshot_free $::snap1
sqlite3_snapshot_free $::snap2

finish_test

Changes to test/swarmvtab3.test.

227
228
229
230
231
232
233
234
}

db close
forcedelete {*}[glob test.db*]
forcedelete {*}[glob test_remote.db*]

finish_test








<
227
228
229
230
231
232
233

}

db close
forcedelete {*}[glob test.db*]
forcedelete {*}[glob test_remote.db*]

finish_test

Changes to test/swarmvtabfault.test.

59
60
61
62
63
64
65
66
} -body {
  execsql { SELECT a FROM xyz }
} -test {
  faultsim_test_result {0 {1 2 9}} {1 {sql error: out of memory}}
}

finish_test








<
59
60
61
62
63
64
65

} -body {
  execsql { SELECT a FROM xyz }
} -test {
  faultsim_test_result {0 {1 2 9}} {1 {sql error: out of memory}}
}

finish_test

Changes to test/table.test.

272
273
274
275
276
277
278

279
280
281
282
283
284
285
  }
} {}

do_test table-5.2.2 {
  db close
  forcedelete test.db
  sqlite3 db test.db

  db eval {
    CREATE TABLE t0(a,b);
    CREATE INDEX t ON t0(a);
    PRAGMA writable_schema=ON;
    UPDATE sqlite_master SET sql='CREATE TABLE a.b(a UNIQUE';
    BEGIN;
    CREATE TABLE t1(x);







>







272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  }
} {}

do_test table-5.2.2 {
  db close
  forcedelete test.db
  sqlite3 db test.db
  sqlite3_db_config db DEFENSIVE 0
  db eval {
    CREATE TABLE t0(a,b);
    CREATE INDEX t ON t0(a);
    PRAGMA writable_schema=ON;
    UPDATE sqlite_master SET sql='CREATE TABLE a.b(a UNIQUE';
    BEGIN;
    CREATE TABLE t1(x);

Changes to test/trigger7.test.

102
103
104
105
106
107
108

109
110
111
112
113
114
115
116
117
118
  }
} {}

# This test corrupts the database file so it must be the last test
# in the series.
#
do_test trigger7-99.1 {

  execsql {
    PRAGMA writable_schema=on;
    UPDATE sqlite_master SET sql='nonsense';
  }
  db close
  catch { sqlite3 db test.db }
  catchsql { DROP TRIGGER t2r5 }
} {/1 {malformed database schema .*}/}

finish_test







>










102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  }
} {}

# This test corrupts the database file so it must be the last test
# in the series.
#
do_test trigger7-99.1 {
  sqlite3_db_config db DEFENSIVE 0
  execsql {
    PRAGMA writable_schema=on;
    UPDATE sqlite_master SET sql='nonsense';
  }
  db close
  catch { sqlite3 db test.db }
  catchsql { DROP TRIGGER t2r5 }
} {/1 {malformed database schema .*}/}

finish_test

Changes to test/triggerE.test.

64
65
66
67
68
69
70

71
72
73
74
75
76
77
  do_catchsql_test 1.2.$tn "CREATE TEMP TRIGGER tr1 $defn" [list 1 $errmsg]
}

#-------------------------------------------------------------------------
# Test that variable references within trigger definitions loaded from 
# the sqlite_master table are automatically converted to NULL.
#

do_execsql_test 2.1 {
  PRAGMA writable_schema = 1;
  INSERT INTO sqlite_master VALUES('trigger', 'tr1', 't1', 0,
    'CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN 
        INSERT INTO t2 VALUES(?1, ?2); 
     END'
  );







>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  do_catchsql_test 1.2.$tn "CREATE TEMP TRIGGER tr1 $defn" [list 1 $errmsg]
}

#-------------------------------------------------------------------------
# Test that variable references within trigger definitions loaded from 
# the sqlite_master table are automatically converted to NULL.
#
sqlite3_db_config db DEFENSIVE 0
do_execsql_test 2.1 {
  PRAGMA writable_schema = 1;
  INSERT INTO sqlite_master VALUES('trigger', 'tr1', 't1', 0,
    'CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN 
        INSERT INTO t2 VALUES(?1, ?2); 
     END'
  );

Changes to test/unionvtab.test.

451
452
453
454
455
456
457
458
} {five six seven eight nine}

do_execsql_test 5.4 {
  SELECT * FROM cc WHERE two LIKE '6'
} {six 6}

finish_test








<
451
452
453
454
455
456
457

} {five six seven eight nine}

do_execsql_test 5.4 {
  SELECT * FROM cc WHERE two LIKE '6'
} {six 6}

finish_test

Changes to test/unionvtabfault.test.

77
78
79
80
81
82
83
84
} -test {
  faultsim_test_result {0 {}} {1 {initialization of unionvtab failed: }}
}



finish_test








<
77
78
79
80
81
82
83

} -test {
  faultsim_test_result {0 {}} {1 {initialization of unionvtab failed: }}
}



finish_test

Changes to test/vtab1.test.

1249
1250
1251
1252
1253
1254
1255

1256
1257
1258
1259
1260
1261
1262

# The following test case exposes an instance in sqlite3_declare_vtab()
# an error message was set using a call similar to sqlite3_mprintf(zErr),
# where zErr is an arbitrary string. This is no good if the string contains
# characters that can be mistaken for printf() formatting directives.
#
do_test vtab1-17.1 {

  execsql { 
    PRAGMA writable_schema = 1;
    INSERT INTO sqlite_master VALUES(
      'table', 't3', 't3', 0, 'INSERT INTO "%s%s" VALUES(1)'
    );
  }
  catchsql { CREATE VIRTUAL TABLE t4 USING echo(t3); }







>







1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263

# The following test case exposes an instance in sqlite3_declare_vtab()
# an error message was set using a call similar to sqlite3_mprintf(zErr),
# where zErr is an arbitrary string. This is no good if the string contains
# characters that can be mistaken for printf() formatting directives.
#
do_test vtab1-17.1 {
  sqlite3_db_config db DEFENSIVE 0
  execsql { 
    PRAGMA writable_schema = 1;
    INSERT INTO sqlite_master VALUES(
      'table', 't3', 't3', 0, 'INSERT INTO "%s%s" VALUES(1)'
    );
  }
  catchsql { CREATE VIRTUAL TABLE t4 USING echo(t3); }

Changes to test/wherelimit2.test.

293
294
295
296
297
298
299
300
  set ::log {}
  execsql { UPDATE "v w" SET "a b" = "a b" || 'x' ORDER BY "a b" LIMIT 5; }
  set ::log
} {ax a bx b cx c dx d ex a}


finish_test








<
293
294
295
296
297
298
299

  set ::log {}
  execsql { UPDATE "v w" SET "a b" = "a b" || 'x' ORDER BY "a b" LIMIT 5; }
  set ::log
} {ax a bx b cx c dx d ex a}


finish_test

Changes to test/window5.test.

90
91
92
93
94
95
96
97
} {1 {sum() may not be used as a window function}}
do_execsql_test 3.1 {
  SELECT sum(a) FROM t1;
} {21}


finish_test








<
90
91
92
93
94
95
96

} {1 {sum() may not be used as a window function}}
do_execsql_test 3.1 {
  SELECT sum(a) FROM t1;
} {21}


finish_test

Changes to test/windowfault.test.

159
160
161
162
163
164
165
166
    ORDER BY a;
  }
} -test {
  faultsim_test_result {0 {1 2 5 6 9 10}}
}

finish_test








<
159
160
161
162
163
164
165

    ORDER BY a;
  }
} -test {
  faultsim_test_result {0 {1 2 5 6 9 10}}
}

finish_test

Changes to test/zipfile2.test.

237
238
239
240
241
242
243
244
  INSERT INTO temp.zip (name,data) VALUES ('test1','test'); 
  INSERT INTO temp.zip (name,data) VALUES ('test2','test'); 
  UPDATE OR REPLACE zip SET name='test2' WHERE name='test1';
  SELECT name FROM zip;
} {test2}

finish_test








<
237
238
239
240
241
242
243

  INSERT INTO temp.zip (name,data) VALUES ('test1','test'); 
  INSERT INTO temp.zip (name,data) VALUES ('test2','test'); 
  UPDATE OR REPLACE zip SET name='test2' WHERE name='test1';
  SELECT name FROM zip;
} {test2}

finish_test

Changes to tool/genfkey.test.

347
348
349
350
351
352
353
354
} {1 {constraint failed}}
do_test genfkey-6.7 {
  execsql {
    SELECT * FROM parent;
    SELECT * FROM child;
  }
} {1 1}








<
347
348
349
350
351
352
353

} {1 {constraint failed}}
do_test genfkey-6.7 {
  execsql {
    SELECT * FROM parent;
    SELECT * FROM child;
  }
} {1 1}