From: drh Date: Sat, 23 Jul 2005 02:17:03 +0000 (+0000) Subject: Full-coverage testing and documentation for the ANALYZE command. The X-Git-Tag: version-3.6.10~3598 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e6e049694d27fe483b13fb476498d8e3aa82e36c;p=thirdparty%2Fsqlite.git Full-coverage testing and documentation for the ANALYZE command. The results of analysis are still not loaded or used, however. (CVS 2561) FossilOrigin-Name: bd7583a5d63412785a9c5de54d25b509da241605 --- diff --git a/main.mk b/main.mk index 3c73fb0bec..2925e1a38d 100644 --- a/main.mk +++ b/main.mk @@ -133,7 +133,8 @@ TESTSRC = \ $(TOP)/src/utf.c \ $(TOP)/src/util.c \ $(TOP)/src/vdbe.c \ - $(TOP)/src/md5.c + $(TOP)/src/md5.c \ + $(TOP)/src/where.c # Header files used by all library source files. # diff --git a/manifest b/manifest index 5929b7aea5..9bed028a6f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C First\scode\sfor\sthe\sANALYZE\scommand.\s\sMostly\suntested.\s\sThe\sanalysis\sis\nnot\sloaded\sinto\sthe\ssymbol\stables\sand\sis\snot\sused\sby\sthe\soptimizer.\s(CVS\s2560) -D 2005-07-23T00:41:49 +C Full-coverage\stesting\sand\sdocumentation\sfor\sthe\sANALYZE\scommand.\s\sThe\nresults\sof\sanalysis\sare\sstill\snot\sloaded\sor\sused,\showever.\s(CVS\s2561) +D 2005-07-23T02:17:03 F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -16,7 +16,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826 -F main.mk b2d38013a10e1c6a821e3d117294bf785deecf97 +F main.mk c6712c0b26305f2da026d722caf3d9f8b6e187ea F mkdll.sh 5ec23622515d5bf8969404e80cfb5e220ddf0512 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodeh.awk 7563ad235670e864ead95cf672be3fe081450ae0 @@ -28,7 +28,7 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.def c413e514217736884254739a105c8c942fdf0c2f F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a F src/alter.c 03041f2464e22532601254f87cb49997fa21dcdf -F src/analyze.c 0eb48929dd1caa21438b067c507b0ee55ce17047 +F src/analyze.c b849c23866b7da98373f7b380f40b2a5f371e962 F src/attach.c 3615dbe960cbee4aa5ea300b8a213dad36527b0f F src/auth.c 18c5a0befe20f3a58a41e3ddd78f372faeeefe1f F src/btree.c ec55bd70052cdd0958f3a0e79ad58d93561acb20 @@ -63,10 +63,10 @@ F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4 F src/select.c c611471052773b94af771693686bd5bcdbbb0dba F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26 -F src/sqlite.h.in 838382ed6b48d392366a55e07f49d9d71263e1fe +F src/sqlite.h.in 7ccf2f61de2a0dca515e73708e561362e6c3d1e3 F src/sqliteInt.h 2925510c0233bb24c550fc5912fcdf0dd3a4421d F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 -F src/tclsqlite.c cccaf6b78c290d824cf8ea089b8b27377e545830 +F src/tclsqlite.c ef3276d0967cc0042bedcc1a7f09e0eb95cd3a8c F src/test1.c 722c1444b5774705eb6eb11163343fc94ffe17f7 F src/test2.c 716c1809dba8e5be6093703e9cada99d627542dc F src/test3.c 683e1e3819152ffd35da2f201e507228921148d0 @@ -91,10 +91,11 @@ F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3 F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6 F test/alter2.test 60ba0a7057dc71ad630a1cc7c487104346849d50 F test/alter3.test d4eecd8dbd008d0e66f1c201fa6dc2edca853c38 +F test/analyze.test a34554a015e9fdc478ae1660188feb0de4e43c2e F test/attach.test f320e98bcca68d100cab7666a0c9a93ac5f236bd F test/attach2.test 3396c012a39ddf7ba6b528d80bd79554168aa115 F test/attach3.test 63013383adc4380af69779f34f4af19bd49f7cbe -F test/auth.test 5129bfe268133092ad2928b8644ef97fa4602b2e +F test/auth.test 6a51c57219e246bdfd4454b3f7bd4136b44ad95c F test/autoinc.test 2aba7dc87438d221e2f2ea0e3e7d5fb6812edf6d F test/autovacuum.test cf2719b17659f7a011202ad05905654cedf26023 F test/autovacuum_crash.test 05a63b8805b20cfba7ace82856ce4ccdda075a31 @@ -269,7 +270,7 @@ F www/faq.tcl 49f31a703f74c71ce66da646aaf18b07a5042672 F www/fileformat.tcl 900c95b9633abc3dcfc384d9ddd8eb4876793059 F www/formatchng.tcl 053ddb73646701353a5b1c9ca6274d5900739b45 F www/index.tcl 9527f4eed69739cf5f81b3d75e0478d1c84d0a8a -F www/lang.tcl e0b9c55bf17a502b8f6f7731e5420278965b81a2 +F www/lang.tcl d55f580cff3f384ae82d29b1201babddf991f510 F www/lockingv3.tcl f59b19d6c8920a931f096699d6faaf61c05db55f F www/mingw.tcl d96b451568c5d28545fefe0c80bee3431c73f69c F www/nulls.tcl ec35193f92485b87b90a994a01d0171b58823fcf @@ -286,7 +287,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b -P 1a573619f558d1d67775d17aabb9d704f82ad1a8 -R a3fdedefcb771a47f367010f865883f0 +P a4886b114d2ccb3841d3d219f6b97f67745b13c2 +R 65a6648aca434084253023a9ade3ab6b U drh -Z d92cfb5ebecb44f8fc7d777743031b10 +Z 5c397aa099a763af87ffe475ca34fcef diff --git a/manifest.uuid b/manifest.uuid index 4da8744596..e2842dd2e2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a4886b114d2ccb3841d3d219f6b97f67745b13c2 \ No newline at end of file +bd7583a5d63412785a9c5de54d25b509da241605 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 76c1348992..a3f8e84c83 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code associated with the ANALYZE command. ** -** @(#) $Id: analyze.c,v 1.2 2005/07/23 00:41:49 drh Exp $ +** @(#) $Id: analyze.c,v 1.3 2005/07/23 02:17:03 drh Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" @@ -64,7 +64,7 @@ static void openStatTable( /* Open the sqlite_stat1 table for writing. */ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, 0); + sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage); sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3); } @@ -92,6 +92,14 @@ static void analyzeOneTable( /* Do no analysis for tables with fewer than 2 indices */ return; } + +#ifndef SQLITE_OMIT_AUTHORIZATION + if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, + pParse->db->aDb[pTab->iDb].zName ) ){ + return; + } +#endif + iIdxCur = pParse->nTab; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ /* Open a cursor to the index to be analyzed @@ -130,9 +138,9 @@ static void analyzeOneTable( /* Do the analysis. */ - sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, 0); - topOfLoop = sqlite3VdbeCurrentAddr(v); endOfLoop = sqlite3VdbeMakeLabel(v); + sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, endOfLoop); + topOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp(v, OP_MemIncr, iMem, 0); for(i=0; in==0 ){ /* Form 2: Analyze the database or table named */ iDb = sqlite3FindDb(db, pName1); if( iDb>=0 ){ analyzeDatabase(pParse, iDb); - return; - } - z = sqlite3NameFromToken(pName1); - pTab = sqlite3LocateTable(pParse, z, 0); - sqliteFree(z); - if( pTab ){ - analyzeTable(pParse, pTab); + }else{ + z = sqlite3NameFromToken(pName1); + pTab = sqlite3LocateTable(pParse, z, 0); + sqliteFree(z); + if( pTab ){ + analyzeTable(pParse, pTab); + } } - return; }else{ /* Form 3: Analyze the fully qualified table name */ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 7457268c3b..9590fd8bfc 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.137 2005/07/09 02:39:40 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.138 2005/07/23 02:17:03 drh Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -452,6 +452,7 @@ int sqlite3_set_authorizer( #define SQLITE_DETACH 25 /* Database Name NULL */ #define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ #define SQLITE_REINDEX 27 /* Index Name NULL */ +#define SQLITE_ANALYZE 28 /* Table Name NULL */ /* diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 64a2a3b8ec..bc98e348df 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.127 2005/06/26 17:55:34 drh Exp $ +** $Id: tclsqlite.c,v 1.128 2005/07/23 02:17:03 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -472,6 +472,7 @@ static int auth_callback( case SQLITE_DETACH : zCode="SQLITE_DETACH"; break; case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break; case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break; + case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break; default : zCode="????"; break; } Tcl_DStringInit(&str); diff --git a/test/analyze.test b/test/analyze.test new file mode 100644 index 0000000000..a9f0118346 --- /dev/null +++ b/test/analyze.test @@ -0,0 +1,190 @@ +# 2005 July 22 +# +# 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. +# This file implements tests for the ANALYZE command. +# +# $Id: analyze.test,v 1.1 2005/07/23 02:17:03 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# There is nothing to test if ANALYZE is disable for this build. +# +ifcapable {!analyze} { + finish_test + return +} + +# Basic sanity checks. +# +do_test analyze-1.1 { + catchsql { + ANALYZE no_such_table + } +} {1 {no such table: no_such_table}} +do_test analyze-1.2 { + execsql { + SELECT count(*) FROM sqlite_master WHERE name='sqlite_stat1' + } +} {0} +do_test analyze-1.3 { + catchsql { + ANALYZE no_such_db.no_such_table + } +} {1 {unknown database no_such_db}} +do_test analyze-1.4 { + execsql { + SELECT count(*) FROM sqlite_master WHERE name='sqlite_stat1' + } +} {0} +do_test analyze-1.5 { + catchsql { + ANALYZE + } +} {0 {}} +do_test analyze-1.6 { + execsql { + SELECT count(*) FROM sqlite_master WHERE name='sqlite_stat1' + } +} {1} +do_test analyze-1.7 { + execsql { + SELECT * FROM sqlite_stat1 + } +} {} +do_test analyze-1.8 { + catchsql { + ANALYZE main + } +} {0 {}} +do_test analyze-1.9 { + execsql { + SELECT * FROM sqlite_stat1 + } +} {} +do_test analyze-1.10 { + catchsql { + CREATE TABLE t1(a,b); + ANALYZE main.t1; + } +} {0 {}} +do_test analyze-1.11 { + execsql { + SELECT * FROM sqlite_stat1 + } +} {} +do_test analyze-1.12 { + catchsql { + ANALYZE t1; + } +} {0 {}} +do_test analyze-1.13 { + execsql { + SELECT * FROM sqlite_stat1 + } +} {} + +# Create some indices that can be analyzed. But do not yet add +# data. Without data in the tables, no analysis is done. +# +do_test analyze-2.1 { + execsql { + CREATE INDEX t1i1 ON t1(a); + ANALYZE main.t1; + SELECT * FROM sqlite_stat1 ORDER BY idx; + } +} {} +do_test analyze-2.2 { + execsql { + CREATE INDEX t1i2 ON t1(b); + ANALYZE t1; + SELECT * FROM sqlite_stat1 ORDER BY idx; + } +} {} +do_test analyze-2.3 { + execsql { + CREATE INDEX t1i3 ON t1(a,b); + ANALYZE main; + SELECT * FROM sqlite_stat1 ORDER BY idx; + } +} {} + +# Start adding data to the table. Verify that the analysis +# is done correctly. +# +do_test analyze-3.1 { + execsql { + INSERT INTO t1 VALUES(1,2); + INSERT INTO t1 VALUES(1,3); + ANALYZE main.t1; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + } +} {t1i1 2 t1i2 1 t1i3 {2 1}} +do_test analyze-3.2 { + execsql { + INSERT INTO t1 VALUES(1,4); + INSERT INTO t1 VALUES(1,5); + ANALYZE t1; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + } +} {t1i1 4 t1i2 1 t1i3 {4 1}} +do_test analyze-3.3 { + execsql { + INSERT INTO t1 VALUES(2,5); + ANALYZE main; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + } +} {t1i1 3 t1i2 2 t1i3 {3 1}} +do_test analyze-3.4 { + execsql { + CREATE TABLE t2 AS SELECT * FROM t1; + CREATE INDEX t2i1 ON t2(a); + CREATE INDEX t2i2 ON t2(b); + CREATE INDEX t2i3 ON t2(a,b); + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + } +} {t1i1 3 t1i2 2 t1i3 {3 1} t2i1 3 t2i2 2 t2i3 {3 1}} +do_test analyze-3.5 { + execsql { + DROP INDEX t2i3; + ANALYZE t1; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + } +} {t1i1 3 t1i2 2 t1i3 {3 1} t2i1 3 t2i2 2 t2i3 {3 1}} +do_test analyze-3.6 { + execsql { + ANALYZE t2; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + } +} {t1i1 3 t1i2 2 t1i3 {3 1} t2i1 3 t2i2 2} +do_test analyze-3.7 { + execsql { + DROP INDEX t2i2; + ANALYZE t2; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + } +} {t1i1 3 t1i2 2 t1i3 {3 1}} +do_test analyze-3.8 { + execsql { + CREATE TABLE t3 AS SELECT a, b, rowid AS c, 'hi' AS d FROM t1; + CREATE INDEX t3i1 ON t3(a); + CREATE INDEX t3i2 ON t3(a,b,c,d); + CREATE INDEX t3i3 ON t3(d,b,c,a); + DROP TABLE t1; + DROP TABLE t2; + ANALYZE; + SELECT idx, stat FROM sqlite_stat1 ORDER BY idx; + } +} {t3i1 3 t3i2 {3 1 1 1} t3i3 {5 2 1 1}} + + +finish_test diff --git a/test/auth.test b/test/auth.test index 1bd32cb65b..cc43b2daeb 100644 --- a/test/auth.test +++ b/test/auth.test @@ -12,7 +12,7 @@ # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # -# $Id: auth.test,v 1.27 2005/03/29 03:11:00 danielk1977 Exp $ +# $Id: auth.test,v 1.28 2005/07/23 02:17:03 drh Exp $ # set testdir [file dirname $argv0] @@ -1951,6 +1951,49 @@ ifcapable tempdb { } ;# ifcapable reindex +ifcapable analyze { + proc auth {code args} { + if {$code=="SQLITE_ANALYZE"} { + set ::authargs [concat $::authargs $args] + } + return SQLITE_OK + } + do_test auth-1.294 { + set ::authargs {} + execsql { + CREATE TABLE t4(a,b,c); + CREATE INDEX t4i1 ON t4(a); + CREATE INDEX t4i2 ON t4(b,a,c); + INSERT INTO t4 VALUES(1,2,3); + ANALYZE; + } + set ::authargs + } {t4 {} main {}} + do_test auth-1.295 { + execsql { + SELECT count(*) FROM sqlite_stat1; + } + } 2 + proc auth {code args} { + if {$code=="SQLITE_ANALYZE"} { + set ::authargs [concat $::authargs $args] + return SQLITE_DENY + } + return SQLITE_OK + } + do_test auth-1.296 { + set ::authargs {} + catchsql { + ANALYZE; + } + } {1 {not authorized}} + do_test auth-1.297 { + execsql { + SELECT count(*) FROM sqlite_stat1; + } + } 2 +} ;# ifcapable analyze + do_test auth-2.1 { proc auth {code arg1 arg2 arg3 arg4} { if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="x"} { diff --git a/www/lang.tcl b/www/lang.tcl index c54c46af62..8e4fe79c86 100644 --- a/www/lang.tcl +++ b/www/lang.tcl @@ -1,7 +1,7 @@ # # Run this Tcl script to generate the lang-*.html files. # -set rcsid {$Id: lang.tcl,v 1.94 2005/07/22 23:56:50 drh Exp $} +set rcsid {$Id: lang.tcl,v 1.95 2005/07/23 02:17:03 drh Exp $} source common.tcl if {[llength $argv]>0} { @@ -76,6 +76,7 @@ foreach {section} [lsort -index 0 -dictionary { {{DETACH DATABASE} detach} {REINDEX reindex} {{ALTER TABLE} altertable} + {{ANALYZE} analyze} }] { foreach {s_title s_tag} $section {} puts "
  • $s_title
  • " @@ -187,6 +188,35 @@ be readable by SQLite version 3.1.3 and earlier until the database is VACUUMed.

    } +Section {ANALYZE} analyze + +Syntax {sql-statement} { + ANALYZE +} +Syntax {sql-statement} { + ANALYZE +} +Syntax {sql-statement} { + ANALYZE [ .] +} + +puts { +

    The ANALYZE command gathers statistics about indices and stores them +in a special tables in the database where the query optimizer can use +them to help make better index choices. +If no arguments are given, all indices in all attached databases are +analyzed. If a database name is given as the argument, all indices +in that one database are analyzed. If the argument is a table name, +then only indices associated with that one table are analyzed.

    + +

    The initial implementation stores all statistics in a single +table named sqlite_stat1. Future enhancements may create +additional tables with the same name pattern except with the "1" +changed to a different digit. The sqlite_stat1 table cannot +be DROPped, but it all the content can be DELETEd which as the +same effect.

    +} + Section {ATTACH DATABASE} attach Syntax {sql-statement} { @@ -1484,8 +1514,7 @@ Syntax {sql-statement} { puts {

    The REINDEX command is used to delete and recreate indices from scratch. -This is primarily useful when the definition of a collation sequence has -changed. +This is useful when the definition of a collation sequence has changed.

    In the first form, all indices in all attached databases that use the