CoolFace
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
hook.test1071 linesDownload Raw Back to test
1# 2004 Jan 142#3# The author disclaims copyright to this source code.  In place of4# 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# This file implements regression tests for TCL interface to the12# SQLite library. 13#14# The focus of the tests in this file is the  following interface:15#16#      sqlite_commit_hook    (tests hook-1..hook-3 inclusive)17#      sqlite_update_hook    (tests hook-4-*)18#      sqlite_rollback_hook  (tests hook-5.*)19#      sqlite_preupdate_hook  (tests hook-7..hook-12)20#21# $Id: hook.test,v 1.15 2009/04/07 14:14:23 danielk1977 Exp $22 23set testdir [file dirname $argv0]24source $testdir/tester.tcl25set ::testprefix hook26 27do_test hook-1.2 {28  db commit_hook29} {}30 31 32do_test hook-3.1 {33  set commit_cnt 034  proc commit_hook {} {35    incr ::commit_cnt36    return 037  }38  db commit_hook ::commit_hook39  db commit_hook40} {::commit_hook}41do_test hook-3.2 {42  set commit_cnt43} {0}44do_test hook-3.3 {45  execsql {46    CREATE TABLE t2(a,b);47  }48  set commit_cnt49} {1}50do_test hook-3.4 {51  execsql {52    INSERT INTO t2 VALUES(1,2);53    INSERT INTO t2 SELECT a+1, b+1 FROM t2;54    INSERT INTO t2 SELECT a+2, b+2 FROM t2;55  }56  set commit_cnt57} {4}58do_test hook-3.5 {59  set commit_cnt {}60  proc commit_hook {} {61    set ::commit_cnt [execsql {SELECT * FROM t2}]62    return 063  }64  execsql {65    INSERT INTO t2 VALUES(5,6);66  }67  set commit_cnt68} {1 2 2 3 3 4 4 5 5 6}69do_test hook-3.6 {70  set commit_cnt {}71  proc commit_hook {} {72    set ::commit_cnt [execsql {SELECT * FROM t2}] 73    return 174  }75  catchsql {76    INSERT INTO t2 VALUES(6,7);77  }78} {1 {constraint failed}}79verify_ex_errcode hook-3.6b SQLITE_CONSTRAINT_COMMITHOOK80do_test hook-3.7 {81  set ::commit_cnt82} {1 2 2 3 3 4 4 5 5 6 6 7}83do_test hook-3.8 {84  execsql {SELECT * FROM t2}85} {1 2 2 3 3 4 4 5 5 6}86 87# Test turnning off the commit hook88#89do_test hook-3.9 {90  db commit_hook {}91  set ::commit_cnt {}92  execsql {93    INSERT INTO t2 VALUES(7,8);94  }95  set ::commit_cnt96} {}97 98# Ticket #3564.99#100do_test hook-3.10 {101  forcedelete test2.db test2.db-journal102  sqlite3 db2 test2.db103  proc commit_hook {} {104    set y [db2 one {SELECT y FROM t3 WHERE y>10}]105    return [expr {$y>10}]106  }107  db2 eval {CREATE TABLE t3(x,y)}108  db2 commit_hook commit_hook109  catchsql {INSERT INTO t3 VALUES(1,2)} db2110  catchsql {INSERT INTO t3 VALUES(11,12)} db2111  catchsql {INSERT INTO t3 VALUES(3,4)} db2112  db2 eval {113    SELECT * FROM t3 ORDER BY x;114  }115} {1 2 3 4}116db2 close117 118 119#----------------------------------------------------------------------------120# Tests for the update-hook.121#122# 4.1.* - Very simple tests. Test that the update hook is invoked correctly 123#         for INSERT, DELETE and UPDATE statements, including DELETE 124#         statements with no WHERE clause.125# 4.2.* - Check that the update-hook is invoked for rows modified by trigger126#         bodies. Also that the database name is correctly reported when 127#         an attached database is modified.128# 4.3.* - Do some sorting, grouping, compound queries, population and 129#         depopulation of indices, to make sure the update-hook is not 130#         invoked incorrectly.131#132# EVIDENCE-OF: R-21999-45122 The sqlite3_update_hook() interface133# registers a callback function with the database connection identified134# by the first argument to be invoked whenever a row is updated,135# inserted or deleted in a rowid table.136 137# Simple tests138do_test hook-4.1.1a {139  catchsql {140    DROP TABLE t1;141  }142  unset -nocomplain ::update_hook143  set ::update_hook {}144  db update_hook [list lappend ::update_hook]145  #146  # EVIDENCE-OF: R-24531-54682 The update hook is not invoked when147  # internal system tables are modified (i.e. sqlite_sequence).148  #149  execsql {150    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);151    CREATE TABLE t1w(a INT PRIMARY KEY, b) WITHOUT ROWID;152  }153  set ::update_hook154} {}155do_test hook-4.1.1b {156  execsql {157    INSERT INTO t1 VALUES(1, 'one');158    INSERT INTO t1 VALUES(2, 'two');159    INSERT INTO t1 VALUES(3, 'three');160    INSERT INTO t1w SELECT * FROM t1;161  }162} {}163 164# EVIDENCE-OF: R-15506-57666 The second callback argument is one of165# SQLITE_INSERT, SQLITE_DELETE, or SQLITE_UPDATE, depending on the166# operation that caused the callback to be invoked.167#168# EVIDENCE-OF: R-29213-61195 The third and fourth arguments to the169# callback contain pointers to the database and table name containing170# the affected row.171#172# EVIDENCE-OF: R-30809-57812 The final callback parameter is the rowid173# of the row.174#175do_test hook-4.1.2 {176  set ::update_hook {}177  execsql {178    INSERT INTO t1 VALUES(4, 'four');179    DELETE FROM t1 WHERE b = 'two';180    UPDATE t1 SET b = '' WHERE a = 1 OR a = 3;181    DELETE FROM t1 WHERE 1; -- Avoid the truncate optimization (for now)182  }183  set ::update_hook184} [list \185    INSERT main t1 4 \186    DELETE main t1 2 \187    UPDATE main t1 1 \188    UPDATE main t1 3 \189    DELETE main t1 1 \190    DELETE main t1 3 \191    DELETE main t1 4 \192]193 194# EVIDENCE-OF: R-61808-14344 The sqlite3_update_hook() interface does195# not fire callbacks for changes to a WITHOUT ROWID table.196#197# EVIDENCE-OF: R-33257-44249 The update hook is not invoked when WITHOUT198# ROWID tables are modified.199#200do_test hook-4.1.2w {201  set ::update_hook {}202  execsql {203    INSERT INTO t1w VALUES(4, 'four');204    DELETE FROM t1w WHERE b = 'two';205    UPDATE t1w SET b = '' WHERE a = 1 OR a = 3;206    DELETE FROM t1w WHERE 1; -- Avoid the truncate optimization (for now)207  }208  set ::update_hook209} {}210 211ifcapable trigger {212  # Update hook is not invoked for changes to sqlite_master213  #214  do_test hook-4.1.3 {215    set ::update_hook {}216    execsql {217      CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN SELECT RAISE(IGNORE); END;218    }219    set ::update_hook220  } {}221  do_test hook-4.1.4 {222    set ::update_hook {}223    execsql {224      DROP TRIGGER r1;225    }226    set ::update_hook227  } {}228  229  set ::update_hook {}230  do_test hook-4.2.1 {231    catchsql {232      DROP TABLE t2;233    }234    execsql {235      CREATE TABLE t2(c INTEGER PRIMARY KEY, d);236      CREATE TRIGGER t1_trigger AFTER INSERT ON t1 BEGIN237        INSERT INTO t2 VALUES(new.a, new.b);238        UPDATE t2 SET d = d || ' via trigger' WHERE new.a = c;239        DELETE FROM t2 WHERE new.a = c;240      END;241    }242  } {}243  do_test hook-4.2.2 {244    execsql {245      INSERT INTO t1 VALUES(1, 'one');246      INSERT INTO t1 VALUES(2, 'two');247    }248    set ::update_hook249  } [list \250      INSERT main t1 1 \251      INSERT main t2 1 \252      UPDATE main t2 1 \253      DELETE main t2 1 \254      INSERT main t1 2 \255      INSERT main t2 2 \256      UPDATE main t2 2 \257      DELETE main t2 2 \258  ]259} else {260  execsql {261    INSERT INTO t1 VALUES(1, 'one');262    INSERT INTO t1 VALUES(2, 'two');263  }264}265 266# Update-hook + ATTACH267set ::update_hook {}268ifcapable attach {269  do_test hook-4.2.3 {270    forcedelete test2.db271    execsql {272      ATTACH 'test2.db' AS aux;273      CREATE TABLE aux.t3(a INTEGER PRIMARY KEY, b);274      INSERT INTO aux.t3 SELECT * FROM t1;275      UPDATE t3 SET b = 'two or so' WHERE a = 2;276      DELETE FROM t3 WHERE 1; -- Avoid the truncate optimization (for now)277    }278    set ::update_hook279  } [list \280      INSERT aux t3 1 \281      INSERT aux t3 2 \282      UPDATE aux t3 2 \283      DELETE aux t3 1 \284      DELETE aux t3 2 \285  ]286}287 288ifcapable trigger {289  execsql {290    DROP TRIGGER t1_trigger;291  }292}293 294# Test that other vdbe operations involving btree structures do not 295# incorrectly invoke the update-hook.296set ::update_hook {}297do_test hook-4.3.1 {298  execsql {299    CREATE INDEX t1_i ON t1(b);300    INSERT INTO t1 VALUES(3, 'three');301    UPDATE t1 SET b = '';302    DELETE FROM t1 WHERE a > 1;303  }304  set ::update_hook305} [list \306    INSERT main t1 3 \307    UPDATE main t1 1 \308    UPDATE main t1 2 \309    UPDATE main t1 3 \310    DELETE main t1 2 \311    DELETE main t1 3 \312]313set ::update_hook {}314ifcapable compound&&attach {315  do_test hook-4.3.2 {316    execsql {317      SELECT * FROM t1 UNION SELECT * FROM t3;318      SELECT * FROM t1 UNION ALL SELECT * FROM t3;319      SELECT * FROM t1 INTERSECT SELECT * FROM t3;320      SELECT * FROM t1 EXCEPT SELECT * FROM t3;321      SELECT * FROM t1 ORDER BY b;322      SELECT * FROM t1 GROUP BY b;323    }324    set ::update_hook325  } [list]326}327 328do_test hook-4.4 {329  execsql {330    CREATE TABLE t4(a UNIQUE, b);331    INSERT INTO t4 VALUES(1, 'a');332    INSERT INTO t4 VALUES(2, 'b');333  }334  set ::update_hook [list]335  execsql {336    REPLACE INTO t4 VALUES(1, 'c');337  }338  set ::update_hook339} [list INSERT main t4 3 ]340do_execsql_test hook-4.4.1 {341  SELECT * FROM t4 ORDER BY a;342} {1 c 2 b}343do_test hook-4.4.2 {344  set ::update_hook [list]345  execsql {346    PRAGMA recursive_triggers = on;347    REPLACE INTO t4 VALUES(1, 'd');348  }349  set ::update_hook350} [list INSERT main t4 4 ]351do_execsql_test hook-4.4.3 {352  SELECT * FROM t4 ORDER BY a;353} {1 d 2 b}354 355db update_hook {}356#357#----------------------------------------------------------------------------358 359#----------------------------------------------------------------------------360# Test the rollback-hook. The rollback-hook is a bit more complicated than361# either the commit or update hooks because a rollback can happen 362# explicitly (an sql ROLLBACK statement) or implicitly (a constraint or 363# error condition).364#365# hook-5.1.* - Test explicit rollbacks.366# hook-5.2.* - Test implicit rollbacks caused by constraint failure.367#368# hook-5.3.* - Test implicit rollbacks caused by IO errors.369# hook-5.4.* - Test implicit rollbacks caused by malloc() failure.370# hook-5.5.* - Test hot-journal rollbacks. Or should the rollback hook 371#              not be called for these?372#373 374do_test hook-5.0 {375  # Configure the rollback hook to increment global variable 376  # $::rollback_hook each time it is invoked.377  set ::rollback_hook 0378  db rollback_hook [list incr ::rollback_hook]379} {}380 381# Test explicit rollbacks. Not much can really go wrong here.382#383do_test hook-5.1.1 {384  set ::rollback_hook 0385  execsql {386    BEGIN;387    ROLLBACK;388  }389  set ::rollback_hook390} {1}391 392# Test implicit rollbacks caused by constraints.393#394do_test hook-5.2.1 {395  set ::rollback_hook 0396  catchsql {397    DROP TABLE t1;398    CREATE TABLE t1(a PRIMARY KEY, b);399    INSERT INTO t1 VALUES('one', 'I');400    INSERT INTO t1 VALUES('one', 'I');401  }402  set ::rollback_hook403} {1}404do_test hook-5.2.2 {405  # Check that the INSERT transaction above really was rolled back.406  execsql {407    SELECT count(*) FROM t1;408  }409} {1}410 411#412# End rollback-hook testing.413#----------------------------------------------------------------------------414 415#----------------------------------------------------------------------------416# Test that if a commit-hook returns non-zero (causing a rollback), the417# rollback-hook is invoked.418#419proc commit_hook {} {420  lappend ::hooks COMMIT421  return 1422}423proc rollback_hook {} {424  lappend ::hooks ROLLBACK425}426do_test hook-6.1 {427  set ::hooks [list]428  db commit_hook commit_hook429  db rollback_hook rollback_hook430  catchsql {431    BEGIN;432      INSERT INTO t1 VALUES('two', 'II');433    COMMIT;434  }435  execsql { SELECT * FROM t1 }436} {one I}437do_test hook-6.2 {438  set ::hooks439} {COMMIT ROLLBACK}440unset ::hooks441 442#----------------------------------------------------------------------------443# The following tests - hook-7.* - test the pre-update hook.444#445ifcapable !preupdate {446  finish_test447  return448}449#450# 7.1.1 - INSERT statement.451# 7.1.2 - INSERT INTO ... SELECT statement.452# 7.1.3 - REPLACE INTO ... (rowid conflict)453# 7.1.4 - REPLACE INTO ... (other index conflicts)454# 7.1.5 - REPLACE INTO ... (both rowid and other index conflicts)455#456# 7.2.1 - DELETE statement.457# 7.2.2 - DELETE statement that uses the truncate optimization.458#459# 7.3.1 - UPDATE statement.460# 7.3.2 - UPDATE statement that modifies the rowid.461# 7.3.3 - UPDATE OR REPLACE ... (rowid conflict).462# 7.3.4 - UPDATE OR REPLACE ... (other index conflicts)463# 7.3.4 - UPDATE OR REPLACE ... (both rowid and other index conflicts)464#465# 7.4.1 - Test that the pre-update-hook is invoked only once if a row being466#         deleted is removed by a BEFORE trigger.467#468# 7.4.2 - Test that the pre-update-hook is invoked if a BEFORE trigger 469#         removes a row being updated. In this case the update hook should470#         be invoked with SQLITE_INSERT as the opcode when inserting the471#         new version of the row.472#         473# TODO: Short records (those created before a column is added to a table 474#       using ALTER TABLE)475#476 477proc do_preupdate_test {tn sql x} {478  set X [list]479  foreach elem $x {lappend X $elem}480  uplevel do_test $tn [list "481    set ::preupdate \[list\]482    execsql { $sql }483    set ::preupdate484  "] [list $X]485}486 487proc preupdate_hook {args} {488  set type [lindex $args 0]489  eval lappend ::preupdate $args490  if {$type != "INSERT"} {491    set x [catch {db preupdate old [db preupdate count]}]492    if {!$x} {493      lappend "ERROR: sqlite3_preupdate_old() accepted an out-of-bounds\494               column index"495    }496    for {set i 0} {$i < [db preupdate count]} {incr i} {497      lappend ::preupdate [db preupdate old $i]498    }499  }500  if {$type != "DELETE"} {501    set x [catch {db preupdate new [db preupdate count]}]502    if {!$x} {503      lappend "ERROR: sqlite3_preupdate_old() accepted an out-of-bounds\504               column index"505    }506    for {set i 0} {$i < [db preupdate count]} {incr i} {507      set rc [catch { db preupdate new $i } v]508      lappend ::preupdate $v509    }510  }511}512 513db close514forcedelete test.db515sqlite3 db test.db516db preupdate hook preupdate_hook517 518# Set up a schema to use for tests 7.1.* to 7.3.*.519do_execsql_test 7.0 { 520  CREATE TABLE t1(a, b); 521  CREATE TABLE t2(x, y); 522  CREATE TABLE t3(i, j, UNIQUE(i));523 524  INSERT INTO t2 VALUES('a', 'b');525  INSERT INTO t2 VALUES('c', 'd');526 527  INSERT INTO t3 VALUES(4, 16);528  INSERT INTO t3 VALUES(5, 25);529  INSERT INTO t3 VALUES(6, 36);530} 531 532do_preupdate_test 7.1.1 {533  INSERT INTO t1 VALUES('x', 'y')534} {INSERT main t1 1 1  x y}535 536# 7.1.2.1 does not use the xfer optimization. 7.1.2.2 does.537do_preupdate_test 7.1.2.1 {538  INSERT INTO t1 SELECT y, x FROM t2;539} {INSERT main t1 2 2 b a   INSERT main t1 3 3 d c}540do_preupdate_test 7.1.2.2 {541  INSERT INTO t1 SELECT * FROM t2;542} {INSERT main t1 4 4 a b   INSERT main t1 5 5 c d}543 544do_preupdate_test 7.1.3 {545  REPLACE INTO t1(rowid, a, b) VALUES(1, 1, 1);546} {547  DELETE main t1 1 1   x y548  INSERT main t1 1 1   1 1549}550 551do_preupdate_test 7.1.4 {552  REPLACE INTO t3 VALUES(4, NULL);553} {554  DELETE main t3 1 1   4 16555  INSERT main t3 4 4   4 {}556}557 558do_preupdate_test 7.1.5 {559  REPLACE INTO t3(rowid, i, j) VALUES(2, 6, NULL);560} {561  DELETE main t3 2 2  5 25562  DELETE main t3 3 3  6 36563  INSERT main t3 2 2  6 {}564}565 566do_execsql_test 7.2.0 { SELECT rowid FROM t1 } {1 2 3 4 5}567 568do_preupdate_test 7.2.1 {569  DELETE FROM t1 WHERE rowid = 3570} {571  DELETE main t1 3 3  d c572}573do_preupdate_test 7.2.2 {574  DELETE FROM t1575} {576  DELETE main t1 1 1   1 1577  DELETE main t1 2 2   b a578  DELETE main t1 4 4   a b579  DELETE main t1 5 5   c d580}581 582do_execsql_test 7.3.0 { 583  DELETE FROM t1;584  DELETE FROM t2;585  DELETE FROM t3;586 587  INSERT INTO t2 VALUES('a', 'b');588  INSERT INTO t2 VALUES('c', 'd');589 590  INSERT INTO t3 VALUES(4, 16);591  INSERT INTO t3 VALUES(5, 25);592  INSERT INTO t3 VALUES(6, 36);593}594 595do_preupdate_test 7.3.1 {596  UPDATE t2 SET y = y||y;597} {598  UPDATE main t2 1 1   a b  a bb599  UPDATE main t2 2 2   c d  c dd600}601 602do_preupdate_test 7.3.2 {603  UPDATE t2 SET rowid = rowid-1;604} {605  UPDATE main t2 1 0   a bb  a bb606  UPDATE main t2 2 1   c dd  c dd607}608 609do_preupdate_test 7.3.3 {610  UPDATE OR REPLACE t2 SET rowid = 1 WHERE x = 'a'611} {612  DELETE main t2 1 1   c dd613  UPDATE main t2 0 1   a bb  a bb614}615 616do_preupdate_test 7.3.4.1 {617  UPDATE OR REPLACE t3 SET i = 5 WHERE i = 6618} {619  DELETE main t3 2 2   5 25620  UPDATE main t3 3 3   6 36  5 36621}622 623do_execsql_test 7.3.4.2 {624  INSERT INTO t3 VALUES(10, 100);625  SELECT rowid, * FROM t3;626} {1 4 16   3 5 36   4 10 100}627 628do_preupdate_test 7.3.5 {629  UPDATE OR REPLACE t3 SET rowid = 1, i = 5 WHERE j = 100;630} {631  DELETE main t3 1 1    4  16632  DELETE main t3 3 3    5  36633  UPDATE main t3 4 1   10 100  5 100634}635 636do_execsql_test 7.4.1.0 {637  CREATE TABLE t4(a, b);638  INSERT INTO t4 VALUES('a', 1);639  INSERT INTO t4 VALUES('b', 2);640  INSERT INTO t4 VALUES('c', 3);641 642  CREATE TRIGGER t4t BEFORE DELETE ON t4 BEGIN643    DELETE FROM t4 WHERE b = 1;644  END;645}646 647do_preupdate_test 7.4.1.1 {648  DELETE FROM t4 WHERE b = 3649} {650  DELETE main t4 1 1   a 1651  DELETE main t4 3 3   c 3652}653 654do_execsql_test 7.4.1.2 {655  INSERT INTO t4(rowid, a, b) VALUES(1, 'a', 1);656  INSERT INTO t4(rowid, a, b) VALUES(3, 'c', 3);657}658do_preupdate_test 7.4.1.3 {659  DELETE FROM t4 WHERE b = 1660} {661  DELETE main t4 1 1   a 1662}663 664do_execsql_test 7.4.2.0 {665  CREATE TABLE t5(a, b);666  INSERT INTO t5 VALUES('a', 1);667  INSERT INTO t5 VALUES('b', 2);668  INSERT INTO t5 VALUES('c', 3);669 670  CREATE TRIGGER t5t BEFORE UPDATE ON t5 BEGIN671    DELETE FROM t5 WHERE b = 1;672  END;673}674do_preupdate_test 7.4.2.1 {675  UPDATE t5 SET b = 4 WHERE a = 'c'676} {677  DELETE main t5 1 1   a 1678  UPDATE main t5 3 3   c 3  c 4679}680 681do_execsql_test 7.4.2.2 {682  INSERT INTO t5(rowid, a, b) VALUES(1, 'a', 1);683}684 685do_preupdate_test 7.4.2.3 {686  UPDATE t5 SET b = 5 WHERE a = 'a'687} {688  DELETE main t5 1 1   a 1689}690 691ifcapable altertable {692  do_execsql_test 7.5.1.0 {693    CREATE TABLE t7(a, b);694    INSERT INTO t7 VALUES('one', 'two');695    INSERT INTO t7 VALUES('three', 'four');696    ALTER TABLE t7 ADD COLUMN c DEFAULT NULL;697  }698  699  do_preupdate_test 7.5.1.1 {700    DELETE FROM t7 WHERE a = 'one'701  } {702    DELETE main t7 1 1   one two {}703  }704  705  do_preupdate_test 7.5.1.2 {706    UPDATE t7 SET b = 'five'707  } {708    UPDATE main t7 2 2   three four {}  three five {}709  }710  711  do_execsql_test 7.5.2.0 {712    CREATE TABLE t8(a, b);713    INSERT INTO t8 VALUES('one', 'two');714    INSERT INTO t8 VALUES('three', 'four');715    ALTER TABLE t8 ADD COLUMN c DEFAULT 'xxx';716  }717}718 719if 1 {720  # At time of writing, these two are broken. They demonstrate that the721  # sqlite3_preupdate_old() method does not handle the case where ALTER TABLE722  # has been used to add a column with a default value other than NULL.723  #724  # 2024-09-18: These are now fixed.725  #726  do_preupdate_test 7.5.2.1 {727    DELETE FROM t8 WHERE a = 'one'728  } {729    DELETE main t8 1 1   one two xxx730  }731  do_preupdate_test 7.5.2.2 {732    UPDATE t8 SET b = 'five'733  } {734    UPDATE main t8 2 2   three four xxx  three five xxx735  }736}737 738# This block of tests verifies that IPK values are correctly reported739# by the sqlite3_preupdate_old() and sqlite3_preupdate_new() functions.740#741do_execsql_test 7.6.1 { CREATE TABLE t9(a, b INTEGER PRIMARY KEY, c) }742do_preupdate_test 7.6.2 {743  INSERT INTO t9 VALUES(1, 2, 3);744  UPDATE t9 SET b = b+1, c = c+1;745  DELETE FROM t9 WHERE a = 1;746} {747  INSERT main t9 2 2   1 2 3748  UPDATE main t9 2 3   1 2 3   1 3 4749  DELETE main t9 3 3   1 3 4750}751 752#--------------------------------------------------------------------------753# Test that the sqlite3_preupdate_depth() API seems to work.754#755proc preupdate_hook {args} {756  set type [lindex $args 0]757  eval lappend ::preupdate $args758  eval lappend ::preupdate [db preupdate depth]759 760  if {$type != "INSERT"} {761    for {set i 0} {$i < [db preupdate count]} {incr i} {762      lappend ::preupdate [db preupdate old $i]763    }764  }765  if {$type != "DELETE"} {766    for {set i 0} {$i < [db preupdate count]} {incr i} {767      set rc [catch { db preupdate new $i } v]768      lappend ::preupdate $v769    }770  }771}772 773db close774forcedelete test.db775sqlite3 db test.db776db preupdate hook preupdate_hook777 778do_execsql_test 7.6.1 { 779  CREATE TABLE t1(x PRIMARY KEY);780  CREATE TABLE t2(x PRIMARY KEY);781  CREATE TABLE t3(x PRIMARY KEY);782  CREATE TABLE t4(x PRIMARY KEY);783 784  CREATE TRIGGER a AFTER INSERT ON t1 BEGIN INSERT INTO t2 VALUES(new.x); END;785  CREATE TRIGGER b AFTER INSERT ON t2 BEGIN INSERT INTO t3 VALUES(new.x); END;786  CREATE TRIGGER c AFTER INSERT ON t3 BEGIN INSERT INTO t4 VALUES(new.x); END;787 788  CREATE TRIGGER d AFTER UPDATE ON t1 BEGIN UPDATE t2 SET x = new.x; END;789  CREATE TRIGGER e AFTER UPDATE ON t2 BEGIN UPDATE t3 SET x = new.x; END;790  CREATE TRIGGER f AFTER UPDATE ON t3 BEGIN UPDATE t4 SET x = new.x; END;791 792  CREATE TRIGGER g AFTER DELETE ON t1 BEGIN DELETE FROM t2 WHERE 1; END;793  CREATE TRIGGER h AFTER DELETE ON t2 BEGIN DELETE FROM t3 WHERE 1; END;794  CREATE TRIGGER i AFTER DELETE ON t3 BEGIN DELETE FROM t4 WHERE 1; END;795}796 797do_preupdate_test 7.6.2 {798  INSERT INTO t1 VALUES('xyz');799} {800  INSERT main t1 1 1   0      xyz801  INSERT main t2 1 1   1      xyz802  INSERT main t3 1 1   2      xyz803  INSERT main t4 1 1   3      xyz804}805do_preupdate_test 7.6.3 {806  UPDATE t1 SET x = 'abc';807} {808  UPDATE main t1 1 1   0      xyz abc809  UPDATE main t2 1 1   1      xyz abc810  UPDATE main t3 1 1   2      xyz abc811  UPDATE main t4 1 1   3      xyz abc812}813do_preupdate_test 7.6.4 {814  DELETE FROM t1 WHERE 1;815} {816  DELETE main t1 1 1   0      abc817  DELETE main t2 1 1   1      abc818  DELETE main t3 1 1   2      abc819  DELETE main t4 1 1   3      abc820}821 822do_execsql_test 7.6.5 { 823  DROP TRIGGER a; DROP TRIGGER b; DROP TRIGGER c;824  DROP TRIGGER d; DROP TRIGGER e; DROP TRIGGER f;825  DROP TRIGGER g; DROP TRIGGER h; DROP TRIGGER i;826 827  CREATE TRIGGER a BEFORE INSERT ON t1 BEGIN INSERT INTO t2 VALUES(new.x); END;828  CREATE TRIGGER b BEFORE INSERT ON t2 BEGIN INSERT INTO t3 VALUES(new.x); END;829  CREATE TRIGGER c BEFORE INSERT ON t3 BEGIN INSERT INTO t4 VALUES(new.x); END;830 831  CREATE TRIGGER d BEFORE UPDATE ON t1 BEGIN UPDATE t2 SET x = new.x; END;832  CREATE TRIGGER e BEFORE UPDATE ON t2 BEGIN UPDATE t3 SET x = new.x; END;833  CREATE TRIGGER f BEFORE UPDATE ON t3 BEGIN UPDATE t4 SET x = new.x; END;834 835  CREATE TRIGGER g BEFORE DELETE ON t1 BEGIN DELETE FROM t2 WHERE 1; END;836  CREATE TRIGGER h BEFORE DELETE ON t2 BEGIN DELETE FROM t3 WHERE 1; END;837  CREATE TRIGGER i BEFORE DELETE ON t3 BEGIN DELETE FROM t4 WHERE 1; END;838}839 840do_preupdate_test 7.6.6 {841  INSERT INTO t1 VALUES('xyz');842} {843  INSERT main t4 1 1   3      xyz844  INSERT main t3 1 1   2      xyz845  INSERT main t2 1 1   1      xyz846  INSERT main t1 1 1   0      xyz847}848do_preupdate_test 7.6.3 {849  UPDATE t1 SET x = 'abc';850} {851  UPDATE main t4 1 1   3      xyz abc852  UPDATE main t3 1 1   2      xyz abc853  UPDATE main t2 1 1   1      xyz abc854  UPDATE main t1 1 1   0      xyz abc855}856do_preupdate_test 7.6.4 {857  DELETE FROM t1 WHERE 1;858} {859  DELETE main t4 1 1   3      abc860  DELETE main t3 1 1   2      abc861  DELETE main t2 1 1   1      abc862  DELETE main t1 1 1   0      abc863}864 865# No preupdate callbacks for modifying sqlite_master.866ifcapable altertable {867  do_preupdate_test 8.1 { CREATE TABLE x1(x, y); } { }868  do_preupdate_test 8.2 { ALTER TABLE x1 ADD COLUMN z } { }869  do_preupdate_test 8.3 { ALTER TABLE x1 RENAME TO y1 } { }870  do_preupdate_test 8.4 { CREATE INDEX y1x ON y1(x) } { }871  do_preupdate_test 8.5 { CREATE VIEW v1 AS SELECT * FROM y1 } { }872  do_preupdate_test 8.6 { DROP TABLE y1 } { }873}874 875#-------------------------------------------------------------------------876reset_db877db preupdate hook preupdate_hook878 879ifcapable altertable {880  do_execsql_test 9.0 {881    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);882    CREATE TABLE t2(a, b INTEGER PRIMARY KEY);883  }884  do_preupdate_test 9.1 {885    INSERT INTO t1 VALUES(456, NULL, NULL);886  } {887    INSERT main t1 456 456  0  456 {} {}888  }889  do_execsql_test 9.2 {890    ALTER TABLE t1 ADD COLUMN d;891  }892  do_preupdate_test 9.3 {893    INSERT INTO t1(a, b, c) VALUES(457, NULL, NULL);894  } {895    INSERT main t1 457 457  0  457 {} {} {}896  }897  do_preupdate_test 9.4 {898    DELETE FROM t1 WHERE a=456899  } {900    DELETE main t1 456 456  0  456 {} {} {}901  }902  do_preupdate_test 9.5 {903    INSERT INTO t2 DEFAULT VALUES;904  } {905    INSERT main t2 1 1  0  {} 1906  } 907  do_preupdate_test 9.6 {908    INSERT INTO t1 DEFAULT VALUES;909  } {910    INSERT main t1 458 458  0  458 {} {} {}911  } 912}913 914 915do_execsql_test 10.0 {916  CREATE TABLE t3(a, b INTEGER PRIMARY KEY);917}918do_preupdate_test 10.1 {919  INSERT INTO t3 DEFAULT VALUES920} {921  INSERT main t3 1 1 0 {} 1922}923do_execsql_test 10.2 { SELECT * FROM t3 } {{} 1}924do_preupdate_test 10.3 {925  DELETE FROM t3 WHERE b=1926} {DELETE main t3 1 1 0 {} 1}927 928#-------------------------------------------------------------------------929# Test that the "update" hook is not fired for operations on the 930# sqlite_stat1 table performed by ANALYZE, even if a pre-update hook is931# registered.932ifcapable analyze {933  reset_db934  do_execsql_test 11.1 {935    CREATE TABLE t1(a, b);936    CREATE INDEX idx1 ON t1(a);937    CREATE INDEX idx2 ON t1(b);938 939    INSERT INTO t1 VALUES(1, 2);940    INSERT INTO t1 VALUES(3, 4);941    INSERT INTO t1 VALUES(5, 6);942    INSERT INTO t1 VALUES(7, 8);943  }944 945  db preupdate hook preupdate_cb946  db update_hook update_cb947 948  proc preupdate_cb {args} { lappend ::res "preupdate" $args }949  proc update_cb {args} { lappend ::res "update" $args }950 951  set ::res [list]952  do_test 11.2 {953    execsql ANALYZE954    set ::res955  } [list {*}{956    preupdate {INSERT main sqlite_stat1 1 1}957    preupdate {INSERT main sqlite_stat1 2 2}958  }]959 960  do_execsql_test 11.3 {961    INSERT INTO t1 VALUES(9, 10);962    INSERT INTO t1 VALUES(11, 12);963    INSERT INTO t1 VALUES(13, 14);964    INSERT INTO t1 VALUES(15, 16);965  }966 967  set ::res [list]968  do_test 11.4 {969    execsql ANALYZE970    set ::res971  } [list {*}{972    preupdate {DELETE main sqlite_stat1 1 1}973    preupdate {DELETE main sqlite_stat1 2 2}974    preupdate {INSERT main sqlite_stat1 1 1}975    preupdate {INSERT main sqlite_stat1 2 2}976  }]977}978 979#-------------------------------------------------------------------------980# Test that the pre-update hook is fired for INSERT statements that use981# the xfer optimization on without rowid tables.982#983reset_db984do_execsql_test 12.1 {985  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);986  CREATE TABLE t2(a INTEGER PRIMARY KEY, b) WITHOUT ROWID;987 988  INSERT INTO t1 VALUES(1, 2);989  INSERT INTO t1 VALUES(3, 4);990  INSERT INTO t2 VALUES(5, 6);991  INSERT INTO t2 VALUES(7, 8);992 993  CREATE TABLE t3 (a INTEGER PRIMARY KEY, b) WITHOUT ROWID;994}995 996db preupdate hook preupdate_cb997db update_hook update_cb998 999proc preupdate_cb {args} { lappend ::res "preupdate" $args }1000proc update_cb {args} { lappend ::res "update" $args }1001 1002set ::res [list]1003do_test 12.2 {1004  execsql VACUUM1005  set ::res1006} {}1007 1008do_test 12.3 {1009  set ::res [list]1010  execsql { INSERT INTO t3 SELECT a, b FROM t2 }1011  set ::res1012} {preupdate {INSERT main t3 0 0} preupdate {INSERT main t3 0 0}}1013 1014do_test 12.4 {1015  execsql { DELETE FROM t3 }1016  set ::res [list]1017  execsql { INSERT INTO t3 SELECT * FROM t2 }1018  set ::res1019} {preupdate {INSERT main t3 0 0} preupdate {INSERT main t3 0 0}}1020 1021do_execsql_test 12.5 {1022  CREATE TABLE t4(a COLLATE nocase PRIMARY KEY, b) WITHOUT ROWID;1023  INSERT INTO t4 VALUES('abc', 1);1024  INSERT INTO t4 VALUES('DEF', 2);1025}1026 1027set ::res [list]1028do_test 12.6 {1029  execsql VACUUM1030  set ::res1031} {}1032 1033do_catchsql_test 12.6 {1034  INSERT INTO t4 VALUES('def', 3);1035} {1 {UNIQUE constraint failed: t4.a}}1036 1037#-------------------------------------------------------------------------1038# Test adding non-NULL default values using ALTER TABLE.1039#1040reset_db1041db preupdate hook preupdate_hook1042do_execsql_test 13.0 {1043  CREATE TABLE t1(a INTEGER PRIMARY KEY);1044  INSERT INTO t1 VALUES(100), (200), (300), (400);1045}1046 1047do_execsql_test 13.1 {1048  ALTER TABLE t1 ADD COLUMN b DEFAULT 1234;1049  ALTER TABLE t1 ADD COLUMN c DEFAULT 'abcdef';1050  ALTER TABLE t1 ADD COLUMN d DEFAULT NULL;1051}1052 1053do_preupdate_test 13.2 {1054  DELETE FROM t1 WHERE a=3001055} {DELETE main t1 300 300 0 300 1234 abcdef {}}1056 1057do_preupdate_test 13.3 {1058  UPDATE t1 SET d='hello world' WHERE a=2001059} {1060  UPDATE main t1 200 200 0 200 1234 abcdef {} 1061                           200 1234 abcdef {hello world}1062}1063 1064do_preupdate_test 13.4 {1065  INSERT INTO t1 DEFAULT VALUES;1066} {1067  INSERT main t1 401 401 0 401 1234 abcdef {}1068}1069 1070finish_test1071