modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/rbu/rbu1.test (about)

     1  # 2014 August 30
     2  #
     3  # The author disclaims copyright to this source code.  In place of
     4  # a legal notice, here is a blessing:
     5  #
     6  #    May you do good and not evil.
     7  #    May you find forgiveness for yourself and forgive others.
     8  #    May you share freely, never taking more than you give.
     9  #
    10  #***********************************************************************
    11  #
    12  
    13  source [file join [file dirname [info script]] rbu_common.tcl]
    14  set ::testprefix rbu1
    15  
    16  db close
    17  sqlite3_shutdown
    18  sqlite3_config_uri 1
    19  
    20  # Create a simple RBU database. That expects to write to a table:
    21  #
    22  #   CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
    23  #
    24  proc create_rbu1 {filename} {
    25    forcedelete $filename
    26    sqlite3 rbu1 $filename  
    27    rbu1 eval {
    28      CREATE TABLE data_t1(a, b, c, rbu_control);
    29      INSERT INTO data_t1 VALUES(1, 2, 3, 0);
    30      INSERT INTO data_t1 VALUES(2, 'two', 'three', 0);
    31      INSERT INTO data_t1 VALUES(3, NULL, 8.2, 0);
    32    }
    33    rbu1 close
    34    return $filename
    35  }
    36  
    37  # Create a simple RBU database. That expects to write to a table:
    38  #
    39  #   CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
    40  #
    41  # This RBU includes both insert and delete operations.
    42  #
    43  proc create_rbu4 {filename} {
    44    forcedelete $filename
    45    sqlite3 rbu1 $filename  
    46    rbu1 eval {
    47      CREATE TABLE data_t1(a, b, c, rbu_control);
    48      INSERT INTO data_t1 VALUES(1, 2, 3, 0);
    49      INSERT INTO data_t1 VALUES(2, NULL, 5, 1);
    50      INSERT INTO data_t1 VALUES(3, 8, 9, 0);
    51      INSERT INTO data_t1 VALUES(4, NULL, 11, 1);
    52    }
    53    rbu1 close
    54    return $filename
    55  }
    56  #
    57  # Create a simple RBU database. That expects to write to a table:
    58  #
    59  #   CREATE TABLE t1(c, b, '(a)' INTEGER PRIMARY KEY);
    60  #
    61  # This RBU includes both insert and delete operations.
    62  #
    63  proc create_rbu4b {filename} {
    64    forcedelete $filename
    65    sqlite3 rbu1 $filename  
    66    rbu1 eval {
    67      CREATE TABLE data_t1(c, b, '(a)', rbu_control);
    68      INSERT INTO data_t1 VALUES(3, 2, 1, 0);
    69      INSERT INTO data_t1 VALUES(5, NULL, 2, 1);
    70      INSERT INTO data_t1 VALUES(9, 8, 3, 0);
    71      INSERT INTO data_t1 VALUES(11, NULL, 4, 1);
    72    }
    73    rbu1 close
    74    return $filename
    75  }
    76  
    77  # Create a simple RBU database. That expects to write to a table:
    78  #
    79  #   CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
    80  #
    81  # This RBU includes update statements.
    82  #
    83  proc create_rbu5 {filename} {
    84    forcedelete $filename
    85    sqlite3 rbu5 $filename  
    86    rbu5 eval {
    87      CREATE TABLE data_t1(a, b, c, d, rbu_control);
    88      INSERT INTO data_t1 VALUES(1, NULL, NULL, 5, '...x');  -- SET d = 5
    89      INSERT INTO data_t1 VALUES(2, NULL, 10, 5, '..xx');    -- SET c=10, d = 5
    90      INSERT INTO data_t1 VALUES(3, 11, NULL, NULL, '.x..'); -- SET b=11
    91    }
    92    rbu5 close
    93    return $filename
    94  }
    95  
    96  
    97  # Same as [step_rbu], except using a URI to open the target db.
    98  #
    99  proc step_rbu_uri {target rbu} {
   100    while 1 {
   101      sqlite3rbu rbu file:$target?xyz=&abc=123 $rbu
   102      set rc [rbu step]
   103      rbu close
   104      if {$rc != "SQLITE_OK"} break
   105    }
   106    set rc
   107  }
   108  
   109  # Same as [step_rbu], except using an external state database - "state.db"
   110  #
   111  proc step_rbu_state {target rbu} {
   112    while 1 {
   113      sqlite3rbu rbu $target $rbu state.db
   114      set rc [rbu step]
   115      rbu close
   116      if {$rc != "SQLITE_OK"} break
   117    }
   118    set rc
   119  }
   120  
   121  proc dbfilecksum {file} {
   122    sqlite3 ck $file
   123    set cksum [dbcksum ck main]
   124    ck close
   125    set cksum
   126  }
   127  
   128  foreach {tn3 create_vfs destroy_vfs} {
   129    1 {} {}
   130    2 {
   131      sqlite3rbu_create_vfs -default myrbu ""
   132    } {
   133      sqlite3rbu_destroy_vfs myrbu
   134    }
   135  } {
   136  
   137    eval $create_vfs
   138  
   139    foreach {tn2 cmd} {
   140        1 run_rbu 
   141        2 step_rbu 3 step_rbu_uri 4 step_rbu_state
   142    } {
   143      foreach {tn schema} {
   144        1 {
   145          CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
   146        }
   147        2 { 
   148          CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
   149          CREATE INDEX i1 ON t1(b);
   150        }
   151        3 { 
   152          CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID;
   153        }
   154        4 { 
   155          CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID;
   156          CREATE INDEX i1 ON t1(b);
   157        }
   158        5 { 
   159          CREATE TABLE t1(a, b, c, PRIMARY KEY(a, c)) WITHOUT ROWID;
   160          CREATE INDEX i1 ON t1(b);
   161        }
   162        6 { 
   163          CREATE TABLE t1(a, b, c, PRIMARY KEY(c)) WITHOUT ROWID;
   164          CREATE INDEX i1 ON t1(b, a);
   165        }
   166        7 { 
   167          CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
   168          CREATE INDEX i1 ON t1(b, c);
   169          CREATE INDEX i2 ON t1(c, b);
   170          CREATE INDEX i3 ON t1(a, b, c, a, b, c);
   171        }
   172  
   173        8 { 
   174          CREATE TABLE t1(a PRIMARY KEY, b, c);
   175          CREATE INDEX i1 ON t1(b, c);
   176          CREATE INDEX i2 ON t1(c, b);
   177          CREATE INDEX i3 ON t1(a, b, c, a, b, c);
   178        }
   179  
   180        9 { 
   181          CREATE TABLE t1(a, b, c, PRIMARY KEY(a, c));
   182          CREATE INDEX i1 ON t1(b);
   183        }
   184  
   185        10 { 
   186          CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
   187          CREATE INDEX i1 ON t1(b DESC);
   188        }
   189  
   190        11 { 
   191          CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
   192          CREATE INDEX i1 ON t1(b DESC, a ASC, c DESC);
   193        }
   194  
   195        12 { 
   196          CREATE TABLE t1(a INT PRIMARY KEY DESC, b, c) WITHOUT ROWID; 
   197        }
   198  
   199        13 { 
   200          CREATE TABLE t1(a INT, b, c, PRIMARY KEY(a DESC)) WITHOUT ROWID; 
   201        }
   202  
   203        14 { 
   204          CREATE TABLE t1(a, b, c, PRIMARY KEY(a DESC, c)) WITHOUT ROWID;
   205          CREATE INDEX i1 ON t1(b);
   206        }
   207  
   208        15 { 
   209          CREATE TABLE t1(a, b, c, PRIMARY KEY(a, c DESC)) WITHOUT ROWID;
   210          CREATE INDEX i1 ON t1(b);
   211        }
   212  
   213        16 { 
   214          CREATE TABLE t1(a, b, c, PRIMARY KEY(c DESC, a)) WITHOUT ROWID;
   215          CREATE INDEX i1 ON t1(b DESC, c, a);
   216        }
   217      } {
   218        reset_db
   219        execsql $schema
   220        create_rbu1 rbu.db
   221        set check [dbfilecksum rbu.db]
   222        forcedelete state.db
   223  
   224        do_test $tn3.1.$tn2.$tn.1 {
   225          $cmd test.db rbu.db
   226        } {SQLITE_DONE}
   227  
   228        do_execsql_test $tn3.1.$tn2.$tn.2 { SELECT * FROM t1 ORDER BY a ASC } {
   229          1 2 3 
   230          2 two three 
   231          3 {} 8.2
   232        }
   233        do_execsql_test $tn3.1.$tn2.$tn.3 { SELECT * FROM t1 ORDER BY b ASC } {
   234          3 {} 8.2
   235          1 2 3 
   236          2 two three 
   237        }
   238        do_execsql_test $tn3.1.$tn2.$tn.4 { SELECT * FROM t1 ORDER BY c ASC } {
   239          1 2 3 
   240          3 {} 8.2
   241          2 two three 
   242        }
   243     
   244        do_execsql_test $tn3.1.$tn2.$tn.5 { PRAGMA integrity_check } ok
   245  
   246        if {$cmd=="step_rbu_state"} {
   247          do_test $tn3.1.$tn2.$tn.6 { file exists state.db } 1
   248          do_test $tn3.1.$tn2.$tn.7 { expr {$check == [dbfilecksum rbu.db]} } 1
   249        } else {
   250          do_test $tn3.1.$tn2.$tn.8 { file exists state.db } 0
   251          do_test $tn3.1.$tn2.$tn.9 { expr {$check == [dbfilecksum rbu.db]} } 0
   252        }
   253      }
   254    }
   255  
   256    #-------------------------------------------------------------------------
   257    # Check that an RBU cannot be applied to a table that has no PK.
   258    #
   259    # UPDATE: At one point RBU required that all tables featured either
   260    # explicit IPK columns or were declared WITHOUT ROWID. This has been
   261    # relaxed so that external PRIMARY KEYs on tables with automatic rowids
   262    # are now allowed.
   263    #
   264    # UPDATE 2: Tables without any PRIMARY KEY declaration are now allowed.
   265    # However the input table must feature an "rbu_rowid" column.
   266    #
   267    reset_db
   268    create_rbu1 rbu.db
   269    do_execsql_test $tn3.2.1 { CREATE TABLE t1(a, b, c) }
   270    do_test $tn3.2.2 {
   271      sqlite3rbu rbu test.db rbu.db
   272      rbu step
   273    } {SQLITE_ERROR}
   274    do_test $tn3.2.3 {
   275      list [catch { rbu close } msg] $msg
   276    } {1 {SQLITE_ERROR - table data_t1 requires rbu_rowid column}}
   277    reset_db
   278    do_execsql_test $tn3.2.4 { CREATE TABLE t1(a PRIMARY KEY, b, c) }
   279    do_test $tn3.2.5 {
   280      sqlite3rbu rbu test.db rbu.db
   281      rbu step
   282    } {SQLITE_OK}
   283    do_test $tn3.2.6 {
   284      list [catch { rbu close } msg] $msg
   285    } {0 SQLITE_OK}
   286  
   287    #-------------------------------------------------------------------------
   288    # Check that if a UNIQUE constraint is violated the current and all 
   289    # subsequent [rbu step] calls return SQLITE_CONSTRAINT. And that the RBU 
   290    # transaction is rolled back by the [rbu close] that deletes the rbu 
   291    # handle.
   292    #
   293    foreach {tn errcode errmsg schema} {
   294      1 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.a" {
   295        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
   296        INSERT INTO t1 VALUES(3, 2, 1);
   297      } 
   298  
   299      2 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.c" {
   300        CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c UNIQUE);
   301        INSERT INTO t1 VALUES(4, 2, 'three');
   302      } 
   303  
   304      3 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.a" {
   305        CREATE TABLE t1(a PRIMARY KEY, b, c);
   306        INSERT INTO t1 VALUES(3, 2, 1);
   307      } 
   308  
   309      4 SQLITE_CONSTRAINT "UNIQUE constraint failed: t1.c" {
   310        CREATE TABLE t1(a PRIMARY KEY, b, c UNIQUE);
   311        INSERT INTO t1 VALUES(4, 2, 'three');
   312      } 
   313  
   314    } {
   315      reset_db
   316      execsql $schema
   317      set cksum [dbcksum db main]
   318  
   319      do_test $tn3.3.$tn.1 {
   320        create_rbu1 rbu.db
   321        sqlite3rbu rbu test.db rbu.db
   322        while {[set res [rbu step]]=="SQLITE_OK"} {}
   323        set res
   324      } $errcode
   325  
   326      do_test $tn3.3.$tn.2 { rbu step } $errcode
   327  
   328      do_test $tn3.3.$tn.3 { 
   329        list [catch { rbu close } msg] $msg
   330      } [list 1 "$errcode - $errmsg"]
   331  
   332      do_test $tn3.3.$tn.4 { dbcksum db main } $cksum
   333    }
   334  
   335    #-------------------------------------------------------------------------
   336    #
   337    foreach {tn2 cmd} {1 run_rbu 2 step_rbu 3 step_rbu_state } {
   338      foreach {tn schema} {
   339        1 {
   340          CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
   341        }
   342        2 {
   343          CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
   344          CREATE INDEX i1 ON t1(b);
   345        }
   346        3 {
   347          CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
   348          CREATE INDEX i1 ON t1(b);
   349          CREATE INDEX i2 ON t1(c, b);
   350          CREATE INDEX i3 ON t1(c, b, c);
   351        }
   352        4 {
   353          CREATE TABLE t1(a INT PRIMARY KEY, b, c) WITHOUT ROWID;
   354          CREATE INDEX i1 ON t1(b);
   355          CREATE INDEX i2 ON t1(c, b);
   356          CREATE INDEX i3 ON t1(c, b, c);
   357        }
   358        5 {
   359          CREATE TABLE t1(a INT PRIMARY KEY, b, c);
   360          CREATE INDEX i1 ON t1(b);
   361          CREATE INDEX i2 ON t1(c, b);
   362          CREATE INDEX i3 ON t1(c, b, c);
   363        }
   364  
   365        6 {
   366          CREATE TABLE t1(a INT PRIMARY KEY DESC, b, c);
   367          CREATE INDEX i1 ON t1(b DESC);
   368          CREATE INDEX i2 ON t1(c, b);
   369          CREATE INDEX i3 ON t1(c DESC, b, c);
   370        }
   371        7 {
   372          CREATE TABLE t1(a INT PRIMARY KEY DESC, b, c) WITHOUT ROWID;
   373          CREATE INDEX i1 ON t1(b);
   374          CREATE INDEX i2 ON t1(c, b);
   375          CREATE INDEX i3 ON t1(c, b, c);
   376        }
   377      } {
   378        reset_db
   379        execsql $schema
   380        execsql {
   381          INSERT INTO t1 VALUES(2, 'hello', 'world');
   382          INSERT INTO t1 VALUES(4, 'hello', 'planet');
   383          INSERT INTO t1 VALUES(6, 'hello', 'xyz');
   384        }
   385  
   386        create_rbu4 rbu.db
   387        set check [dbfilecksum rbu.db]
   388        forcedelete state.db
   389      
   390        do_test $tn3.4.$tn2.$tn.1 {
   391          $cmd test.db rbu.db
   392        } {SQLITE_DONE}
   393        
   394        do_execsql_test $tn3.4.$tn2.$tn.2 {
   395          SELECT * FROM t1 ORDER BY a ASC;
   396        } {
   397          1 2 3 
   398          3 8 9
   399          6 hello xyz
   400        }
   401      
   402        do_execsql_test $tn3.4.$tn2.$tn.3 { PRAGMA integrity_check } ok
   403  
   404        if {$cmd=="step_rbu_state"} {
   405          do_test $tn3.4.$tn2.$tn.4 { file exists state.db } 1
   406          do_test $tn3.4.$tn2.$tn.5 { expr {$check == [dbfilecksum rbu.db]} } 1
   407        } else {
   408          do_test $tn3.4.$tn2.$tn.6 { file exists state.db } 0
   409          do_test $tn3.4.$tn2.$tn.7 { expr {$check == [dbfilecksum rbu.db]} } 0
   410        }
   411      }
   412    }
   413  
   414    foreach {tn2 cmd} {1 run_rbu 2 step_rbu 3 step_rbu_state} {
   415      foreach {tn schema} {
   416        1 {
   417          CREATE TABLE t1(c, b, '(a)' INTEGER PRIMARY KEY);
   418          CREATE INDEX i1 ON t1(c, b);
   419        }
   420        2 {
   421          CREATE TABLE t1(c, b, '(a)' PRIMARY KEY);
   422        }
   423        3 {
   424          CREATE TABLE t1(c, b, '(a)' PRIMARY KEY) WITHOUT ROWID;
   425        }
   426      } {
   427        reset_db
   428        execsql $schema
   429        execsql {
   430          INSERT INTO t1('(a)', b, c) VALUES(2, 'hello', 'world');
   431          INSERT INTO t1('(a)', b, c) VALUES(4, 'hello', 'planet');
   432          INSERT INTO t1('(a)', b, c) VALUES(6, 'hello', 'xyz');
   433        }
   434  
   435        create_rbu4b rbu.db
   436        set check [dbfilecksum rbu.db]
   437        forcedelete state.db
   438      
   439        do_test $tn3.5.$tn2.$tn.1 {
   440          $cmd test.db rbu.db
   441        } {SQLITE_DONE}
   442        
   443        do_execsql_test $tn3.5.$tn2.$tn.2 {
   444          SELECT * FROM t1 ORDER BY "(a)" ASC;
   445        } {
   446          3 2 1
   447          9 8 3
   448          xyz hello 6
   449        }
   450      
   451        do_execsql_test $tn3.4.$tn2.$tn.3 { PRAGMA integrity_check } ok
   452  
   453        if {$cmd=="step_rbu_state"} {
   454          do_test $tn3.5.$tn2.$tn.4 { file exists state.db } 1
   455          do_test $tn3.5.$tn2.$tn.5 { expr {$check == [dbfilecksum rbu.db]} } 1
   456        } else {
   457          do_test $tn3.5.$tn2.$tn.6 { file exists state.db } 0
   458          do_test $tn3.5.$tn2.$tn.7 { expr {$check == [dbfilecksum rbu.db]} } 0
   459        }
   460      }
   461    }
   462  
   463    #-------------------------------------------------------------------------
   464    #
   465    foreach {tn2 cmd} {1 run_rbu 2 step_rbu 3 step_rbu_state} {
   466      foreach {tn schema} {
   467        1 {
   468          CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
   469        }
   470        2 {
   471          CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
   472          CREATE INDEX i1 ON t1(d);
   473          CREATE INDEX i2 ON t1(d, c);
   474          CREATE INDEX i3 ON t1(d, c, b);
   475          CREATE INDEX i4 ON t1(b);
   476          CREATE INDEX i5 ON t1(c);
   477          CREATE INDEX i6 ON t1(c, b);
   478        }
   479        3 {
   480          CREATE TABLE t1(a PRIMARY KEY, b, c, d) WITHOUT ROWID;
   481          CREATE INDEX i1 ON t1(d);
   482          CREATE INDEX i2 ON t1(d, c);
   483          CREATE INDEX i3 ON t1(d, c, b);
   484          CREATE INDEX i4 ON t1(b);
   485          CREATE INDEX i5 ON t1(c);
   486          CREATE INDEX i6 ON t1(c, b);
   487        }
   488        4 {
   489          CREATE TABLE t1(a PRIMARY KEY, b, c, d);
   490          CREATE INDEX i1 ON t1(d);
   491          CREATE INDEX i2 ON t1(d, c);
   492          CREATE INDEX i3 ON t1(d, c, b);
   493          CREATE INDEX i4 ON t1(b);
   494          CREATE INDEX i5 ON t1(c);
   495          CREATE INDEX i6 ON t1(c, b);
   496        }
   497      } {
   498        reset_db
   499        execsql $schema
   500        execsql {
   501          INSERT INTO t1 VALUES(1, 2, 3, 4);
   502          INSERT INTO t1 VALUES(2, 5, 6, 7);
   503          INSERT INTO t1 VALUES(3, 8, 9, 10);
   504        }
   505      
   506        create_rbu5 rbu.db
   507        set check [dbfilecksum rbu.db]
   508        forcedelete state.db
   509  
   510        do_test $tn3.5.$tn2.$tn.1 {
   511          $cmd test.db rbu.db
   512        } {SQLITE_DONE}
   513        
   514        do_execsql_test $tn3.5.$tn2.$tn.2 {
   515          SELECT * FROM t1 ORDER BY a ASC;
   516        } {
   517          1 2 3 5
   518          2 5 10 5
   519          3 11 9 10
   520        }
   521      
   522        do_execsql_test $tn3.6.$tn2.$tn.3 { PRAGMA integrity_check } ok
   523  
   524        if {$cmd=="step_rbu_state"} {
   525          do_test $tn3.6.$tn2.$tn.4 { file exists state.db } 1
   526          do_test $tn3.6.$tn2.$tn.5 { expr {$check == [dbfilecksum rbu.db]} } 1
   527        } else {
   528          do_test $tn3.6.$tn2.$tn.6 { file exists state.db } 0
   529          do_test $tn3.6.$tn2.$tn.7 { expr {$check == [dbfilecksum rbu.db]} } 0
   530        }
   531      }
   532    }
   533  
   534    #-------------------------------------------------------------------------
   535    # Test some error cases:
   536    # 
   537    #   * A virtual table with no rbu_rowid column.
   538    #   * A no-PK table with no rbu_rowid column.
   539    #   * A PK table with an rbu_rowid column.
   540    #
   541    #   6: An update string of the wrong length
   542    #
   543    ifcapable fts3 {
   544      foreach {tn schema error} {
   545         1 {
   546           CREATE TABLE t1(a, b);
   547           CREATE TABLE rbu.data_t1(a, b, rbu_control);
   548         } {SQLITE_ERROR - table data_t1 requires rbu_rowid column}
   549      
   550         2 {
   551           CREATE VIRTUAL TABLE t1 USING fts4(a, b);
   552           CREATE TABLE rbu.data_t1(a, b, rbu_control);
   553         } {SQLITE_ERROR - table data_t1 requires rbu_rowid column}
   554      
   555         3 {
   556           CREATE TABLE t1(a PRIMARY KEY, b);
   557           CREATE TABLE rbu.data_t1(a, b, rbu_rowid, rbu_control);
   558         } {SQLITE_ERROR - table data_t1 may not have rbu_rowid column}
   559      
   560         4 {
   561           CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
   562           CREATE TABLE rbu.data_t1(a, b, rbu_rowid, rbu_control);
   563         } {SQLITE_ERROR - table data_t1 may not have rbu_rowid column}
   564      
   565         5 {
   566           CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT ROWID;
   567           CREATE TABLE rbu.data_t1(a, b, rbu_rowid, rbu_control);
   568         } {SQLITE_ERROR - table data_t1 may not have rbu_rowid column}
   569  
   570         6 {
   571           CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT ROWID;
   572           CREATE TABLE rbu.data_t1(a, b, rbu_control);
   573           INSERT INTO rbu.data_t1 VALUES(1, 2, 'x.x');
   574         } {SQLITE_ERROR - invalid rbu_control value}
   575  
   576         7 {
   577           CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT ROWID;
   578           CREATE TABLE rbu.data_t1(a, b, rbu_control);
   579           INSERT INTO rbu.data_t1 VALUES(1, 2, NULL);
   580         } {SQLITE_ERROR - invalid rbu_control value}
   581  
   582         8 {
   583           CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT ROWID;
   584           CREATE TABLE rbu.data_t1(a, b, rbu_control);
   585           INSERT INTO rbu.data_t1 VALUES(1, 2, 4);
   586         } {SQLITE_ERROR - invalid rbu_control value}
   587  
   588         9 {
   589           CREATE TABLE t1(a, b PRIMARY KEY) WITHOUT ROWID;
   590           CREATE TABLE rbu.data_t1(a, b, rbu_control);
   591           INSERT INTO rbu.data_t1 VALUES(1, 2, 3);
   592         } {SQLITE_ERROR - invalid rbu_control value}
   593  
   594         10 {
   595           CREATE TABLE t2(a, b);
   596           CREATE TABLE rbu.data_t1(a, b, rbu_control);
   597           INSERT INTO rbu.data_t1 VALUES(1, 2, 2);
   598         } {SQLITE_ERROR - no such table: t1}
   599  
   600         11 {
   601           CREATE TABLE rbu.data_t2(a, b, rbu_control);
   602           INSERT INTO rbu.data_t2 VALUES(1, 2, 2);
   603         } {SQLITE_ERROR - no such table: t2}
   604  
   605      } {
   606        reset_db
   607        forcedelete rbu.db
   608        execsql { ATTACH 'rbu.db' AS rbu }
   609        execsql $schema
   610  
   611        do_test $tn3.7.$tn {
   612          list [catch { run_rbu test.db rbu.db } msg] $msg
   613        } [list 1 $error]
   614      }
   615    }
   616  
   617    # Test that an RBU database containing no input tables is handled
   618    # correctly.
   619    reset_db
   620    forcedelete rbu.db
   621    do_test $tn3.8.1 {
   622      list [catch { run_rbu test.db rbu.db } msg] $msg
   623    } {0 SQLITE_DONE}
   624  
   625    # Test that an RBU database containing only empty data_xxx tables is
   626    # also handled correctly.
   627    reset_db
   628    forcedelete rbu.db
   629    do_execsql_test $tn3.8.2.1 {
   630      CREATE TABLE t1(a PRIMARY KEY, b);
   631      INSERT INTO t1 VALUES(1, 2);
   632      ATTACH 'rbu.db' AS rbu;
   633      CREATE TABLE data_t1(a, b, rbu_control);
   634      DETACH rbu;
   635    }
   636    do_test $tn3.8.2.1 {
   637      list [catch { run_rbu test.db rbu.db } msg] $msg
   638    } {0 SQLITE_DONE}
   639  
   640    # Test that RBU can update indexes containing NULL values.
   641    #
   642    reset_db
   643    forcedelete rbu.db
   644    do_execsql_test $tn3.9.1 {
   645      CREATE TABLE t1(a PRIMARY KEY, b, c);
   646      CREATE INDEX i1 ON t1(b, c);
   647      INSERT INTO t1 VALUES(1, 1, NULL);
   648      INSERT INTO t1 VALUES(2, NULL, 2);
   649      INSERT INTO t1 VALUES(3, NULL, NULL);
   650  
   651      ATTACH 'rbu.db' AS rbu;
   652      CREATE TABLE rbu.data_t1(a, b, c, rbu_control);
   653      INSERT INTO data_t1 VALUES(1, NULL, NULL, 1);
   654      INSERT INTO data_t1 VALUES(3, NULL, NULL, 1);
   655    } {}
   656  
   657    do_test $tn3.9.2 {
   658      list [catch { run_rbu test.db rbu.db } msg] $msg
   659    } {0 SQLITE_DONE}
   660  
   661    do_execsql_test $tn3.9.3 {
   662      SELECT * FROM t1
   663    } {2 {} 2}
   664    do_execsql_test $tn3.9.4 { PRAGMA integrity_check } {ok}
   665  
   666    catch { db close }
   667    eval $destroy_vfs
   668  }
   669  
   670  
   671  finish_test
   672