From 36963fdca81850a2f9e5a0bc808c70872859ba39 Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Sat, 19 Feb 2005 08:18:05 +0000 Subject: [PATCH] Support for a future file format that includes 'short' records. (CVS 2351) FossilOrigin-Name: 173aeb256e2c09098a4392874f8623e8a760d951 --- manifest | 21 ++-- manifest.uuid | 2 +- src/build.c | 12 +- src/main.c | 17 ++- src/vdbe.c | 47 +++++--- test/alter2.test | 292 ++++++++++++++++++++++++++++++++++++++++++++++ test/capi3.test | 4 +- test/corrupt.test | 26 ++--- 8 files changed, 374 insertions(+), 47 deletions(-) create mode 100644 test/alter2.test diff --git a/manifest b/manifest index c0c7be21f9..71d7beed72 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stypos\sin\sdocumentation\sfor\spragma\sshort_column_names.\sTicket\s#1130.\s(CVS\s2350) -D 2005-02-18T01:15:23 +C Support\sfor\sa\sfuture\sfile\sformat\sthat\sincludes\s'short'\srecords.\s(CVS\s2351) +D 2005-02-19T08:18:06 F Makefile.in 76443a83549d1539105e12d13bd0054a05ab2214 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -32,7 +32,7 @@ F src/attach.c f78f76bc6a8e5e487ca53636e21ccba2484a9a61 F src/auth.c 18c5a0befe20f3a58a41e3ddd78f372faeeefe1f F src/btree.c 5c6e81855deec3d1eac5ae03e4c8db6c2595421f F src/btree.h 2e2cc923224649337d7217df0dd32b06673ca180 -F src/build.c 7db7f593093caeb223c849a0fd7ca428dcda631e +F src/build.c a8792b2f866c1ccc32f4977f4ff61d787d60ddfb F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f F src/delete.c 4b94395b52a8f7785acd71135c2ce54f3f5550b3 F src/experimental.c 8cc66b2be6a011055d75ef19ed2584bcfbb585ad @@ -42,7 +42,7 @@ F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/insert.c 0456649d4d48396f918e7ea1fecbf3d66ed90816 F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b -F src/main.c 981099f5f73a71e54b0858b01e03d29b83168f7b +F src/main.c 9f0716fcee245c275a04b42c778c921483dcf868 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070 F src/os.h ae44064dc118b20d39450cb331409a775e8bb1c6 F src/os_common.h 0e7f428ba0a6c40a61bc56c4e96f493231301b73 @@ -75,7 +75,7 @@ F src/update.c b6f4668c11059f86b71581187d09197fa28ec4be F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c F src/util.c 1b7b9a127b66743ab6cba8d44597aeb570723c99 F src/vacuum.c 5cf598003191bd91c17a64742bad8e46241698a8 -F src/vdbe.c 40de3ba927a8a99b582d9cd554a2f9eca1c7a025 +F src/vdbe.c 26b085c3a64a8d7a50f9a4ef116481b6afce80b9 F src/vdbe.h bb9186484f749a839c6c43953e79a6530253f7cd F src/vdbeInt.h e80721cd8ff611789e20743eec43363a9fb5a48e F src/vdbeapi.c 467caa6e6fb9247528b1c7ab9132ae1b4748e8ac @@ -85,6 +85,7 @@ F src/where.c c4b6a799ed9cc99c63d298c8741956156eeb05eb F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3 F test/alter.test 3a20ce14c3989f7e2e75da50797065c2e56f838b +F test/alter2.test cd4204a4f5e11c5abfe8abbdf880538c994f3b47 F test/attach.test 5147d531ca5fc5c2539fd20ce3b07a00420e1fbb F test/attach2.test 6f3a3a3a7f5be40388dd4d805e0e0712718dca9d F test/attach3.test c05c70b933afbde0901dab9da3e66ee842c09f38 @@ -105,7 +106,7 @@ F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2 F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027 F test/btree7.test a6d3b842db22af97dd14b989e90a2fd96066b72f F test/capi2.test 2bd71f573b32e3ac5b97441a55873eae14eeab0d -F test/capi3.test f50dd4666deba96275f9927fe8ec089a3d8c0efa +F test/capi3.test 39143488ac6aeddb35fa76557d0a25f54081cebc F test/capi3b.test 5b6a66f9f295f79f443b5d3f33187fa5ef6cf336 F test/collate1.test f79736d2ebf5492167ee4d1f4ab4c09dda776b03 F test/collate2.test 224a632ba04907c049804b08162efd234aa7871f @@ -114,7 +115,7 @@ F test/collate4.test b8668612691c4dcf90f67a8df1eeb1544e7fdaf8 F test/collate5.test 581775b94604b7435dc6a5c6e72fbbf7d69e3830 F test/collate6.test 6c9470d1606ee3e564675b229653e320c49ec638 F test/conflict.test c5b849b01cfbe0a4f63a90cba6f68e2fe3a75f87 -F test/corrupt.test c34304baf2f027e05942af2efeb26844adca9a53 +F test/corrupt.test 18c7a995b1af76a8c8600b996257f2c7b7bff083 F test/corrupt2.test 88342570828f2b8cbbd8369eff3891f5c0bdd5ba F test/crash.test f38b980a0508655d08c957a6dd27d66bca776504 F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 @@ -273,7 +274,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl 3e522a06ad41992023c80ca29a048ae2331ca5bd -P c5366deaf5beca9c99558c0f375ba73f817acd92 -R b75a67c7136a5c5600c1249b41513257 +P fac56fa1e06e15ffd738cb9b780d422a73a743ae +R 9d7f7d2d11da73519486c2d9ff0d66a6 U danielk1977 -Z 6cb6073f29d2f0c0fa8b11d17ae22e19 +Z 26acc87d20c627eefd55cc96ad30a1f6 diff --git a/manifest.uuid b/manifest.uuid index 74cb36cc54..5cdf5a7dff 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fac56fa1e06e15ffd738cb9b780d422a73a743ae \ No newline at end of file +173aeb256e2c09098a4392874f8623e8a760d951 \ No newline at end of file diff --git a/src/build.c b/src/build.c index e8412d1a21..594674564d 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.311 2005/02/15 20:47:57 drh Exp $ +** $Id: build.c,v 1.312 2005/02/19 08:18:06 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -746,16 +746,20 @@ void sqlite3StartTable( ** now. */ if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){ + int lbl; sqlite3BeginWriteOperation(pParse, 0, iDb); - /* Every time a new table is created the file-format - ** and encoding meta-values are set in the database, in - ** case this is the first table created. + /* If the file format and encoding in the database have not been set, + ** set them now. */ + sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); /* file_format */ + lbl = sqlite3VdbeMakeLabel(v); + sqlite3VdbeAddOp(v, OP_If, 0, lbl); sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4); + sqlite3VdbeResolveLabel(v, lbl); /* This just creates a place-holder record in the sqlite_master table. ** The record created does not contain anything yet. It will be replaced diff --git a/src/main.c b/src/main.c index d36777df9c..5a3f26cf06 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.280 2005/02/06 02:45:42 drh Exp $ +** $Id: main.c,v 1.281 2005/02/19 08:18:06 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -257,12 +257,23 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ /* This happens if the database was initially empty */ db->file_format = 1; } + + if( db->file_format==2 ){ + /* File format 2 is treated exactly as file format 1. New + ** databases are created with file format 1. + */ + db->file_format = 1; + } } /* - ** file_format==1 Version 3.0.0. + ** file_format==1 Version 3.0.0. + ** file_format==2 Version 3.1.3. + ** + ** Version 3.0 can only use files with file_format==1. Version 3.1.3 + ** can read and write files with file_format==1 or file_format==2. */ - if( meta[1]>1 ){ + if( meta[1]>2 ){ sqlite3BtreeCloseCursor(curMain); sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0); return SQLITE_ERROR; diff --git a/src/vdbe.c b/src/vdbe.c index 9f5dbfa2aa..6b52ff79f1 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.455 2005/02/17 00:03:07 drh Exp $ +** $Id: vdbe.c,v 1.456 2005/02/19 08:18:06 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -1682,7 +1682,8 @@ case OP_SetNumColumns: { ** Interpret the data that cursor P1 points to as a structure built using ** the MakeRecord instruction. (See the MakeRecord opcode for additional ** information about the format of the data.) Push onto the stack the value -** of the P2-th column contained in the data. +** of the P2-th column contained in the data. If there are less that (P2+1) +** values in the record, push a NULL onto the stack. ** ** If the KeyAsData opcode has previously executed on this cursor, then the ** field might be extracted from the key rather than the data. @@ -1850,6 +1851,7 @@ case OP_Column: { ** of the record to the start of the data for the i-th column */ offset = szHdr; + assert( offset>0 ); i = 0; while( idxkeyAsData, &sMem); - if( rc!=SQLITE_OK ){ - goto op_column_out; + if( aOffset[p2] ){ + assert( rc==SQLITE_OK ); + if( zRec ){ + zData = &zRec[aOffset[p2]]; + }else{ + len = sqlite3VdbeSerialTypeLen(aType[p2]); + rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len,pC->keyAsData,&sMem); + if( rc!=SQLITE_OK ){ + goto op_column_out; + } + zData = sMem.z; } - zData = sMem.z; + sqlite3VdbeSerialGet(zData, aType[p2], pTos); + pTos->enc = db->enc; + }else{ + pTos->flags = MEM_Null; } - sqlite3VdbeSerialGet(zData, aType[p2], pTos); - pTos->enc = db->enc; /* If we dynamically allocated space to hold the data (in the ** sqlite3VdbeMemFromBtree() call above) then transfer control of that diff --git a/test/alter2.test b/test/alter2.test new file mode 100644 index 0000000000..1582222e5a --- /dev/null +++ b/test/alter2.test @@ -0,0 +1,292 @@ +# 2005 February 18 +# +# 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 implements regression tests for SQLite library. The +# focus of this script is testing that SQLite can handle a subtle +# file format change that may be used in the future to implement +# "ALTER TABLE ... ADD COLUMN". +# +# $Id: alter2.test,v 1.1 2005/02/19 08:18:06 danielk1977 Exp $ +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# The file format change affects the way row-records stored in tables (but +# not indices) are interpreted. Before version 3.1.3, a row-record for a +# table with N columns was guaranteed to contain exactly N fields. As +# of version 3.1.3, the record may contain up to N fields. In this case +# the M fields that are present are the values for the left-most M +# columns. The (N-M) rightmost columns contain NULL. +# +# If any records in the database contain less fields than their table +# has columns, then the file-format meta value should be set to (at least) 2. +# + +# This procedure sets the value of the file-format in file 'test.db' +# to $newval. Also, the schema cookie is incremented. +# +proc set_file_format {newval} { + set bt [btree_open test.db 10 0] + btree_begin_transaction $bt + set meta [btree_get_meta $bt] + lset meta 2 $newval ;# File format + lset meta 1 [expr [lindex $meta 1]+1] ;# Schema cookie + eval "btree_update_meta $bt $meta" + btree_commit $bt + btree_close $bt +} + +# This procedure returns the value of the file-format in file 'test.db'. +# +proc get_file_format {{fname test.db}} { + set bt [btree_open $fname 10 0] + set meta [btree_get_meta $bt] + btree_close $bt + lindex $meta 2 +} + +# This procedure sets the SQL statement stored for table $tbl in the +# sqlite_master table of file 'test.db' to $sql. +# +proc alter_table {tbl sql} { + sqlite3 dbat test.db + dbat eval { + PRAGMA writable_schema = 1; + UPDATE sqlite_master SET sql = $sql WHERE name = $tbl AND type = 'table'; + PRAGMA writable_schema = 0; + } + dbat close + set_file_format 2 +} + +#----------------------------------------------------------------------- +# 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); + } +} {} +do_test alter2-1.2 { + # ALTER TABLE abc ADD COLUMN c; + alter_table abc {CREATE TABLE abc(a, b, c);} +} {} +do_test alter2-1.3 { + execsql { + SELECT * FROM abc; + } +} {1 2 {} 3 4 {} 5 6 {}} +do_test alter2-1.4 { + execsql { + UPDATE abc SET c = 10 WHERE a = 1; + SELECT * FROM abc; + } +} {1 2 10 3 4 {} 5 6 {}} +do_test alter2-1.5 { + execsql { + CREATE INDEX abc_i ON abc(c); + } +} {} +do_test alter2-1.6 { + execsql { + SELECT c FROM abc ORDER BY c; + } +} {{} {} 10} +do_test alter2-1.7 { + execsql { + SELECT * FROM abc WHERE c = 10; + } +} {1 2 10} +do_test alter2-1.8 { + execsql { + SELECT sum(a), c FROM abc GROUP BY c; + } +} {8.0 {} 1.0 10} +do_test alter2-1.9 { + # ALTER TABLE abc ADD COLUMN d; + alter_table abc {CREATE TABLE abc(a, b, c, d);} + execsql { SELECT * FROM abc; } + execsql { + UPDATE abc SET d = 11 WHERE c IS NULL AND a<4; + SELECT * FROM abc; + } +} {1 2 10 {} 3 4 {} 11 5 6 {} {}} +do_test alter2-1.10 { + execsql { + SELECT typeof(d) FROM abc; + } +} {null integer null} +do_test alter2-1.99 { + execsql { + DROP TABLE abc; + } +} {} + +#----------------------------------------------------------------------- +# Test that views work when the underlying table structure is changed. +# +ifcapable view { + do_test alter2-2.1 { + execsql { + CREATE TABLE abc2(a, b, c); + INSERT INTO abc2 VALUES(1, 2, 10); + INSERT INTO abc2 VALUES(3, 4, NULL); + INSERT INTO abc2 VALUES(5, 6, NULL); + CREATE VIEW abc2_v AS SELECT * FROM abc2; + SELECT * FROM abc2_v; + } + } {1 2 10 3 4 {} 5 6 {}} + do_test alter2-2.2 { + # ALTER TABLE abc ADD COLUMN d; + alter_table abc2 {CREATE TABLE abc2(a, b, c, d);} + execsql { + SELECT * FROM abc2_v; + } + } {1 2 10 {} 3 4 {} {} 5 6 {} {}} + do_test alter2-2.3 { + execsql { + DROP TABLE abc2; + DROP VIEW abc2_v; + } + } {} +} + +#----------------------------------------------------------------------- +# Test that triggers work when a short row is copied to the old.* +# trigger pseudo-table. +# +ifcapable trigger { + do_test alter2-3.1 { + execsql { + CREATE TABLE abc3(a, b); + CREATE TABLE blog(o, n); + CREATE TRIGGER abc3_t AFTER UPDATE OF b ON abc3 BEGIN + INSERT INTO blog VALUES(old.b, new.b); + END; + } + } {} + do_test alter2-3.2 { + execsql { + INSERT INTO abc3 VALUES(1, 4); + UPDATE abc3 SET b = 2 WHERE b = 4; + SELECT * FROM blog; + } + } {4 2} + do_test alter2-3.3 { + execsql { + INSERT INTO abc3 VALUES(3, 4); + INSERT INTO abc3 VALUES(5, 6); + } + alter_table abc3 {CREATE TABLE abc3(a, b, c);} + execsql { + SELECT * FROM abc3; + } + } {1 2 {} 3 4 {} 5 6 {}} + do_test alter2-3.4 { + execsql { + UPDATE abc3 SET b = b*2 WHERE a<4; + SELECT * FROM abc3; + } + } {1 4 {} 3 8 {} 5 6 {}} + do_test alter2-3.5 { + execsql { + SELECT * FROM blog; + } + } {4 2 2 4 4 8} + + do_test alter2-3.6 { + execsql { + CREATE TABLE clog(o, n); + CREATE TRIGGER abc3_t2 AFTER UPDATE OF c ON abc3 BEGIN + INSERT INTO clog VALUES(old.c, new.c); + END; + UPDATE abc3 SET c = a*2; + SELECT * FROM clog; + } + } {{} 2 {} 6 {} 10} +} + +#--------------------------------------------------------------------- +# Check that an error occurs if the database is upgraded to a file +# format that SQLite does not support (in this case 3). Note: The +# file format is checked each time the schema is read, so changing the +# file format requires incrementing the schema cookie. +# +do_test alter2-4.1 { + set_file_format 3 +} {} +do_test alter2-4.2 { + catchsql { + SELECT * FROM sqlite_master; + } +} {1 {unsupported file format}} +do_test alter2-4.3 { + sqlite3_errcode $::DB +} {SQLITE_ERROR} +do_test alter2-4.4 { + db close + set ::DB [sqlite3 db test.db] + catchsql { + SELECT * FROM sqlite_master; + } +} {1 {unsupported file format}} +do_test alter2-4.5 { + sqlite3_errcode $::DB +} {SQLITE_ERROR} + +#--------------------------------------------------------------------- +# Check that executing VACUUM on a file with file-format version 2 +# resets the file format to 1. +# +do_test alter2-5.1 { + set_file_format 2 + get_file_format +} {2} +do_test alter2-5.2 { + execsql { + VACUUM; + } +} {} +do_test alter2-5.3 { + get_file_format +} {1} + +#--------------------------------------------------------------------- +# Test that when a database with file-format 2 is opened, new +# databases are still created with file-format 1. +# +do_test alter2-6.1 { + db close + set_file_format 2 + set ::DB [sqlite3 db test.db] + get_file_format +} {2} +do_test alter2-6.2 { + file delete -force test2.db-journal + file delete -force test2.db + execsql { + ATTACH 'test2.db' AS aux; + CREATE TABLE aux.t1(a, b); + } + get_file_format test2.db +} {1} +do_test alter2-6.3 { + execsql { + CREATE TABLE t1(a, b); + } + get_file_format +} {2} + +finish_test + diff --git a/test/capi3.test b/test/capi3.test index 8c19053dc7..4aef3e66dd 100644 --- a/test/capi3.test +++ b/test/capi3.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script testing the callback-free C/C++ API. # -# $Id: capi3.test,v 1.29 2005/01/24 10:26:00 danielk1977 Exp $ +# $Id: capi3.test,v 1.30 2005/02/19 08:18:06 danielk1977 Exp $ # set testdir [file dirname $argv0] @@ -487,7 +487,7 @@ if {![sqlite3 -has-codec]} { set ::bt [btree_open test.db 10 0] btree_begin_transaction $::bt set meta [btree_get_meta $::bt] - lset meta 2 2 + lset meta 2 3 eval [concat btree_update_meta $::bt [lrange $meta 0 end]] btree_commit $::bt btree_close $::bt diff --git a/test/corrupt.test b/test/corrupt.test index a6633e7641..be69d5c557 100644 --- a/test/corrupt.test +++ b/test/corrupt.test @@ -13,7 +13,7 @@ # This file implements tests to make sure SQLite does not crash or # segfault if it sees a corrupt database file. # -# $Id: corrupt.test,v 1.7 2005/02/05 12:48:49 danielk1977 Exp $ +# $Id: corrupt.test,v 1.8 2005/02/19 08:18:06 danielk1977 Exp $ catch {file delete -force test.db} catch {file delete -force test.db-journal} @@ -27,18 +27,18 @@ do_test corrupt-1.1 { execsql { BEGIN; CREATE TABLE t1(x); - INSERT INTO t1 VALUES(randstr(10,100)); - INSERT INTO t1 VALUES(randstr(10,100)); - INSERT INTO t1 VALUES(randstr(10,100)); - INSERT INTO t1 SELECT x || randstr(5,10) FROM t1; - INSERT INTO t1 SELECT x || randstr(5,10) FROM t1; - INSERT INTO t1 SELECT x || randstr(5,10) FROM t1; - INSERT INTO t1 SELECT x || randstr(5,10) FROM t1; - INSERT INTO t1 VALUES(randstr(2100,3000)); - INSERT INTO t1 SELECT x || randstr(5,10) FROM t1; - INSERT INTO t1 SELECT x || randstr(5,10) FROM t1; - INSERT INTO t1 SELECT x || randstr(5,10) FROM t1; - INSERT INTO t1 SELECT x || randstr(5,10) FROM t1; + INSERT INTO t1 VALUES(randstr(100,100)); + INSERT INTO t1 VALUES(randstr(90,90)); + INSERT INTO t1 VALUES(randstr(80,80)); + INSERT INTO t1 SELECT x || randstr(5,5) FROM t1; + INSERT INTO t1 SELECT x || randstr(6,6) FROM t1; + INSERT INTO t1 SELECT x || randstr(7,7) FROM t1; + INSERT INTO t1 SELECT x || randstr(8,8) FROM t1; + INSERT INTO t1 VALUES(randstr(3000,3000)); + INSERT INTO t1 SELECT x || randstr(9,9) FROM t1; + INSERT INTO t1 SELECT x || randstr(10,10) FROM t1; + INSERT INTO t1 SELECT x || randstr(11,11) FROM t1; + INSERT INTO t1 SELECT x || randstr(12,12) FROM t1; CREATE INDEX t1i1 ON t1(x); CREATE TABLE t2 AS SELECT * FROM t1; DELETE FROM t2 WHERE rowid%5!=0;