CoolFace
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
alter2.test471 linesDownload Raw Back to test
1# 2005 February 182#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 SQLite library.  The12# focus of this script is testing that SQLite can handle a subtle 13# file format change that may be used in the future to implement14# "ALTER TABLE ... ADD COLUMN".15#16# $Id: alter2.test,v 1.14 2009/04/07 14:14:22 danielk1977 Exp $17#18 19set testdir [file dirname $argv0]20source $testdir/tester.tcl21 22# We have to have pragmas in order to do this test23ifcapable {!pragma} return24 25# Do not use a codec for tests in this file, as the database file is26# manipulated directly using tcl scripts. See proc [set_file_format].27#28do_not_use_codec29 30# The file format change affects the way row-records stored in tables (but 31# not indices) are interpreted. Before version 3.1.3, a row-record for a 32# table with N columns was guaranteed to contain exactly N fields. As33# of version 3.1.3, the record may contain up to N fields. In this case34# the M fields that are present are the values for the left-most M 35# columns. The (N-M) rightmost columns contain NULL.36#37# If any records in the database contain less fields than their table38# has columns, then the file-format meta value should be set to (at least) 2. 39#40 41# This procedure sets the value of the file-format in file 'test.db'42# to $newval. Also, the schema cookie is incremented.43# 44proc set_file_format {newval} {45  hexio_write test.db 44 [hexio_render_int32 $newval]46  set schemacookie [hexio_get_int [hexio_read test.db 40 4]]47  incr schemacookie48  hexio_write test.db 40 [hexio_render_int32 $schemacookie]49  return {}50}51 52# This procedure returns the value of the file-format in file 'test.db'.53# 54proc get_file_format {{fname test.db}} {55  return [hexio_get_int [hexio_read $fname 44 4]]56}57 58# This procedure sets the SQL statement stored for table $tbl in the59# sqlite_master table of file 'test.db' to $sql. Also set the file format60# to the supplied value. This is 2 if the added column has a default that is61# NULL, or 3 otherwise. 62#63proc alter_table {tbl sql {file_format 2}} {64  sqlite3 dbat test.db65  set s [string map {' ''} $sql]66  set t [string map {' ''} $tbl]67  sqlite3_db_config dbat DEFENSIVE 068  dbat eval [subst {69    PRAGMA writable_schema = 1;70    UPDATE sqlite_master SET sql = '$s' WHERE name = '$t' AND type = 'table';71    PRAGMA writable_schema = 0;72  }]73  dbat close74  set_file_format 275}76 77# Create bogus application-defined functions for functions used 78# internally by ALTER TABLE, to ensure that ALTER TABLE falls back79# to the built-in functions.80#81proc failing_app_func {args} {error "bad function"}82do_test alter2-1.0 {83  db func substr failing_app_func84  db func like failing_app_func85  db func sqlite_rename_table failing_app_func86  db func sqlite_rename_trigger failing_app_func87  db func sqlite_rename_parent failing_app_func88  catchsql {SELECT substr('abcdefg',1,3)}89} {1 {bad function}}90 91 92#-----------------------------------------------------------------------93# Some basic tests to make sure short rows are handled.94#95sqlite3_db_config db DEFENSIVE 096do_test alter2-1.1 {97  execsql {98    CREATE TABLE abc(a, b);99    INSERT INTO abc VALUES(1, 2);100    INSERT INTO abc VALUES(3, 4);101    INSERT INTO abc VALUES(5, 6);102  }103} {}104do_test alter2-1.2 {105  # ALTER TABLE abc ADD COLUMN c;106  alter_table abc {CREATE TABLE abc(a, b, c);}107} {}108do_test alter2-1.3 {109  execsql {110    SELECT * FROM abc;111  }112} {1 2 {} 3 4 {} 5 6 {}}113do_test alter2-1.4 {114  execsql {115    UPDATE abc SET c = 10 WHERE a = 1;116    SELECT * FROM abc;117  }118} {1 2 10 3 4 {} 5 6 {}}119do_test alter2-1.5 {120  execsql {121    CREATE INDEX abc_i ON abc(c);122  }123} {}124do_test alter2-1.6 {125  execsql {126    SELECT c FROM abc ORDER BY c;127  }128} {{} {} 10}129do_test alter2-1.7 {130  execsql {131    SELECT * FROM abc WHERE c = 10;132  }133} {1 2 10}134do_test alter2-1.8 {135  execsql {136    SELECT sum(a), c FROM abc GROUP BY c;137  }138} {8 {} 1 10}139do_test alter2-1.9 {140  # ALTER TABLE abc ADD COLUMN d;141  alter_table abc {CREATE TABLE abc(a, b, c, d);}142  if {[permutation] == "prepare"} { db cache flush }143  execsql { SELECT * FROM abc; }144  execsql {145    UPDATE abc SET d = 11 WHERE c IS NULL AND a<4;146    SELECT * FROM abc;147  }148} {1 2 10 {} 3 4 {} 11 5 6 {} {}}149do_test alter2-1.10 {150  execsql {151    SELECT typeof(d) FROM abc;152  }153} {null integer null}154do_test alter2-1.99 {155  execsql {156    DROP TABLE abc;157  }158} {}159 160#-----------------------------------------------------------------------161# Test that views work when the underlying table structure is changed.162#163ifcapable view {164  do_test alter2-2.1 {165    execsql {166      CREATE TABLE abc2(a, b, c);167      INSERT INTO abc2 VALUES(1, 2, 10);168      INSERT INTO abc2 VALUES(3, 4, NULL);169      INSERT INTO abc2 VALUES(5, 6, NULL);170      CREATE VIEW abc2_v AS SELECT * FROM abc2;171      SELECT * FROM abc2_v;172    }173  } {1 2 10 3 4 {} 5 6 {}}174  do_test alter2-2.2 {175    # ALTER TABLE abc ADD COLUMN d;176    alter_table abc2 {CREATE TABLE abc2(a, b, c, d);}177    execsql {178      SELECT * FROM abc2_v;179    }180  } {1 2 10 {} 3 4 {} {} 5 6 {} {}}181  do_test alter2-2.3 {182    execsql {183      DROP TABLE abc2;184      DROP VIEW abc2_v;185    }186  } {}187}188 189#-----------------------------------------------------------------------190# Test that triggers work when a short row is copied to the old.*191# trigger pseudo-table.192#193ifcapable trigger {194  do_test alter2-3.1 {195    execsql {196      CREATE TABLE abc3(a, b);197      CREATE TABLE blog(o, n);198      CREATE TRIGGER abc3_t AFTER UPDATE OF b ON abc3 BEGIN199        INSERT INTO blog VALUES(old.b, new.b);200      END;201    }202  } {}203  do_test alter2-3.2 {204    execsql {205      INSERT INTO abc3 VALUES(1, 4);206      UPDATE abc3 SET b = 2 WHERE b = 4;207      SELECT * FROM blog;208    }209  } {4 2}210  do_test alter2-3.3 {211    execsql {212      INSERT INTO abc3 VALUES(3, 4);213      INSERT INTO abc3 VALUES(5, 6);214    }215    alter_table abc3 {CREATE TABLE abc3(a, b, c);}216    execsql {217      SELECT * FROM abc3;218    }219  } {1 2 {} 3 4 {} 5 6 {}}220  do_test alter2-3.4 {221    execsql {222      UPDATE abc3 SET b = b*2 WHERE a<4;223      SELECT * FROM abc3;224    }225  } {1 4 {} 3 8 {} 5 6 {}}226  do_test alter2-3.5 {227    execsql {228      SELECT * FROM blog;229    }230  } {4 2 2 4 4 8}231 232  do_test alter2-3.6 {233    execsql {234      CREATE TABLE clog(o, n);235      CREATE TRIGGER abc3_t2 AFTER UPDATE OF c ON abc3 BEGIN236        INSERT INTO clog VALUES(old.c, new.c);237      END;238      UPDATE abc3 SET c = a*2;239      SELECT * FROM clog;240    }241  } {{} 2 {} 6 {} 10}242} else {243  execsql { CREATE TABLE abc3(a, b); }244}245 246#---------------------------------------------------------------------247# Check that an error occurs if the database is upgraded to a file248# format that SQLite does not support (in this case 5). Note: The 249# file format is checked each time the schema is read, so changing the250# file format requires incrementing the schema cookie.251#252do_test alter2-4.1 {253  db close254  set_file_format 5255  catch { sqlite3 db test.db }256  set {} {}257} {}258do_test alter2-4.2 {259  # We have to run two queries here because the Tcl interface uses260  # sqlite3_prepare_v2(). In this case, the first query encounters an 261  # SQLITE_SCHEMA error. Then, when trying to recompile the statement, the262  # "unsupported file format" error is encountered. So the error code263  # returned is SQLITE_SCHEMA, not SQLITE_ERROR as required by the following264  # test case.265  #266  # When the query is attempted a second time, the same error message is267  # returned but the error code is SQLITE_ERROR, because the unsupported268  # file format was detected during a call to sqlite3_prepare(), not269  # sqlite3_step().270  #271  catchsql { SELECT * FROM sqlite_master; }272  catchsql { SELECT * FROM sqlite_master; }273} {1 {unsupported file format}}274do_test alter2-4.3 {275  sqlite3_errcode db276} {SQLITE_ERROR}277do_test alter2-4.4 {278  set ::DB [sqlite3_connection_pointer db]279  catchsql {280    SELECT * FROM sqlite_master;281  }282} {1 {unsupported file format}}283do_test alter2-4.5 {284  sqlite3_errcode db285} {SQLITE_ERROR}286 287#---------------------------------------------------------------------288# Check that executing VACUUM on a file with file-format version 2289# resets the file format to 1.290#291set default_file_format [expr $SQLITE_DEFAULT_FILE_FORMAT==4 ? 4 : 1]292ifcapable vacuum {293  do_test alter2-5.1 {294    set_file_format 2295    db close296    sqlite3 db test.db297    execsql {SELECT 1 FROM sqlite_master LIMIT 1;}298    get_file_format299  } {2}300  do_test alter2-5.2 {301    execsql { VACUUM }302  } {}303  do_test alter2-5.3 {304    get_file_format305  } $default_file_format306}307 308#---------------------------------------------------------------------309# Test that when a database with file-format 2 is opened, new 310# databases are still created with file-format 1.311#312do_test alter2-6.1 {313  db close314  set_file_format 2315  sqlite3 db test.db316  get_file_format317} {2}318ifcapable attach {319  do_test alter2-6.2 {320    forcedelete test2.db-journal321    forcedelete test2.db322    execsql {323      ATTACH 'test2.db' AS aux;324      CREATE TABLE aux.t1(a, b);325    }326    get_file_format test2.db327  } $default_file_format328}329do_test alter2-6.3 {330  execsql {331    CREATE TABLE t1(a, b);332  }333  get_file_format 334} {2}335 336#---------------------------------------------------------------------337# Test that types and values for columns added with default values 338# other than NULL work with SELECT statements.339#340do_test alter2-7.1 {341  execsql {342    DROP TABLE t1;343    CREATE TABLE t1(a);344    INSERT INTO t1 VALUES(1);345    INSERT INTO t1 VALUES(2);346    INSERT INTO t1 VALUES(3);347    INSERT INTO t1 VALUES(4);348    SELECT * FROM t1;349  }350} {1 2 3 4}351do_test alter2-7.2 {352  set sql {CREATE TABLE t1(a, b DEFAULT '123', c INTEGER DEFAULT '123')}353  alter_table t1 $sql 3354  execsql {355    SELECT * FROM t1 LIMIT 1;356  }357} {1 123 123}358do_test alter2-7.3 {359  execsql {360    SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1;361  }362} {1 integer 123 text 123 integer}363do_test alter2-7.4 {364  execsql {365    SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1;366  }367} {1 integer 123 text 123 integer}368do_test alter2-7.5 {369  set sql {CREATE TABLE t1(a, b DEFAULT -123.0, c VARCHAR(10) default 5)}370  alter_table t1 $sql 3371  execsql {372    SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1;373  }374} {1 integer -123.0 real 5 text}375 376#-----------------------------------------------------------------------377# Test that UPDATE trigger tables work with default values, and that when378# a row is updated the default values are correctly transfered to the 379# new row.380# 381ifcapable trigger {382db function set_val {set ::val}383  do_test alter2-8.1 {384    execsql {385      CREATE TRIGGER trig1 BEFORE UPDATE ON t1 BEGIN386      SELECT set_val(387          old.b||' '||typeof(old.b)||' '||old.c||' '||typeof(old.c)||' '||388          new.b||' '||typeof(new.b)||' '||new.c||' '||typeof(new.c) 389      );390      END;391    }392    list393  } {}394}395do_test alter2-8.2 {396  execsql {397    UPDATE t1 SET c = 10 WHERE a = 1;398    SELECT a, typeof(a), b, typeof(b), c, typeof(c) FROM t1 LIMIT 1;399  }400} {1 integer -123.0 real 10 text}401ifcapable trigger {402  do_test alter2-8.3 {403    set ::val404  } {-123.0 real 5 text -123.0 real 10 text}405}406 407#-----------------------------------------------------------------------408# Test that DELETE trigger tables work with default values, and that when409# a row is updated the default values are correctly transfered to the 410# new row.411# 412ifcapable trigger {413  do_test alter2-9.1 {414    execsql {415      CREATE TRIGGER trig2 BEFORE DELETE ON t1 BEGIN416      SELECT set_val(417          old.b||' '||typeof(old.b)||' '||old.c||' '||typeof(old.c)418      );419      END;420    }421    list422  } {}423  do_test alter2-9.2 {424    execsql {425      DELETE FROM t1 WHERE a = 2;426    }427    set ::val428  } {-123.0 real 5 text}429}430 431#-----------------------------------------------------------------------432# Test creating an index on a column added with a default value. 433#434ifcapable bloblit {435  do_test alter2-10.1 {436    execsql {437      CREATE TABLE t2(a);438      INSERT INTO t2 VALUES('a');439      INSERT INTO t2 VALUES('b');440      INSERT INTO t2 VALUES('c');441      INSERT INTO t2 VALUES('d');442    }443    alter_table t2 {CREATE TABLE t2(a, b DEFAULT X'ABCD', c DEFAULT NULL);} 3444    catchsql {445      SELECT * FROM sqlite_master;446    }447    execsql {448      SELECT quote(a), quote(b), quote(c) FROM t2 LIMIT 1;449    }450  } {'a' X'ABCD' NULL}451  do_test alter2-10.2 {452    execsql {453      CREATE INDEX i1 ON t2(b);454      SELECT a FROM t2 WHERE b = X'ABCD';455    }456  } {a b c d}457  do_test alter2-10.3 {458    execsql {459      DELETE FROM t2 WHERE a = 'c';460      SELECT a FROM t2 WHERE b = X'ABCD';461    }462  } {a b d}463  do_test alter2-10.4 {464    execsql {465      SELECT count(b) FROM t2 WHERE b = X'ABCD';466    }467  } {3}468}469 470finish_test471