Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 60ea3720f2 | |||
| 85b988c803 | |||
| e98d4fafe4 | |||
| 77155c480a | |||
| 57809db9c5 | |||
| 0ac6589202 | |||
| 67505e78c6 | |||
| c8cacb3704 | |||
| dd45df8a5b | |||
| 45698a3a03 | |||
| 1d0b872d43 | |||
| 7e2dfdd726 | |||
| a168045f7d | |||
| fc6cdfe9dc | |||
| 6b0e620fda | |||
| adbe353fc6 | |||
| c8d30ac109 | |||
| b04a5d8768 | |||
| feeb1394ee | |||
| fe1a1773a8 | |||
| 8b32e17d26 | |||
| 6ed41ad735 | |||
| bf3a4fa4cb | |||
| 41e941dda6 | |||
| 5447322939 | |||
| f238f700c2 |
@@ -1,9 +1,9 @@
|
||||
C Version\s2.4.6\s(CVS\s516)
|
||||
D 2002-04-02T13:27:43
|
||||
C Version\s2.4.9\s(CVS\s542)
|
||||
D 2002-04-22T00:35:06
|
||||
F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d
|
||||
F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296
|
||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||
F VERSION ed0299de5b86deca846fdb0f8b99aaae85f27f47
|
||||
F VERSION 23cded544ac22813b39f410aac0a8735ae991d64
|
||||
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
|
||||
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
|
||||
F config.log 6a73d03433669b10a3f0c221198c3f26b9413914
|
||||
@@ -18,33 +18,33 @@ F libtool c56e618713c9510a103bda6b95f3ea3900dcacd6
|
||||
F ltmain.sh e9ed72eb1d690f447c13945eaf69e28af531eda1
|
||||
F publish.sh 0b9da5898bf5997f30d6f80de4880072db7e5718
|
||||
F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e
|
||||
F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9
|
||||
F sqlite.1 6b339cb747b45f8e7ea0335b06291b6d52067b31
|
||||
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
||||
F src/btree.c 7dd7ddc66459982dd0cb9800958c1f8d65a32d9f
|
||||
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
|
||||
F src/build.c d01b81f41481e733e27ab2fa8e1bfcc64f24257d
|
||||
F src/delete.c 577da499162291c1855f0b304b211bffcf9da945
|
||||
F src/expr.c e7a1e22bc2ebcd789f0f8c0db544cf16ad664054
|
||||
F src/func.c 87516e7dc37190c24af77593931a5d09d797520a
|
||||
F src/delete.c 6a6b8192cdff5e4b083da3bc63de099f3790d01f
|
||||
F src/expr.c cf8d2ea17e419fc83b23e080195b2952e0be4164
|
||||
F src/func.c a31dcba85bc2ecb9b752980289cf7e6cd0cafbce
|
||||
F src/hash.c cc259475e358baaf299b00a2c7370f2b03dda892
|
||||
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
|
||||
F src/insert.c 903ff262c90586c99eafd43934517bc3aed5f77e
|
||||
F src/main.c b21019084b93fe685a8a25217d01f6958584ae9b
|
||||
F src/insert.c 31233f44fc79edbb43523a830e54736a8e222ff4
|
||||
F src/main.c df43fe585d2bfb925c837b6822783c0ee3dd6e1c
|
||||
F src/md5.c b2b1a34fce66ceca97f4e0dabc20be8be7933c92
|
||||
F src/os.c 5ab8b6b4590d0c1ab8e96c67996c170e4462e0fc
|
||||
F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10
|
||||
F src/pager.c f136f5ba82c896d500a10b6a2e5caea62abf716b
|
||||
F src/pager.c ba5740104cc27b342cd43eebfdc44d60f64a3ded
|
||||
F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
|
||||
F src/parse.y a0943e2774c7b0cab608640df1126f6c3ae39e90
|
||||
F src/parse.y 0ce56f1c751657f01e18a4b4ac1aa4d29525ac20
|
||||
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
|
||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||
F src/select.c 9323800e2937e84b52c198fffc51995d822b1779
|
||||
F src/shell.c b3454229599246b944cdb5b95753af3fca5d8bb0
|
||||
F src/select.c 92aef3f69e90dc065d680d88b1f075409e9249bb
|
||||
F src/shell.c 5acbe59e137d60d8efd975c683dbea74ab626530
|
||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in 1dae50411aee9439860d7fbe315183c582d27197
|
||||
F src/sqliteInt.h 73e7d0f39a3c11d395fc422986959261bd193eba
|
||||
F src/sqlite.h.in ffcacf73b5ed1a4939205d29a704a185758fa6a6
|
||||
F src/sqliteInt.h e47ca9267a4c4a98e9f8d90c2df994a18f23d699
|
||||
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
|
||||
F src/tclsqlite.c df847b71b28277f1cfa1ee1e3e51452ffe5a9a26
|
||||
F src/tclsqlite.c c9e9039762d9866eae70bf782237d0206a13f57e
|
||||
F src/test1.c d46ab7a82a9c16a3b1ee363cb4c0f98c5ff65743
|
||||
F src/test2.c d410dbd8a90faa466c3ab694fa0aa57f5a773aa6
|
||||
F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
|
||||
@@ -52,23 +52,23 @@ F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
|
||||
F src/tokenize.c 5624d342601f616157ba266abccc1368a5afee70
|
||||
F src/update.c 7dd714a6a7fa47f849ebb36b6d915974d6c6accb
|
||||
F src/util.c b34cd91387bbfdc79319ea451a7d120cef478120
|
||||
F src/vdbe.c 3cebe9f77cac311a3c537587258946d04a09c58f
|
||||
F src/vdbe.h f9be1f6e9a336c3ff4d14ea7489ee976e07460cc
|
||||
F src/vdbe.c 0ed88fff32273c103a24396d491b71bc69b4b596
|
||||
F src/vdbe.h 67840a462e1daedb958cca0ccc97db140d3d9152
|
||||
F src/where.c 9d36f6c9fea4af71501770c13089f824cb9b033c
|
||||
F test/all.test 6aa106eee4d7127afa5cee97c51a783a79694ead
|
||||
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
||||
F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1
|
||||
F test/btree2.test e3b81ec33dc2f89b3e6087436dfe605b870c9080
|
||||
F test/btree3.test 9caa9e22491dd8cd8aa36d7ac3b48b089817c895
|
||||
F test/conflict.test c794c6c8f6e59918107dbab2d201ae454bb47db8
|
||||
F test/conflict.test 5149646703d3930c9111068b5cda7e2e938476e3
|
||||
F test/copy.test b3cefcb520c64d7e7dfedbab06b4d4c31fa5b99a
|
||||
F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
|
||||
F test/expr.test 846795016b5993a7411f772eebe82ab67bd7230a
|
||||
F test/func.test 4359344586067e79abf4c710c4737d67ed3cf963
|
||||
F test/func.test d34e461f0acb0cf2978a4b3a3e098460f2ea8fbc
|
||||
F test/in.test c09312672e3f0709fa02c8e2e9cd8fb4bd6269aa
|
||||
F test/index.test c8a471243bbf878974b99baf5badd59407237cf3
|
||||
F test/insert.test c36d534a4ab58c2cd452a273e51b2b0dd1ede1f9
|
||||
F test/insert2.test 2f02b1e0dbfba3e8c76496209be5f4010b584181
|
||||
F test/insert.test 58d44c19b3557f67f4aeb5110ed9ef02038c3684
|
||||
F test/insert2.test eb8481878a7f52ccb4e3346f87550f5afdd77f76
|
||||
F test/intpkey.test 31b5f28b2c44273e6695cf36ab2e4133aee7753c
|
||||
F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
|
||||
F test/limit.test a930f3eba2a7691c8397ccab33710b931589566a
|
||||
@@ -84,7 +84,7 @@ F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da
|
||||
F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
|
||||
F test/quote.test 286db944717afa9a9bf829dd85e59185c65d5435
|
||||
F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274
|
||||
F test/select1.test 572d53f7b28c35a1efdce207f7579523358ba637
|
||||
F test/select1.test 734b9f45a85b4f8d594390b1ed3cbff0b8c76c84
|
||||
F test/select2.test aceea74fd895b9d007512f72499db589735bd8e4
|
||||
F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18
|
||||
F test/select4.test 29a2ffb187f3d8b6ca42a0a6b619e9cabe12e228
|
||||
@@ -94,7 +94,7 @@ F test/sort.test 3b996ce7ca385f9cd559944ac0f4027a23aa546b
|
||||
F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78
|
||||
F test/table.test 17b0b6eafa3faaee5545b7a94e6c1ff73f0880f3
|
||||
F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6
|
||||
F test/tclsqlite.test ca8dd89b02ab68bd4540163c24551756a69f6783
|
||||
F test/tclsqlite.test 79deeffd7cd637ca0f06c5dbbf2f44d272079533
|
||||
F test/temptable.test 0e9934283259a5e637eec756a7eefd6964c0f79b
|
||||
F test/tester.tcl dc1b56bd628b487e4d75bfd1e7480b5ed8810ac6
|
||||
F test/trans.test ae0b9a82d5d34122c3a3108781eb8d078091ccee
|
||||
@@ -110,28 +110,28 @@ F tool/opNames.awk 5ba1f48aa854ee3b7c3d2b54233665bc3e649ea2
|
||||
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
|
||||
F tool/report1.txt 9eae07f26a8fc53889b45fc833a66a33daa22816
|
||||
F tool/speedtest.tcl 6d89431651f2eb800fb0998a8de44b84168e08b9
|
||||
F tool/speedtest.tcl 8287851340fd4a9500a69e9b10fb5ed9e6b0d0c3
|
||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
|
||||
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
||||
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
|
||||
F www/c_interface.tcl 567cda531aac9d68a61ef02e26c6b202bd856db2
|
||||
F www/changes.tcl 563071eacf1c0fc03521bf874438274d83445c78
|
||||
F www/c_interface.tcl 79f63ffa8c6e7adb9e3449ff325d093cfb0ce3e3
|
||||
F www/changes.tcl c4bc9b9e57bf67f272e6d420de4d99175f4d9e82
|
||||
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
|
||||
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
||||
F www/download.tcl 29aa6679ca29621d10613f60ebbbda18f4b91c49
|
||||
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
||||
F www/faq.tcl fb1e92e2f604546694f83a36d969492f52fb685d
|
||||
F www/formatchng.tcl 2ce21ff30663fad6618198fe747ce675df577590
|
||||
F www/index.tcl e6d59816ad6f90b03b0a92eccd45d6a4a928438a
|
||||
F www/lang.tcl e6c277480c4e31877c08509af7a16f6c69bb1046
|
||||
F www/index.tcl d0c52fbf031d0a3ee6d9d77aa669d5a4b24b6130
|
||||
F www/lang.tcl 2d4654255ad1ec7f58d02dc41b59528c0ee6ea44
|
||||
F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
|
||||
F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
|
||||
F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
|
||||
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
||||
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
|
||||
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||
P abb12259a09418eb6e3cf573ea718ac58c91ac7b
|
||||
R 1e8462f1dea7fa55f9cf92098e6e2f92
|
||||
P a91da82f8ae2b375bf9f5e064f16d6a5770e20b6
|
||||
R 472bee23aa57568ebf6afa84b40ded15
|
||||
U drh
|
||||
Z c767d9da34c060a9378c5b233c151832
|
||||
Z 4019f966a724267cde26980ddbf6ddea
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
5ae7efd87f1a8e2f3e927bf373fbcb5c692d1a02
|
||||
0691720a4b94141635734ab0a8c4072cab189a33
|
||||
@@ -2,7 +2,7 @@
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH SQLITE SECTION "January 2, 2002"
|
||||
.TH SQLITE 1 "Mon Apr 15 23:49:17 2002"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.\"
|
||||
.\" Some roff macros, for reference:
|
||||
@@ -73,19 +73,39 @@ any time. For example:
|
||||
.nf
|
||||
.cc |
|
||||
sqlite> .help
|
||||
.dump Dump database in a text format
|
||||
.dump ?TABLE? ... Dump the database in an text format
|
||||
.echo ON|OFF Turn command echo on or off
|
||||
.exit Exit this program
|
||||
.explain Set output mode suitable for EXPLAIN
|
||||
.header ON|OFF Turn display of headers on or off
|
||||
.explain ON|OFF Turn output mode suitable for EXPLAIN on or off.
|
||||
"off" will revert to the output mode that was
|
||||
previously in effect
|
||||
.header(s) ON|OFF Turn display of headers on or off
|
||||
.help Show this message
|
||||
.indices TABLE Show names of all indices on TABLE
|
||||
.mode MODE Set mode to one of "line", "column", "list", or "html"
|
||||
.mode MODE Set mode to one of "line(s)", "column(s)",
|
||||
"insert", "list", or "html"
|
||||
.mode insert TABLE Generate SQL insert statements for TABLE
|
||||
.nullvalue STRING Print STRING instead of nothing for NULL data
|
||||
.output FILENAME Send output to FILENAME
|
||||
.output stdout Send output to the screen
|
||||
.prompt MAIN CONTINUE Replace the standard prompts
|
||||
"sqlite > " and " ...> "
|
||||
with the strings MAIN and CONTINUE
|
||||
CONTINUE is optional.
|
||||
.quit Exit this program
|
||||
.read FILENAME Execute SQL in FILENAME
|
||||
.reindex ?TABLE? Rebuild indices
|
||||
.schema ?TABLE? Show the CREATE statements
|
||||
.separator STRING Change separator string for "list" mode
|
||||
.tables List names all tables in the database
|
||||
.show Show the current values for the following:
|
||||
.echo
|
||||
.explain
|
||||
.mode
|
||||
.nullvalue
|
||||
.output
|
||||
.separator
|
||||
.width
|
||||
.tables ?PATTERN? List names of tables matching a pattern
|
||||
.timeout MS Try opening locked tables for MS milliseconds
|
||||
.width NUM NUM ... Set column widths for "column" mode
|
||||
sqlite>
|
||||
@@ -96,6 +116,10 @@ sqlite>
|
||||
.SH OPTIONS
|
||||
The program has the following options:
|
||||
.TP
|
||||
.BI \-init\ file
|
||||
Read in and process 'file', which contains "dot commands".
|
||||
You can use this file to initialize display settings.
|
||||
.TP
|
||||
.B \-html
|
||||
Set output mode to HTML.
|
||||
.TP
|
||||
@@ -105,9 +129,22 @@ Set output mode to 'list'.
|
||||
.B \-line
|
||||
Set output mode to 'line'.
|
||||
.TP
|
||||
.B \-column
|
||||
Set output mode to 'column'.
|
||||
.TP
|
||||
.BI \-seperator\ seperator
|
||||
Specify which output field seperator for 'list' mode to use.
|
||||
Specify which output field seperator for 'list' mode to use.
|
||||
Default is '|'.
|
||||
.TP
|
||||
.BI \-nullvalue\ string
|
||||
When a null is encountered, print 'string'. Default is no string.
|
||||
.TP
|
||||
.B \-[no]header
|
||||
Turn headers on or off. Default is off.
|
||||
.TP
|
||||
.B \-echo
|
||||
Print commands before execution.
|
||||
|
||||
|
||||
.SH OUTPUT MODE
|
||||
The SQLite program has different output modes, which define the way
|
||||
@@ -124,6 +161,38 @@ In HTML mode, an XHTML table is generated.
|
||||
|
||||
In 'column' mode, one record per line is output, aligned neatly in colums.
|
||||
|
||||
.SH INIT FILE
|
||||
sqlite can be initialized using resource files. These can be combined with
|
||||
command line arguments to set up sqlite exactly the way you want it.
|
||||
Initialization proceeds as follows:
|
||||
|
||||
o The defaults of
|
||||
|
||||
.sp
|
||||
.nf
|
||||
.cc |
|
||||
mode = LIST
|
||||
separator = "|"
|
||||
main prompt = "sqlite> "
|
||||
continue prompt = " ...> "
|
||||
|cc .
|
||||
.sp
|
||||
.fi
|
||||
|
||||
are established.
|
||||
|
||||
o If a file .sqliterc can be found in the user's home directory, it is
|
||||
read and processed. It should only contain "dot commands". If the
|
||||
file is not found or cannot be read, processing continues without
|
||||
notification.
|
||||
|
||||
o If a file is specified on the command line with the -init option, it
|
||||
is processed in the same manner as .sqliterc
|
||||
|
||||
o All other command line options are processed
|
||||
|
||||
o The database is opened and you are now ready to begin.
|
||||
|
||||
.SH SEE ALSO
|
||||
http://www.hwaci.com/sw/sqlite/
|
||||
.br
|
||||
|
||||
+5
-4
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.29 2002/03/03 18:59:40 drh Exp $
|
||||
** $Id: delete.c,v 1.30 2002/04/12 10:08:59 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -183,7 +183,7 @@ void sqliteDeleteFrom(
|
||||
}
|
||||
end = sqliteVdbeMakeLabel(v);
|
||||
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
|
||||
sqliteGenerateRowDelete(v, pTab, base);
|
||||
sqliteGenerateRowDelete(v, pTab, base, 1);
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
|
||||
sqliteVdbeResolveLabel(v, end);
|
||||
sqliteVdbeAddOp(v, OP_ListReset, 0, 0);
|
||||
@@ -229,11 +229,12 @@ delete_from_cleanup:
|
||||
void sqliteGenerateRowDelete(
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
Table *pTab, /* Table containing the row to be deleted */
|
||||
int base /* Cursor number for the table */
|
||||
int base, /* Cursor number for the table */
|
||||
int count /* Increment the row change counter */
|
||||
){
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
||||
sqliteGenerateRowIndexDelete(v, pTab, base, 0);
|
||||
sqliteVdbeAddOp(v, OP_Delete, base, 0);
|
||||
sqliteVdbeAddOp(v, OP_Delete, base, count);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+3
-20
@@ -12,7 +12,7 @@
|
||||
** This file contains routines used for analyzing expressions and
|
||||
** for generating VDBE code that evaluates expressions in SQLite.
|
||||
**
|
||||
** $Id: expr.c,v 1.57 2002/03/24 13:13:29 drh Exp $
|
||||
** $Id: expr.c,v 1.58 2002/04/20 14:24:42 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -705,8 +705,6 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
|
||||
case TK_GE: op = OP_Ge; break;
|
||||
case TK_NE: op = OP_Ne; break;
|
||||
case TK_EQ: op = OP_Eq; break;
|
||||
case TK_LIKE: op = OP_Like; break;
|
||||
case TK_GLOB: op = OP_Glob; break;
|
||||
case TK_ISNULL: op = OP_IsNull; break;
|
||||
case TK_NOTNULL: op = OP_NotNull; break;
|
||||
case TK_NOT: op = OP_Not; break;
|
||||
@@ -784,9 +782,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
|
||||
case TK_GT:
|
||||
case TK_GE:
|
||||
case TK_NE:
|
||||
case TK_EQ:
|
||||
case TK_LIKE:
|
||||
case TK_GLOB: {
|
||||
case TK_EQ: {
|
||||
int dest;
|
||||
sqliteVdbeAddOp(v, OP_Integer, 1, 0);
|
||||
sqliteExprCode(pParse, pExpr->pLeft);
|
||||
@@ -938,8 +934,6 @@ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
|
||||
case TK_GE: op = OP_Ge; break;
|
||||
case TK_NE: op = OP_Ne; break;
|
||||
case TK_EQ: op = OP_Eq; break;
|
||||
case TK_LIKE: op = OP_Like; break;
|
||||
case TK_GLOB: op = OP_Glob; break;
|
||||
case TK_ISNULL: op = OP_IsNull; break;
|
||||
case TK_NOTNULL: op = OP_NotNull; break;
|
||||
default: break;
|
||||
@@ -966,9 +960,7 @@ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
|
||||
case TK_GT:
|
||||
case TK_GE:
|
||||
case TK_NE:
|
||||
case TK_EQ:
|
||||
case TK_LIKE:
|
||||
case TK_GLOB: {
|
||||
case TK_EQ: {
|
||||
sqliteExprCode(pParse, pExpr->pLeft);
|
||||
sqliteExprCode(pParse, pExpr->pRight);
|
||||
sqliteVdbeAddOp(v, op, 0, dest);
|
||||
@@ -1026,8 +1018,6 @@ void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){
|
||||
case TK_GE: op = OP_Lt; break;
|
||||
case TK_NE: op = OP_Eq; break;
|
||||
case TK_EQ: op = OP_Ne; break;
|
||||
case TK_LIKE: op = OP_Like; break;
|
||||
case TK_GLOB: op = OP_Glob; break;
|
||||
case TK_ISNULL: op = OP_NotNull; break;
|
||||
case TK_NOTNULL: op = OP_IsNull; break;
|
||||
default: break;
|
||||
@@ -1060,13 +1050,6 @@ void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){
|
||||
sqliteVdbeAddOp(v, op, 0, dest);
|
||||
break;
|
||||
}
|
||||
case TK_LIKE:
|
||||
case TK_GLOB: {
|
||||
sqliteExprCode(pParse, pExpr->pLeft);
|
||||
sqliteExprCode(pParse, pExpr->pRight);
|
||||
sqliteVdbeAddOp(v, op, 1, dest);
|
||||
break;
|
||||
}
|
||||
case TK_ISNULL:
|
||||
case TK_NOTNULL: {
|
||||
sqliteExprCode(pParse, pExpr->pLeft);
|
||||
|
||||
+42
-1
@@ -16,7 +16,7 @@
|
||||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: func.c,v 1.14 2002/03/04 02:26:16 drh Exp $
|
||||
** $Id: func.c,v 1.16 2002/04/20 14:24:42 drh Exp $
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
@@ -196,6 +196,43 @@ static void randomFunc(sqlite_func *context, int argc, const char **argv){
|
||||
sqlite_set_result_int(context, sqliteRandomInteger());
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the last_insert_rowid() SQL function. The return
|
||||
** value is the same as the sqlite_last_insert_rowid() API function.
|
||||
*/
|
||||
static void last_insert_rowid(sqlite_func *context, int arg, const char **argv){
|
||||
sqlite *db = sqlite_user_data(context);
|
||||
sqlite_set_result_int(context, sqlite_last_insert_rowid(db));
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the like() SQL function. This function implements
|
||||
** the build-in LIKE operator. The first argument to the function is the
|
||||
** string and the second argument is the pattern. So, the SQL statements:
|
||||
**
|
||||
** A LIKE B
|
||||
**
|
||||
** is implemented as like(A,B).
|
||||
*/
|
||||
static void likeFunc(sqlite_func *context, int arg, const char **argv){
|
||||
sqlite_set_result_int(context,
|
||||
sqliteLikeCompare(argv[0] ? argv[0] : "",argv[1] ? argv[1] : ""));
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the glob() SQL function. This function implements
|
||||
** the build-in GLOB operator. The first argument to the function is the
|
||||
** string and the second argument is the pattern. So, the SQL statements:
|
||||
**
|
||||
** A GLOB B
|
||||
**
|
||||
** is implemented as glob(A,B).
|
||||
*/
|
||||
static void globFunc(sqlite_func *context, int arg, const char **argv){
|
||||
sqlite_set_result_int(context,
|
||||
sqliteGlobCompare(argv[0] ? argv[0] : "",argv[1] ? argv[1] : ""));
|
||||
}
|
||||
|
||||
/*
|
||||
** An instance of the following structure holds the context of a
|
||||
** sum() or avg() aggregate computation.
|
||||
@@ -385,6 +422,8 @@ void sqliteRegisterBuildinFunctions(sqlite *db){
|
||||
{ "coalesce", 0, 0 },
|
||||
{ "coalesce", 1, 0 },
|
||||
{ "random", -1, randomFunc },
|
||||
{ "like", 2, likeFunc },
|
||||
{ "glob", 2, globFunc },
|
||||
};
|
||||
static struct {
|
||||
char *zName;
|
||||
@@ -408,6 +447,8 @@ void sqliteRegisterBuildinFunctions(sqlite *db){
|
||||
sqlite_create_function(db, aFuncs[i].zName,
|
||||
aFuncs[i].nArg, aFuncs[i].xFunc, 0);
|
||||
}
|
||||
sqlite_create_function(db, "last_insert_rowid", 0,
|
||||
last_insert_rowid, db);
|
||||
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
|
||||
sqlite_create_aggregate(db, aAggs[i].zName,
|
||||
aAggs[i].nArg, aAggs[i].xStep, aAggs[i].xFinalize, 0);
|
||||
|
||||
+15
-13
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.48 2002/03/31 18:29:03 drh Exp $
|
||||
** $Id: insert.c,v 1.52 2002/04/12 10:08:59 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -100,6 +100,9 @@ void sqliteInsert(
|
||||
if( sqliteExprResolveIds(pParse, 0, &dummy, 0, pList->a[i].pExpr) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
if( sqliteExprCheck(pParse, pList->a[i].pExpr, 0, 0) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,15 +186,18 @@ void sqliteInsert(
|
||||
}
|
||||
pParse->nTab += idx;
|
||||
|
||||
/* Initialize the count of rows to be inserted
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */
|
||||
}
|
||||
|
||||
/* If the data source is a SELECT statement, then we have to create
|
||||
** a loop because there might be multiple rows of data. If the data
|
||||
** source is an expression list, then exactly one row will be inserted
|
||||
** and the loop is not used.
|
||||
*/
|
||||
if( srcTab>=0 ){
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */
|
||||
}
|
||||
iBreak = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak);
|
||||
iCont = sqliteVdbeCurrentAddr(v);
|
||||
@@ -258,10 +264,9 @@ void sqliteInsert(
|
||||
sqliteGenerateConstraintChecks(pParse, pTab, base, 0,0,0, onError, endOfLoop);
|
||||
sqliteCompleteInsertion(pParse, pTab, base, 0,0,0);
|
||||
|
||||
/* If inserting from a SELECT, keep a count of the number of
|
||||
** rows inserted.
|
||||
/* Update the count of rows that are inserted
|
||||
*/
|
||||
if( srcTab>=0 && (db->flags & SQLITE_CountRows)!=0 ){
|
||||
if( (db->flags & SQLITE_CountRows)!=0 ){
|
||||
sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
}
|
||||
|
||||
@@ -286,9 +291,6 @@ void sqliteInsert(
|
||||
sqliteVdbeAddOp(v, OP_ColumnCount, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
|
||||
sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC);
|
||||
if( srcTab<0 ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, 1, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}
|
||||
|
||||
@@ -519,12 +521,12 @@ void sqliteGenerateConstraintChecks(
|
||||
}
|
||||
case OE_Ignore: {
|
||||
assert( seenReplace==0 );
|
||||
sqliteVdbeAddOp(v, OP_Pop, nCol+extra+2+hasTwoRecnos, 0);
|
||||
sqliteVdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRecnos, 0);
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
||||
break;
|
||||
}
|
||||
case OE_Replace: {
|
||||
sqliteGenerateRowDelete(v, pTab, base);
|
||||
sqliteGenerateRowDelete(v, pTab, base, 0);
|
||||
if( isUpdate ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1);
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
|
||||
@@ -571,7 +573,7 @@ void sqliteCompleteInsertion(
|
||||
sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, base, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, base, 1);
|
||||
if( isUpdate && recnoChng ){
|
||||
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
|
||||
}
|
||||
|
||||
+11
-1
@@ -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.68 2002/03/06 22:01:36 drh Exp $
|
||||
** $Id: main.c,v 1.69 2002/04/12 10:08:59 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@@ -421,6 +421,13 @@ int sqlite_last_insert_rowid(sqlite *db){
|
||||
return db->lastRowid;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of changes in the most recent call to sqlite_exec().
|
||||
*/
|
||||
int sqlite_changes(sqlite *db){
|
||||
return db->nChange;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an existing SQLite database
|
||||
*/
|
||||
@@ -526,6 +533,8 @@ int sqlite_exec(
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if( db->recursionDepth==0 ){ db->nChange = 0; }
|
||||
db->recursionDepth++;
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = db;
|
||||
sParse.pBe = db->pBe;
|
||||
@@ -544,6 +553,7 @@ int sqlite_exec(
|
||||
if( sParse.rc==SQLITE_SCHEMA ){
|
||||
clearHashTable(db, 1);
|
||||
}
|
||||
db->recursionDepth--;
|
||||
return sParse.rc;
|
||||
}
|
||||
|
||||
|
||||
+15
-3
@@ -18,7 +18,7 @@
|
||||
** file simultaneously, or one process from reading the database while
|
||||
** another is writing.
|
||||
**
|
||||
** @(#) $Id: pager.c,v 1.44 2002/03/06 22:01:36 drh Exp $
|
||||
** @(#) $Id: pager.c,v 1.45 2002/04/18 01:56:58 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@@ -120,6 +120,7 @@ struct Pager {
|
||||
u8 tempFile; /* zFilename is a temporary file */
|
||||
u8 readOnly; /* True for a read-only database */
|
||||
u8 needSync; /* True if an fsync() is needed on the journal */
|
||||
u8 dirtyFile; /* True if database file has changed in any way */
|
||||
u8 *aInJournal; /* One bit for each page in the database file */
|
||||
u8 *aInCkpt; /* One bit for each page in the database */
|
||||
PgHdr *pFirst, *pLast; /* List of free pages */
|
||||
@@ -444,7 +445,7 @@ end_ckpt_playback:
|
||||
*/
|
||||
void sqlitepager_set_cachesize(Pager *pPager, int mxPage){
|
||||
if( mxPage>=0 ){
|
||||
pPager->noSync = 0;
|
||||
pPager->noSync = pPager->tempFile;
|
||||
}else{
|
||||
pPager->noSync = 1;
|
||||
mxPage = -mxPage;
|
||||
@@ -538,6 +539,7 @@ int sqlitepager_open(
|
||||
pPager->tempFile = tempFile;
|
||||
pPager->readOnly = readOnly;
|
||||
pPager->needSync = 0;
|
||||
pPager->noSync = pPager->tempFile;
|
||||
pPager->pFirst = 0;
|
||||
pPager->pLast = 0;
|
||||
pPager->nExtra = nExtra;
|
||||
@@ -1036,7 +1038,8 @@ int sqlitepager_begin(void *pData){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
pPager->journalOpen = 1;
|
||||
pPager->needSync = !pPager->noSync;
|
||||
pPager->needSync = 0;
|
||||
pPager->dirtyFile = 0;
|
||||
pPager->state = SQLITE_WRITELOCK;
|
||||
sqlitepager_pagecount(pPager);
|
||||
pPager->origDbSize = pPager->dbSize;
|
||||
@@ -1088,6 +1091,7 @@ int sqlitepager_write(void *pData){
|
||||
*/
|
||||
pPg->dirty = 1;
|
||||
if( pPg->inJournal && (pPg->inCkpt || pPager->ckptOpen==0) ){
|
||||
pPager->dirtyFile = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -1100,6 +1104,7 @@ int sqlitepager_write(void *pData){
|
||||
*/
|
||||
assert( pPager->state!=SQLITE_UNLOCK );
|
||||
rc = sqlitepager_begin(pData);
|
||||
pPager->dirtyFile = 1;
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
assert( pPager->state==SQLITE_WRITELOCK );
|
||||
assert( pPager->journalOpen );
|
||||
@@ -1238,6 +1243,13 @@ int sqlitepager_commit(Pager *pPager){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
assert( pPager->journalOpen );
|
||||
if( pPager->dirtyFile==0 ){
|
||||
/* Exit early (without doing the time-consuming sqliteOsSync() calls)
|
||||
** if there have been no changes to the database file. */
|
||||
rc = pager_unwritelock(pPager);
|
||||
pPager->dbSize = -1;
|
||||
return rc;
|
||||
}
|
||||
if( pPager->needSync && sqliteOsSync(&pPager->jfd)!=SQLITE_OK ){
|
||||
goto commit_abort;
|
||||
}
|
||||
|
||||
+19
-10
@@ -14,7 +14,7 @@
|
||||
** the parser. Lemon will also generate a header file containing
|
||||
** numeric codes for all of the tokens.
|
||||
**
|
||||
** @(#) $Id: parse.y,v 1.59 2002/03/30 15:26:51 drh Exp $
|
||||
** @(#) $Id: parse.y,v 1.62 2002/04/20 14:24:42 drh Exp $
|
||||
*/
|
||||
%token_prefix TK_
|
||||
%token_type {Token}
|
||||
@@ -255,6 +255,11 @@ selcollist(A) ::= sclp(P) expr(X) as ids(Y). {A = sqliteExprListAppend(P,X,&Y);}
|
||||
selcollist(A) ::= sclp(P) STAR. {
|
||||
A = sqliteExprListAppend(P, sqliteExpr(TK_ALL, 0, 0, 0), 0);
|
||||
}
|
||||
selcollist(A) ::= sclp(P) ids(X) DOT STAR. {
|
||||
Expr *pRight = sqliteExpr(TK_ALL, 0, 0, 0);
|
||||
Expr *pLeft = sqliteExpr(TK_ID, 0, 0, &X);
|
||||
A = sqliteExprListAppend(P, sqliteExpr(TK_DOT, pLeft, pRight, 0), 0);
|
||||
}
|
||||
as ::= .
|
||||
as ::= AS.
|
||||
|
||||
@@ -266,6 +271,7 @@ as ::= AS.
|
||||
%type from {IdList*}
|
||||
%destructor from {sqliteIdListDelete($$);}
|
||||
|
||||
from(A) ::= . {A = sqliteMalloc(sizeof(*A));}
|
||||
from(A) ::= FROM seltablist(X). {A = X;}
|
||||
stl_prefix(A) ::= seltablist(X) COMMA. {A = X;}
|
||||
stl_prefix(A) ::= . {A = 0;}
|
||||
@@ -425,18 +431,21 @@ expr(A) ::= expr(X) BITAND expr(Y). {A = sqliteExpr(TK_BITAND, X, Y, 0);}
|
||||
expr(A) ::= expr(X) BITOR expr(Y). {A = sqliteExpr(TK_BITOR, X, Y, 0);}
|
||||
expr(A) ::= expr(X) LSHIFT expr(Y). {A = sqliteExpr(TK_LSHIFT, X, Y, 0);}
|
||||
expr(A) ::= expr(X) RSHIFT expr(Y). {A = sqliteExpr(TK_RSHIFT, X, Y, 0);}
|
||||
expr(A) ::= expr(X) LIKE expr(Y). {A = sqliteExpr(TK_LIKE, X, Y, 0);}
|
||||
expr(A) ::= expr(X) NOT LIKE expr(Y). {
|
||||
A = sqliteExpr(TK_LIKE, X, Y, 0);
|
||||
A = sqliteExpr(TK_NOT, A, 0, 0);
|
||||
sqliteExprSpan(A,&X->span,&Y->span);
|
||||
}
|
||||
expr(A) ::= expr(X) GLOB expr(Y). {A = sqliteExpr(TK_GLOB,X,Y,0);}
|
||||
expr(A) ::= expr(X) NOT GLOB expr(Y). {
|
||||
A = sqliteExpr(TK_GLOB, X, Y, 0);
|
||||
expr(A) ::= expr(X) likeop(OP) expr(Y). [LIKE] {
|
||||
ExprList *pList = sqliteExprListAppend(0, Y, 0);
|
||||
pList = sqliteExprListAppend(pList, X, 0);
|
||||
A = sqliteExprFunction(pList, &OP);
|
||||
sqliteExprSpan(A, &X->span, &Y->span);
|
||||
}
|
||||
expr(A) ::= expr(X) NOT likeop(OP) expr(Y). [LIKE] {
|
||||
ExprList *pList = sqliteExprListAppend(0, Y, 0);
|
||||
pList = sqliteExprListAppend(pList, X, 0);
|
||||
A = sqliteExprFunction(pList, &OP);
|
||||
A = sqliteExpr(TK_NOT, A, 0, 0);
|
||||
sqliteExprSpan(A,&X->span,&Y->span);
|
||||
}
|
||||
likeop(A) ::= LIKE(X). {A = X;}
|
||||
likeop(A) ::= GLOB(X). {A = X;}
|
||||
expr(A) ::= expr(X) PLUS expr(Y). {A = sqliteExpr(TK_PLUS, X, Y, 0);}
|
||||
expr(A) ::= expr(X) MINUS expr(Y). {A = sqliteExpr(TK_MINUS, X, Y, 0);}
|
||||
expr(A) ::= expr(X) STAR expr(Y). {A = sqliteExpr(TK_STAR, X, Y, 0);}
|
||||
|
||||
+54
-18
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.77 2002/03/23 00:31:29 drh Exp $
|
||||
** $Id: select.c,v 1.78 2002/04/04 02:10:57 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -355,16 +355,16 @@ Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
||||
** (1) Fill in the pTabList->a[].pTab fields in the IdList that
|
||||
** defines the set of tables that should be scanned.
|
||||
**
|
||||
** (2) If the columns to be extracted variable (pEList) is NULL
|
||||
** (meaning that a "*" was used in the SQL statement) then
|
||||
** create a fake pEList containing the names of all columns
|
||||
** of all tables.
|
||||
** (2) Scan the list of columns in the result set (pEList) looking
|
||||
** for instances of the "*" operator or the TABLE.* operator.
|
||||
** If found, expand each "*" to be every column in every table
|
||||
** and TABLE.* to be every column in TABLE.
|
||||
**
|
||||
** Return 0 on success. If there are problems, leave an error message
|
||||
** in pParse and return non-zero.
|
||||
*/
|
||||
static int fillInColumnList(Parse *pParse, Select *p){
|
||||
int i, j, k;
|
||||
int i, j, k, rc;
|
||||
IdList *pTabList;
|
||||
ExprList *pEList;
|
||||
Table *pTab;
|
||||
@@ -410,42 +410,72 @@ static int fillInColumnList(Parse *pParse, Select *p){
|
||||
}
|
||||
|
||||
/* For every "*" that occurs in the column list, insert the names of
|
||||
** all columns in all tables. The parser inserted a special expression
|
||||
** all columns in all tables. And for every TABLE.* insert the names
|
||||
** of all columns in TABLE. The parser inserted a special expression
|
||||
** with the TK_ALL operator for each "*" that it found in the column list.
|
||||
** The following code just has to locate the TK_ALL expressions and expand
|
||||
** each one to the list of all columns in all tables.
|
||||
**
|
||||
** The first loop just checks to see if there are any "*" operators
|
||||
** that need expanding.
|
||||
*/
|
||||
for(k=0; k<pEList->nExpr; k++){
|
||||
if( pEList->a[k].pExpr->op==TK_ALL ) break;
|
||||
Expr *pE = pEList->a[k].pExpr;
|
||||
if( pE->op==TK_ALL ) break;
|
||||
if( pE->op==TK_DOT && pE->pRight && pE->pRight->op==TK_ALL
|
||||
&& pE->pLeft && pE->pLeft->op==TK_ID ) break;
|
||||
}
|
||||
rc = 0;
|
||||
if( k<pEList->nExpr ){
|
||||
/*
|
||||
** If we get here it means the result set contains one or more "*"
|
||||
** operators that need to be expanded. Loop through each expression
|
||||
** in the result set and expand them one by one.
|
||||
*/
|
||||
struct ExprList_item *a = pEList->a;
|
||||
ExprList *pNew = 0;
|
||||
for(k=0; k<pEList->nExpr; k++){
|
||||
if( a[k].pExpr->op!=TK_ALL ){
|
||||
Expr *pE = a[k].pExpr;
|
||||
if( pE->op!=TK_ALL &&
|
||||
(pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){
|
||||
/* This particular expression does not need to be expanded.
|
||||
*/
|
||||
pNew = sqliteExprListAppend(pNew, a[k].pExpr, 0);
|
||||
pNew->a[pNew->nExpr-1].zName = a[k].zName;
|
||||
a[k].pExpr = 0;
|
||||
a[k].zName = 0;
|
||||
}else{
|
||||
/* This expression is a "*" or a "TABLE.*" and needs to be
|
||||
** expanded. */
|
||||
int tableSeen = 0; /* Set to 1 when TABLE matches */
|
||||
Token *pName; /* text of name of TABLE */
|
||||
if( pE->op==TK_DOT && pE->pLeft ){
|
||||
pName = &pE->pLeft->token;
|
||||
}else{
|
||||
pName = 0;
|
||||
}
|
||||
for(i=0; i<pTabList->nId; i++){
|
||||
Table *pTab = pTabList->a[i].pTab;
|
||||
char *zTabName = pTabList->a[i].zAlias;
|
||||
if( zTabName==0 || zTabName[0]==0 ){
|
||||
zTabName = pTab->zName;
|
||||
}
|
||||
if( pName && (zTabName==0 || zTabName[0]==0 ||
|
||||
sqliteStrNICmp(pName->z, zTabName, pName->n)!=0) ){
|
||||
continue;
|
||||
}
|
||||
tableSeen = 1;
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
Expr *pExpr, *pLeft, *pRight;
|
||||
pRight = sqliteExpr(TK_ID, 0, 0, 0);
|
||||
if( pRight==0 ) break;
|
||||
pRight->token.z = pTab->aCol[j].zName;
|
||||
pRight->token.n = strlen(pTab->aCol[j].zName);
|
||||
if( pTab->zName ){
|
||||
if( zTabName ){
|
||||
pLeft = sqliteExpr(TK_ID, 0, 0, 0);
|
||||
if( pLeft==0 ) break;
|
||||
if( pTabList->a[i].zAlias && pTabList->a[i].zAlias[0] ){
|
||||
pLeft->token.z = pTabList->a[i].zAlias;
|
||||
pLeft->token.n = strlen(pTabList->a[i].zAlias);
|
||||
}else{
|
||||
pLeft->token.z = pTab->zName;
|
||||
pLeft->token.n = strlen(pTab->zName);
|
||||
}
|
||||
pLeft->token.z = zTabName;
|
||||
pLeft->token.n = strlen(zTabName);
|
||||
pExpr = sqliteExpr(TK_DOT, pLeft, pRight, 0);
|
||||
if( pExpr==0 ) break;
|
||||
}else{
|
||||
@@ -455,12 +485,18 @@ static int fillInColumnList(Parse *pParse, Select *p){
|
||||
pNew = sqliteExprListAppend(pNew, pExpr, 0);
|
||||
}
|
||||
}
|
||||
if( !tableSeen ){
|
||||
assert( pName!=0 );
|
||||
sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1,
|
||||
pName->z, pName->n, 0);
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqliteExprListDelete(pEList);
|
||||
p->pEList = pNew;
|
||||
}
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+319
-49
@@ -12,15 +12,19 @@
|
||||
** This file contains code to implement the "sqlite" command line
|
||||
** utility for accessing SQLite databases.
|
||||
**
|
||||
** $Id: shell.c,v 1.47 2002/03/03 23:06:01 drh Exp $
|
||||
** $Id: shell.c,v 1.56 2002/04/21 19:06:22 drh Exp $
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "sqlite.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#if !defined(_WIN32) && !defined(WIN32)
|
||||
# include <signal.h>
|
||||
# include <pwd.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
@@ -28,7 +32,10 @@
|
||||
# include <readline/history.h>
|
||||
#else
|
||||
# define readline(p) getline(p,stdin)
|
||||
# define add_history(X)
|
||||
# define add_history(X)
|
||||
# define read_history(X)
|
||||
# define write_history(X)
|
||||
# define stifle_history(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -38,6 +45,24 @@
|
||||
*/
|
||||
static sqlite *db = 0;
|
||||
|
||||
/*
|
||||
** True if an interrupt (Control-C) has been received.
|
||||
*/
|
||||
static int seenInterrupt = 0;
|
||||
|
||||
/*
|
||||
** This is the name of our program. It is set in main(), used
|
||||
** in a number of other places, mostly for error messages.
|
||||
*/
|
||||
static char *Argv0;
|
||||
|
||||
/*
|
||||
** Prompt strings. Initialized in main. Settable with
|
||||
** .prompt main continue
|
||||
*/
|
||||
static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
|
||||
static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
|
||||
|
||||
/*
|
||||
** This routine reads a line of text from standard input, stores
|
||||
** the text in memory obtained from malloc() and returns a pointer
|
||||
@@ -104,15 +129,21 @@ static char *one_input_line(const char *zPrior, FILE *in){
|
||||
return getline(0, in);
|
||||
}
|
||||
if( zPrior && zPrior[0] ){
|
||||
zPrompt = " ...> ";
|
||||
zPrompt = continuePrompt;
|
||||
}else{
|
||||
zPrompt = "sqlite> ";
|
||||
zPrompt = mainPrompt;
|
||||
}
|
||||
zResult = readline(zPrompt);
|
||||
if( zResult ) add_history(zResult);
|
||||
return zResult;
|
||||
}
|
||||
|
||||
struct previous_mode_data {
|
||||
int valid; /* Is there legit data in here? */
|
||||
int mode;
|
||||
int showHeader;
|
||||
int colWidth[100];
|
||||
};
|
||||
/*
|
||||
** An pointer to an instance of this structure is passed from
|
||||
** the main program to the callback. This is used to communicate
|
||||
@@ -129,6 +160,11 @@ struct callback_data {
|
||||
char separator[20]; /* Separator character for MODE_List */
|
||||
int colWidth[100]; /* Requested width of each column when in column mode*/
|
||||
int actualWidth[100]; /* Actual width of each column */
|
||||
char nullvalue[20]; /* The text to print when a NULL comes back from the database */
|
||||
struct previous_mode_data explainPrev;
|
||||
/* Holds the mode information just before .explain ON */
|
||||
char outfile[FILENAME_MAX];
|
||||
/* Filename for *out */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -140,6 +176,16 @@ struct callback_data {
|
||||
#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
|
||||
#define MODE_Html 4 /* Generate an XHTML table */
|
||||
#define MODE_Insert 5 /* Generate SQL "insert" statements */
|
||||
#define MODE_NUM_OF 6
|
||||
|
||||
char *modeDescr[MODE_NUM_OF] = {
|
||||
"line",
|
||||
"column",
|
||||
"list",
|
||||
"semi",
|
||||
"html",
|
||||
"insert"
|
||||
};
|
||||
|
||||
/*
|
||||
** Number of elements in an array
|
||||
@@ -154,7 +200,7 @@ static int is_numeric(const char *z){
|
||||
if( *z=='-' || *z=='+' ){
|
||||
z++;
|
||||
}
|
||||
while( isdigit(*z) ){
|
||||
while( isdigit(*z) ){
|
||||
seen_digit = 1;
|
||||
z++;
|
||||
}
|
||||
@@ -231,6 +277,7 @@ static void output_html_string(FILE *out, const char *z){
|
||||
** This routine runs when the user presses Ctrl-C
|
||||
*/
|
||||
static void interrupt_handler(int NotUsed){
|
||||
seenInterrupt = 1;
|
||||
if( db ) sqlite_interrupt(db);
|
||||
}
|
||||
|
||||
@@ -251,7 +298,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
}
|
||||
if( p->cnt++>0 ) fprintf(p->out,"\n");
|
||||
for(i=0; i<nArg; i++){
|
||||
fprintf(p->out,"%*s = %s\n", w, azCol[i], azArg[i] ? azArg[i] : 0);
|
||||
fprintf(p->out,"%*s = %s\n", w, azCol[i], azArg[i] ? azArg[i] : p->nullvalue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -267,11 +314,11 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
if( w<=0 ){
|
||||
w = strlen(azCol[i] ? azCol[i] : "");
|
||||
if( w<10 ) w = 10;
|
||||
n = strlen(azArg && azArg[i] ? azArg[i] : "");
|
||||
n = strlen(azArg && azArg[i] ? azArg[i] : p->nullvalue);
|
||||
if( w<n ) w = n;
|
||||
}
|
||||
if( i<ArraySize(p->actualWidth) ){
|
||||
p->actualWidth[i] = w;
|
||||
p->actualWidth[i] = w;
|
||||
}
|
||||
if( p->showHeader ){
|
||||
fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
|
||||
@@ -300,7 +347,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
w = 10;
|
||||
}
|
||||
fprintf(p->out,"%-*.*s%s",w,w,
|
||||
azArg[i] ? azArg[i] : "", i==nArg-1 ? "\n": " ");
|
||||
azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -314,7 +361,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
if( azArg==0 ) break;
|
||||
for(i=0; i<nArg; i++){
|
||||
char *z = azArg[i];
|
||||
if( z==0 ) z = "";
|
||||
if( z==0 ) z = p->nullvalue;
|
||||
fprintf(p->out, "%s", z);
|
||||
if( i<nArg-1 ){
|
||||
fprintf(p->out, "%s", p->separator);
|
||||
@@ -338,7 +385,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
fprintf(p->out,"<TR>");
|
||||
for(i=0; i<nArg; i++){
|
||||
fprintf(p->out,"<TD>");
|
||||
output_html_string(p->out, azArg[i] ? azArg[i] : "");
|
||||
output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
|
||||
fprintf(p->out,"</TD>\n");
|
||||
}
|
||||
fprintf(p->out,"</TD></TR>\n");
|
||||
@@ -361,7 +408,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
fprintf(p->out,");\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -419,7 +466,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
d2.mode = MODE_Insert;
|
||||
d2.zDestTable = 0;
|
||||
set_table_name(&d2, azArg[0]);
|
||||
sqlite_exec_printf(p->db,
|
||||
sqlite_exec_printf(p->db,
|
||||
"SELECT * FROM '%q'",
|
||||
callback, &d2, 0, azArg[0]
|
||||
);
|
||||
@@ -431,24 +478,28 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||
/*
|
||||
** Text of a help message
|
||||
*/
|
||||
static char zHelp[] =
|
||||
static char zHelp[] =
|
||||
".dump ?TABLE? ... Dump the database in an text format\n"
|
||||
".echo ON|OFF Turn command echo on or off\n"
|
||||
".exit Exit this program\n"
|
||||
".explain Set output mode suitable for EXPLAIN\n"
|
||||
".header ON|OFF Turn display of headers on or off\n"
|
||||
".explain ON|OFF Turn output mode suitable for EXPLAIN on or off.\n"
|
||||
".header(s) ON|OFF Turn display of headers on or off\n"
|
||||
".help Show this message\n"
|
||||
".indices TABLE Show names of all indices on TABLE\n"
|
||||
".mode MODE Set mode to one of \"line\", \"column\", \n"
|
||||
".mode MODE Set mode to one of \"line(s)\", \"column(s)\", \n"
|
||||
" \"insert\", \"list\", or \"html\"\n"
|
||||
".mode insert TABLE Generate SQL insert statements for TABLE\n"
|
||||
".nullvalue STRING Print STRING instead of nothing for NULL data\n"
|
||||
".output FILENAME Send output to FILENAME\n"
|
||||
".output stdout Send output to the screen\n"
|
||||
".prompt MAIN CONTINUE Replace the standard prompts\n"
|
||||
".quit Exit this program\n"
|
||||
".read FILENAME Execute SQL in FILENAME\n"
|
||||
".reindex ?TABLE? Rebuild indices\n"
|
||||
/* ".rename OLD NEW Change the name of a table or index\n" */
|
||||
".schema ?TABLE? Show the CREATE statements\n"
|
||||
".separator STRING Change separator string for \"list\" mode\n"
|
||||
".show Show the current values for various settings\n"
|
||||
".tables ?PATTERN? List names of tables matching a pattern\n"
|
||||
".timeout MS Try opening locked tables for MS milliseconds\n"
|
||||
".width NUM NUM ... Set column widths for \"column\" mode\n"
|
||||
@@ -460,11 +511,14 @@ static void process_input(struct callback_data *p, FILE *in);
|
||||
/*
|
||||
** If an input line begins with "." then invoke this routine to
|
||||
** process that line.
|
||||
**
|
||||
** Return 1 to exit and 0 to continue.
|
||||
*/
|
||||
static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
static int do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
int i = 1;
|
||||
int nArg = 0;
|
||||
int n, c;
|
||||
int rc = 0;
|
||||
char *azArg[50];
|
||||
|
||||
/* Parse the input line into tokens.
|
||||
@@ -487,7 +541,7 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
|
||||
/* Process the input line.
|
||||
*/
|
||||
if( nArg==0 ) return;
|
||||
if( nArg==0 ) return rc;
|
||||
n = strlen(azArg[0]);
|
||||
c = azArg[0][0];
|
||||
if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
|
||||
@@ -497,19 +551,18 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
sqlite_exec(db,
|
||||
"SELECT name, type, sql FROM sqlite_master "
|
||||
"WHERE type!='meta' AND sql NOT NULL "
|
||||
"ORDER BY tbl_name, type DESC, name",
|
||||
"ORDER BY substr(type,2,1), name",
|
||||
dump_callback, p, &zErrMsg
|
||||
);
|
||||
}else{
|
||||
int i;
|
||||
for(i=1; i<nArg && zErrMsg==0; i++){
|
||||
sqlite_exec_printf(db,
|
||||
sqlite_exec_printf(db,
|
||||
"SELECT name, type, sql FROM sqlite_master "
|
||||
"WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOT NULL "
|
||||
"ORDER BY type DESC, name",
|
||||
"ORDER BY substr(type,2,1), name",
|
||||
dump_callback, p, &zErrMsg, azArg[i]
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
if( zErrMsg ){
|
||||
@@ -531,26 +584,59 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
val = 1;
|
||||
}else if( strcmp(z,"yes")==0 ){
|
||||
val = 1;
|
||||
}
|
||||
}
|
||||
p->echoOn = val;
|
||||
}else
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
|
||||
sqlite_close(db);
|
||||
exit(0);
|
||||
rc = 1;
|
||||
}else
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
|
||||
p->mode = MODE_Column;
|
||||
p->showHeader = 1;
|
||||
p->colWidth[0] = 4;
|
||||
p->colWidth[1] = 12;
|
||||
p->colWidth[2] = 10;
|
||||
p->colWidth[3] = 10;
|
||||
p->colWidth[4] = 35;
|
||||
int j;
|
||||
char *z = nArg>=2 ? azArg[1] : "1";
|
||||
int val = atoi(z);
|
||||
for(j=0; z[j]; j++){
|
||||
if( isupper(z[j]) ) z[j] = tolower(z[j]);
|
||||
}
|
||||
if( strcmp(z,"on")==0 ){
|
||||
val = 1;
|
||||
}else if( strcmp(z,"yes")==0 ){
|
||||
val = 1;
|
||||
}
|
||||
if(val == 1) {
|
||||
if(!p->explainPrev.valid) {
|
||||
p->explainPrev.valid = 1;
|
||||
p->explainPrev.mode = p->mode;
|
||||
p->explainPrev.showHeader = p->showHeader;
|
||||
memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
|
||||
}
|
||||
/* We could put this code under the !p->explainValid
|
||||
** condition so that it does not execute if we are already in
|
||||
** explain mode. However, always executing it allows us an easy
|
||||
** was to reset to explain mode in case the user previously
|
||||
** did an .explain followed by a .width, .mode or .header
|
||||
** command.
|
||||
*/
|
||||
p->mode = MODE_Column;
|
||||
p->showHeader = 1;
|
||||
memset(p->colWidth,0,ArraySize(p->colWidth));
|
||||
p->colWidth[0] = 4;
|
||||
p->colWidth[1] = 12;
|
||||
p->colWidth[2] = 10;
|
||||
p->colWidth[3] = 10;
|
||||
p->colWidth[4] = 35;
|
||||
}else if (p->explainPrev.valid) {
|
||||
p->explainPrev.valid = 0;
|
||||
p->mode = p->explainPrev.mode;
|
||||
p->showHeader = p->explainPrev.showHeader;
|
||||
memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
|
||||
if( c=='h' && (strncmp(azArg[0], "header", n)==0
|
||||
||
|
||||
strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
|
||||
int j;
|
||||
char *z = azArg[1];
|
||||
int val = atoi(azArg[1]);
|
||||
@@ -561,7 +647,7 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
val = 1;
|
||||
}else if( strcmp(z,"yes")==0 ){
|
||||
val = 1;
|
||||
}
|
||||
}
|
||||
p->showHeader = val;
|
||||
}else
|
||||
|
||||
@@ -575,7 +661,7 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
memcpy(&data, p, sizeof(data));
|
||||
data.showHeader = 0;
|
||||
data.mode = MODE_List;
|
||||
sqlite_exec_printf(db,
|
||||
sqlite_exec_printf(db,
|
||||
"SELECT name FROM sqlite_master "
|
||||
"WHERE type='index' AND tbl_name LIKE '%q' "
|
||||
"ORDER BY name",
|
||||
@@ -589,9 +675,13 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
|
||||
if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
|
||||
int n2 = strlen(azArg[1]);
|
||||
if( strncmp(azArg[1],"line",n2)==0 ){
|
||||
if( strncmp(azArg[1],"line",n2)==0
|
||||
||
|
||||
strncmp(azArg[1],"lines",n2)==0 ){
|
||||
p->mode = MODE_Line;
|
||||
}else if( strncmp(azArg[1],"column",n2)==0 ){
|
||||
}else if( strncmp(azArg[1],"column",n2)==0
|
||||
||
|
||||
strncmp(azArg[1],"columns",n2)==0 ){
|
||||
p->mode = MODE_Column;
|
||||
}else if( strncmp(azArg[1],"list",n2)==0 ){
|
||||
p->mode = MODE_List;
|
||||
@@ -609,21 +699,42 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
|
||||
sprintf(p->nullvalue, "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
|
||||
if( p->out!=stdout ){
|
||||
fclose(p->out);
|
||||
}
|
||||
if( strcmp(azArg[1],"stdout")==0 ){
|
||||
p->out = stdout;
|
||||
strcpy(p->outfile,"stdout");
|
||||
}else{
|
||||
p->out = fopen(azArg[1], "w");
|
||||
if( p->out==0 ){
|
||||
fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
|
||||
p->out = stdout;
|
||||
} else {
|
||||
strcpy(p->outfile,azArg[1]);
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
|
||||
if( nArg >= 2) {
|
||||
strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
|
||||
}
|
||||
if( nArg >= 3) {
|
||||
strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
|
||||
sqlite_close(db);
|
||||
exit(0);
|
||||
}else
|
||||
|
||||
if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
|
||||
FILE *alt = fopen(azArg[1], "r");
|
||||
if( alt==0 ){
|
||||
@@ -714,6 +825,23 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "show", n)==0){
|
||||
int i;
|
||||
fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
|
||||
fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
|
||||
fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
|
||||
fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
|
||||
fprintf(p->out,"%9.9s: %s\n","nullvalue", p->nullvalue);
|
||||
fprintf(p->out,"%9.9s: %s\n","output",
|
||||
strlen(p->outfile) ? p->outfile : "stdout");
|
||||
fprintf(p->out,"%9.9s: %s\n","separator", p->separator);
|
||||
fprintf(p->out,"%9.9s: ","width");
|
||||
for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
|
||||
fprintf(p->out,"%d ",p->colWidth[i]);
|
||||
}
|
||||
fprintf(p->out,"\n\n");
|
||||
}else
|
||||
|
||||
if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
|
||||
char **azResult;
|
||||
int nRow, rc;
|
||||
@@ -772,22 +900,35 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
}else
|
||||
|
||||
{
|
||||
fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
|
||||
azArg[0]);
|
||||
fprintf(stderr, "unknown command or invalid arguments: "
|
||||
" \"%s\". Enter \".help\" for help\n", azArg[0]);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static char *Argv0;
|
||||
/*
|
||||
** Read input from *in and process it. If *in==0 then input
|
||||
** is interactive - the user is typing it it. Otherwise, input
|
||||
** is coming from a file or device. A prompt is issued and history
|
||||
** is saved only if input is interactive. An interrupt signal will
|
||||
** cause this routine to exit immediately, unless input is interactive.
|
||||
*/
|
||||
static void process_input(struct callback_data *p, FILE *in){
|
||||
char *zLine;
|
||||
char *zSql = 0;
|
||||
int nSql = 0;
|
||||
char *zErrMsg;
|
||||
while( (zLine = one_input_line(zSql, in))!=0 ){
|
||||
while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){
|
||||
if( seenInterrupt ){
|
||||
if( in!=0 ) break;
|
||||
seenInterrupt = 0;
|
||||
}
|
||||
if( p->echoOn ) printf("%s\n", zLine);
|
||||
if( zLine && zLine[0]=='.' && nSql==0 ){
|
||||
do_meta_command(zLine, db, p);
|
||||
int rc = do_meta_command(zLine, db, p);
|
||||
free(zLine);
|
||||
if( rc ) break;
|
||||
continue;
|
||||
}
|
||||
if( zSql==0 ){
|
||||
@@ -812,7 +953,7 @@ static void process_input(struct callback_data *p, FILE *in){
|
||||
free(zLine);
|
||||
if( zSql && sqlite_complete(zSql) ){
|
||||
p->cnt = 0;
|
||||
if( sqlite_exec(db, zSql, callback, p, &zErrMsg)!=0
|
||||
if( sqlite_exec(db, zSql, callback, p, &zErrMsg)!=0
|
||||
&& zErrMsg!=0 ){
|
||||
if( in!=0 && !p->echoOn ) printf("%s\n",zSql);
|
||||
printf("SQL error: %s\n", zErrMsg);
|
||||
@@ -830,20 +971,130 @@ static void process_input(struct callback_data *p, FILE *in){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pathname which is the user's home directory. A
|
||||
** 0 return indicates an error of some kind. Space to hold the
|
||||
** resulting string is obtained from malloc(). The calling
|
||||
** function should free the result.
|
||||
*/
|
||||
static char *find_home_dir(void){
|
||||
char *home_dir = NULL;
|
||||
|
||||
#if !defined(_WIN32) && !defined(WIN32)
|
||||
struct passwd *pwent;
|
||||
uid_t uid = getuid();
|
||||
while( (pwent=getpwent()) != NULL) {
|
||||
if(pwent->pw_uid == uid) {
|
||||
home_dir = pwent->pw_dir;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!home_dir) {
|
||||
home_dir = getenv("HOME");
|
||||
if (!home_dir) {
|
||||
home_dir = getenv("HOMEPATH"); /* Windows? */
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
if (!home_dir) {
|
||||
home_dir = "c:";
|
||||
}
|
||||
#endif
|
||||
|
||||
if( home_dir ){
|
||||
char *z = malloc( strlen(home_dir)+1 );
|
||||
if( z ) strcpy(z, home_dir);
|
||||
home_dir = z;
|
||||
}
|
||||
|
||||
return home_dir;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read input from the file given by sqliterc_override. Or if that
|
||||
** parameter is NULL, take input from ~/.sqliterc
|
||||
*/
|
||||
static void process_sqliterc(struct callback_data *p, char *sqliterc_override){
|
||||
char *home_dir = NULL;
|
||||
char *sqliterc = sqliterc_override;
|
||||
FILE *in = NULL;
|
||||
|
||||
if (sqliterc == NULL) {
|
||||
home_dir = find_home_dir();
|
||||
if( home_dir==0 ){
|
||||
fprintf(stderr,"%s: cannot locate your home directory!\n", Argv0);
|
||||
return;
|
||||
}
|
||||
sqliterc = malloc(strlen(home_dir) + 15);
|
||||
if( sqliterc==0 ){
|
||||
fprintf(stderr,"%s: out of memory!\n", Argv0);
|
||||
exit(1);
|
||||
}
|
||||
sprintf(sqliterc,"%s/.sqliterc",home_dir);
|
||||
free(home_dir);
|
||||
}
|
||||
in = fopen(sqliterc,"r");
|
||||
if(in) {
|
||||
printf("Loading resources from %s\n",sqliterc);
|
||||
process_input(p,in);
|
||||
fclose(in);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize the state information in data
|
||||
*/
|
||||
void main_init(struct callback_data *data) {
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->mode = MODE_List;
|
||||
strcpy(data->separator,"|");
|
||||
data->showHeader = 0;
|
||||
strcpy(mainPrompt,"sqlite> ");
|
||||
strcpy(continuePrompt," ...> ");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
char *zErrMsg = 0;
|
||||
struct callback_data data;
|
||||
int origArgc = argc;
|
||||
char **origArgv = argv;
|
||||
|
||||
Argv0 = argv[0];
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.mode = MODE_List;
|
||||
strcpy(data.separator,"|");
|
||||
data.showHeader = 0;
|
||||
main_init(&data);
|
||||
process_sqliterc(&data,NULL);
|
||||
|
||||
#ifdef SIGINT
|
||||
signal(SIGINT, interrupt_handler);
|
||||
#endif
|
||||
while( argc>=2 && argv[1][0]=='-' ){
|
||||
if( strcmp(argv[1],"-html")==0 ){
|
||||
if( argc>=3 && strcmp(argv[1],"-init")==0 ){
|
||||
/* If we get a -init to do, we have to pretend that
|
||||
** it replaced the .sqliterc file. Soooo, in order to
|
||||
** do that we need to start from scratch...*/
|
||||
main_init(&data);
|
||||
|
||||
/* treat this file as the sqliterc... */
|
||||
process_sqliterc(&data,argv[2]);
|
||||
|
||||
/* fix up the command line so we do not re-read
|
||||
** the option next time around... */
|
||||
{
|
||||
int i = 1;
|
||||
for(i=1;i<=argc-2;i++) {
|
||||
argv[i] = argv[i+2];
|
||||
}
|
||||
}
|
||||
origArgc-=2;
|
||||
|
||||
/* and reset the command line options to be re-read.*/
|
||||
argv = origArgv;
|
||||
argc = origArgc;
|
||||
|
||||
}else if( strcmp(argv[1],"-html")==0 ){
|
||||
data.mode = MODE_Html;
|
||||
argc--;
|
||||
argv++;
|
||||
@@ -855,10 +1106,18 @@ int main(int argc, char **argv){
|
||||
data.mode = MODE_Line;
|
||||
argc--;
|
||||
argv++;
|
||||
}else if( strcmp(argv[1],"-column")==0 ){
|
||||
data.mode = MODE_Column;
|
||||
argc--;
|
||||
argv++;
|
||||
}else if( argc>=3 && strcmp(argv[1],"-separator")==0 ){
|
||||
sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
}else if( argc>=3 && strcmp(argv[1],"-nullvalue")==0 ){
|
||||
sprintf(data.nullvalue,"%.*s",(int)sizeof(data.nullvalue)-1,argv[2]);
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
}else if( strcmp(argv[1],"-header")==0 ){
|
||||
data.showHeader = 1;
|
||||
argc--;
|
||||
@@ -910,12 +1169,23 @@ int main(int argc, char **argv){
|
||||
}else{
|
||||
extern int isatty();
|
||||
if( isatty(0) ){
|
||||
char *zHome;
|
||||
char *zHistory = 0;
|
||||
printf(
|
||||
"SQLite version %s\n"
|
||||
"Enter \".help\" for instructions\n",
|
||||
sqlite_version
|
||||
);
|
||||
zHome = find_home_dir();
|
||||
if( zHome && (zHistory = malloc(strlen(zHome)+20))!=0 ){
|
||||
sprintf(zHistory,"%s/.sqlite_history", zHome);
|
||||
}
|
||||
if( zHistory ) read_history(zHistory);
|
||||
process_input(&data, 0);
|
||||
if( zHistory ){
|
||||
stifle_history(100);
|
||||
write_history(zHistory);
|
||||
}
|
||||
}else{
|
||||
process_input(&data, stdin);
|
||||
}
|
||||
|
||||
+23
-1
@@ -12,7 +12,7 @@
|
||||
** This header file defines the interface that the SQLite library
|
||||
** presents to client programs.
|
||||
**
|
||||
** @(#) $Id: sqlite.h.in,v 1.29 2002/03/08 02:12:00 drh Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.30 2002/04/12 10:08:59 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_H_
|
||||
#define _SQLITE_H_
|
||||
@@ -173,6 +173,28 @@ int sqlite_exec(
|
||||
*/
|
||||
int sqlite_last_insert_rowid(sqlite*);
|
||||
|
||||
/*
|
||||
** This function returns the number of database rows that were changed
|
||||
** (or inserted or deleted) by the most recent called sqlite_exec().
|
||||
**
|
||||
** All changes are counted, even if they were later undone by a
|
||||
** ROLLBACK or ABORT. Except, changes associated with creating and
|
||||
** dropping tables are not counted.
|
||||
**
|
||||
** If a callback invokes sqlite_exec() recursively, then the changes
|
||||
** in the inner, recursive call are counted together with the changes
|
||||
** in the outer call.
|
||||
**
|
||||
** SQLite implements the command "DELETE FROM table" without a WHERE clause
|
||||
** by dropping and recreating the table. (This is much faster than going
|
||||
** through and deleting individual elements form the table.) Because of
|
||||
** this optimization, the change count for "DELETE FROM table" will be
|
||||
** zero regardless of the number of elements that were originally in the
|
||||
** table. To get an accurate count of the number of rows deleted, use
|
||||
** "DELETE FROM table WHERE 1" instead.
|
||||
*/
|
||||
int sqlite_changes(sqlite*);
|
||||
|
||||
/* If the parameter to this routine is one of the return value constants
|
||||
** defined above, then this routine returns a constant text string which
|
||||
** descripts (in English) the meaning of the return value.
|
||||
|
||||
+4
-2
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.104 2002/03/12 23:10:05 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.105 2002/04/12 10:08:59 drh Exp $
|
||||
*/
|
||||
#include "sqlite.h"
|
||||
#include "hash.h"
|
||||
@@ -167,6 +167,8 @@ struct sqlite {
|
||||
int lastRowid; /* ROWID of most recent insert */
|
||||
int priorNewRowid; /* Last randomly generated ROWID */
|
||||
int onError; /* Default conflict algorithm */
|
||||
int nChange; /* Number of rows changed */
|
||||
int recursionDepth; /* Number of nested calls to sqlite_exec() */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -630,7 +632,7 @@ void sqliteCommitTransaction(Parse*);
|
||||
void sqliteRollbackTransaction(Parse*);
|
||||
char *sqlite_mprintf(const char *, ...);
|
||||
int sqliteExprIsConstant(Expr*);
|
||||
void sqliteGenerateRowDelete(Vdbe*, Table*, int);
|
||||
void sqliteGenerateRowDelete(Vdbe*, Table*, int, int);
|
||||
void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*);
|
||||
void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
|
||||
void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int);
|
||||
|
||||
+24
-3
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** A TCL Interface to SQLite
|
||||
**
|
||||
** $Id: tclsqlite.c,v 1.30 2002/03/11 02:06:13 drh Exp $
|
||||
** $Id: tclsqlite.c,v 1.31 2002/04/12 10:08:59 drh Exp $
|
||||
*/
|
||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||
|
||||
@@ -268,10 +268,12 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
SqliteDb *pDb = (SqliteDb*)cd;
|
||||
int choice;
|
||||
static char *DB_optStrs[] = {
|
||||
"busy", "close", "complete", "eval", "last_insert_rowid", "timeout", 0
|
||||
"busy", "changes", "close", "complete",
|
||||
"eval", "last_insert_rowid", "timeout", 0
|
||||
};
|
||||
enum DB_opts {
|
||||
DB_BUSY, DB_CLOSE, DB_COMPLETE, DB_EVAL, DB_LAST_INSERT_ROWID, DB_TIMEOUT
|
||||
DB_BUSY, DB_CHANGES, DB_CLOSE, DB_COMPLETE,
|
||||
DB_EVAL, DB_LAST_INSERT_ROWID, DB_TIMEOUT
|
||||
};
|
||||
|
||||
if( objc<2 ){
|
||||
@@ -320,6 +322,25 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** $db changes
|
||||
**
|
||||
** Return the number of rows that were modified, inserted, or deleted by
|
||||
** the most recent "eval".
|
||||
*/
|
||||
case DB_CHANGES: {
|
||||
Tcl_Obj *pResult;
|
||||
int nChange;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
nChange = sqlite_changes(pDb->db);
|
||||
pResult = Tcl_GetObjResult(interp);
|
||||
Tcl_SetIntObj(pResult, nChange);
|
||||
break;
|
||||
}
|
||||
|
||||
/* $db close
|
||||
**
|
||||
** Shutdown the database
|
||||
|
||||
+16
-86
@@ -30,7 +30,7 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.136 2002/04/02 01:44:51 drh Exp $
|
||||
** $Id: vdbe.c,v 1.139 2002/04/20 14:24:42 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -1058,11 +1058,11 @@ static char *zOpName[] = { 0,
|
||||
"MustBeInt", "Add", "AddImm", "Subtract",
|
||||
"Multiply", "Divide", "Remainder", "BitAnd",
|
||||
"BitOr", "BitNot", "ShiftLeft", "ShiftRight",
|
||||
"AbsValue", "Like", "Glob", "Eq",
|
||||
"Ne", "Lt", "Le", "Gt",
|
||||
"Ge", "IsNull", "NotNull", "Negative",
|
||||
"And", "Or", "Not", "Concat",
|
||||
"Noop", "Function", "Limit",
|
||||
"AbsValue", "Eq", "Ne", "Lt",
|
||||
"Le", "Gt", "Ge", "IsNull",
|
||||
"NotNull", "Negative", "And", "Or",
|
||||
"Not", "Concat", "Noop", "Function",
|
||||
"Limit",
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2011,69 +2011,6 @@ case OP_Ge: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Like P1 P2 *
|
||||
**
|
||||
** Pop the top two elements from the stack. The top-most is a
|
||||
** "like" pattern -- the right operand of the SQL "LIKE" operator.
|
||||
** The lower element is the string to compare against the like
|
||||
** pattern. Jump to P2 if the two compare, and fall through without
|
||||
** jumping if they do not. The '%' in the top-most element matches
|
||||
** any sequence of zero or more characters in the lower element. The
|
||||
** '_' character in the topmost matches any single character of the
|
||||
** lower element. Case is ignored for this comparison.
|
||||
**
|
||||
** If P1 is not zero, the sense of the test is inverted and we
|
||||
** have a "NOT LIKE" operator. The jump is made if the two values
|
||||
** are different.
|
||||
*/
|
||||
case OP_Like: {
|
||||
int tos = p->tos;
|
||||
int nos = tos - 1;
|
||||
int c;
|
||||
VERIFY( if( nos<0 ) goto not_enough_stack; )
|
||||
if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
|
||||
c = sqliteLikeCompare((unsigned char*)zStack[tos],
|
||||
(unsigned char*)zStack[nos]);
|
||||
POPSTACK;
|
||||
POPSTACK;
|
||||
if( pOp->p1 ) c = !c;
|
||||
if( c ) pc = pOp->p2-1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Glob P1 P2 *
|
||||
**
|
||||
** Pop the top two elements from the stack. The top-most is a
|
||||
** "glob" pattern. The lower element is the string to compare
|
||||
** against the glob pattern.
|
||||
**
|
||||
** Jump to P2 if the two compare, and fall through without
|
||||
** jumping if they do not. The '*' in the top-most element matches
|
||||
** any sequence of zero or more characters in the lower element. The
|
||||
** '?' character in the topmost matches any single character of the
|
||||
** lower element. [...] matches a range of characters. [^...]
|
||||
** matches any character not in the range. Case is significant
|
||||
** for globs.
|
||||
**
|
||||
** If P1 is not zero, the sense of the test is inverted and we
|
||||
** have a "NOT GLOB" operator. The jump is made if the two values
|
||||
** are different.
|
||||
*/
|
||||
case OP_Glob: {
|
||||
int tos = p->tos;
|
||||
int nos = tos - 1;
|
||||
int c;
|
||||
VERIFY( if( nos<0 ) goto not_enough_stack; )
|
||||
if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
|
||||
c = sqliteGlobCompare((unsigned char*)zStack[tos],
|
||||
(unsigned char*)zStack[nos]);
|
||||
POPSTACK;
|
||||
POPSTACK;
|
||||
if( pOp->p1 ) c = !c;
|
||||
if( c ) pc = pOp->p2-1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: And * * *
|
||||
**
|
||||
** Pop two values off the stack. Take the logical AND of the
|
||||
@@ -3155,19 +3092,16 @@ case OP_NewRecno: {
|
||||
** stack. The key is the next value down on the stack. The key must
|
||||
** be an integer. The stack is popped twice by this instruction.
|
||||
**
|
||||
** If P2==1 then overwriting is prohibited. If a prior entry with
|
||||
** the same key exists, an SQLITE_CONSTRAINT exception is raised.
|
||||
** If P2==1 then the row change count is incremented. If P2==0 the
|
||||
** row change count is unmodified.
|
||||
*/
|
||||
/* Opcode: PutStrKey P1 P2 *
|
||||
/* Opcode: PutStrKey P1 * *
|
||||
**
|
||||
** Write an entry into the database file P1. A new entry is
|
||||
** created if it doesn't already exist or the data for an existing
|
||||
** entry is overwritten. The data is the value on the top of the
|
||||
** stack. The key is the next value down on the stack. The key must
|
||||
** be a string. The stack is popped twice by this instruction.
|
||||
**
|
||||
** If P2==1 then overwriting is prohibited. If a prior entry with
|
||||
** the same key exists, an SQLITE_CONSTRAINT exception is raised.
|
||||
*/
|
||||
case OP_PutIntKey:
|
||||
case OP_PutStrKey: {
|
||||
@@ -3188,16 +3122,7 @@ case OP_PutStrKey: {
|
||||
iKey = intToKey(aStack[nos].i);
|
||||
zKey = (char*)&iKey;
|
||||
db->lastRowid = aStack[nos].i;
|
||||
}
|
||||
if( pOp->p2 ){
|
||||
int res;
|
||||
rc = sqliteBtreeMoveto(p->aCsr[i].pCursor, zKey, nKey, &res);
|
||||
if( res==0 && rc==SQLITE_OK ){
|
||||
rc = SQLITE_CONSTRAINT;
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
if( pOp->p2 ) db->nChange++;
|
||||
}
|
||||
rc = sqliteBtreeInsert(p->aCsr[i].pCursor, zKey, nKey,
|
||||
zStack[tos], aStack[tos].n);
|
||||
@@ -3208,7 +3133,7 @@ case OP_PutStrKey: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Delete P1 * *
|
||||
/* Opcode: Delete P1 P2 *
|
||||
**
|
||||
** Delete the record at which the P1 cursor is currently pointing.
|
||||
**
|
||||
@@ -3216,12 +3141,16 @@ case OP_PutStrKey: {
|
||||
** record in the table. If it is left pointing at the next record, then
|
||||
** the next Next instruction will be a no-op. Hence it is OK to delete
|
||||
** a record from within an Next loop.
|
||||
**
|
||||
** The row change counter is incremented if P2==1 and is unmodified
|
||||
** if P2==0.
|
||||
*/
|
||||
case OP_Delete: {
|
||||
int i = pOp->p1;
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){
|
||||
rc = sqliteBtreeDelete(p->aCsr[i].pCursor);
|
||||
}
|
||||
if( pOp->p2 ) db->nChange++;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4715,6 +4644,7 @@ cleanup:
|
||||
}
|
||||
sqliteBtreeCommitCkpt(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
|
||||
assert( p->tos<pc );
|
||||
return rc;
|
||||
|
||||
/* Jump to here if a malloc() fails. It's hard to get a malloc()
|
||||
|
||||
+18
-20
@@ -15,7 +15,7 @@
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
**
|
||||
** $Id: vdbe.h,v 1.49 2002/02/28 03:31:12 drh Exp $
|
||||
** $Id: vdbe.h,v 1.50 2002/04/20 14:24:43 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@@ -180,27 +180,25 @@ typedef struct VdbeOp VdbeOp;
|
||||
#define OP_ShiftLeft 95
|
||||
#define OP_ShiftRight 96
|
||||
#define OP_AbsValue 97
|
||||
#define OP_Like 98
|
||||
#define OP_Glob 99
|
||||
#define OP_Eq 100
|
||||
#define OP_Ne 101
|
||||
#define OP_Lt 102
|
||||
#define OP_Le 103
|
||||
#define OP_Gt 104
|
||||
#define OP_Ge 105
|
||||
#define OP_IsNull 106
|
||||
#define OP_NotNull 107
|
||||
#define OP_Negative 108
|
||||
#define OP_And 109
|
||||
#define OP_Or 110
|
||||
#define OP_Not 111
|
||||
#define OP_Concat 112
|
||||
#define OP_Noop 113
|
||||
#define OP_Function 114
|
||||
#define OP_Eq 98
|
||||
#define OP_Ne 99
|
||||
#define OP_Lt 100
|
||||
#define OP_Le 101
|
||||
#define OP_Gt 102
|
||||
#define OP_Ge 103
|
||||
#define OP_IsNull 104
|
||||
#define OP_NotNull 105
|
||||
#define OP_Negative 106
|
||||
#define OP_And 107
|
||||
#define OP_Or 108
|
||||
#define OP_Not 109
|
||||
#define OP_Concat 110
|
||||
#define OP_Noop 111
|
||||
#define OP_Function 112
|
||||
|
||||
#define OP_Limit 115
|
||||
#define OP_Limit 113
|
||||
|
||||
#define OP_MAX 115
|
||||
#define OP_MAX 113
|
||||
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
|
||||
+115
-1
@@ -13,7 +13,7 @@
|
||||
# This file implements tests for the conflict resolution extension
|
||||
# to SQLite.
|
||||
#
|
||||
# $Id: conflict.test,v 1.8 2002/02/19 13:39:23 drh Exp $
|
||||
# $Id: conflict.test,v 1.11 2002/04/12 10:09:00 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -377,6 +377,120 @@ foreach {i conf1 conf2 cmd t0 t1 t2} {
|
||||
} [list $t0 $t1 $t2]
|
||||
}
|
||||
|
||||
# Test to make sure a lot of IGNOREs don't cause a stack overflow
|
||||
#
|
||||
do_test conflict-7.1 {
|
||||
execsql {
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t2;
|
||||
DROP TABLE t3;
|
||||
CREATE TABLE t1(a unique, b);
|
||||
}
|
||||
for {set i 1} {$i<=50} {incr i} {
|
||||
execsql "INSERT into t1 values($i,[expr {$i+1}]);"
|
||||
}
|
||||
execsql {
|
||||
SELECT count(*), min(a), max(b) FROM t1;
|
||||
}
|
||||
} {50 1 51}
|
||||
do_test conflict-7.2 {
|
||||
execsql {
|
||||
PRAGMA count_changes=on;
|
||||
UPDATE OR IGNORE t1 SET a=1000;
|
||||
}
|
||||
} {1}
|
||||
do_test conflict-7.2.1 {
|
||||
db changes
|
||||
} {1}
|
||||
do_test conflict-7.3 {
|
||||
execsql {
|
||||
SELECT b FROM t1 WHERE a=1000;
|
||||
}
|
||||
} {2}
|
||||
do_test conflict-7.4 {
|
||||
execsql {
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
} {50}
|
||||
do_test conflict-7.5 {
|
||||
execsql {
|
||||
PRAGMA count_changes=on;
|
||||
UPDATE OR REPLACE t1 SET a=1001;
|
||||
}
|
||||
} {50}
|
||||
do_test conflict-7.5.1 {
|
||||
db changes
|
||||
} {50}
|
||||
do_test conflict-7.6 {
|
||||
execsql {
|
||||
SELECT b FROM t1 WHERE a=1001;
|
||||
}
|
||||
} {51}
|
||||
do_test conflict-7.7 {
|
||||
execsql {
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
} {1}
|
||||
do_test conflict-7.7.1 {
|
||||
db changes
|
||||
} {0}
|
||||
|
||||
# Make sure the row count is right for rows that are ignored on
|
||||
# an insert.
|
||||
#
|
||||
do_test conflict-8.1 {
|
||||
execsql {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1 VALUES(1,2);
|
||||
}
|
||||
execsql {
|
||||
INSERT OR IGNORE INTO t1 VALUES(2,3);
|
||||
}
|
||||
} {1}
|
||||
do_test conflict-8.1.1 {
|
||||
db changes
|
||||
} {1}
|
||||
do_test conflict-8.2 {
|
||||
execsql {
|
||||
INSERT OR IGNORE INTO t1 VALUES(2,4);
|
||||
}
|
||||
} {0}
|
||||
do_test conflict-8.2.1 {
|
||||
db changes
|
||||
} {0}
|
||||
do_test conflict-8.3 {
|
||||
execsql {
|
||||
INSERT OR REPLACE INTO t1 VALUES(2,4);
|
||||
}
|
||||
} {1}
|
||||
do_test conflict-8.3.1 {
|
||||
db changes
|
||||
} {1}
|
||||
do_test conflict-8.4 {
|
||||
execsql {
|
||||
INSERT OR IGNORE INTO t1 SELECT * FROM t1;
|
||||
}
|
||||
} {0}
|
||||
do_test conflict-8.4.1 {
|
||||
db changes
|
||||
} {0}
|
||||
do_test conflict-8.5 {
|
||||
execsql {
|
||||
INSERT OR IGNORE INTO t1 SELECT a+2,b+2 FROM t1;
|
||||
}
|
||||
} {2}
|
||||
do_test conflict-8.5.1 {
|
||||
db changes
|
||||
} {2}
|
||||
do_test conflict-8.6 {
|
||||
execsql {
|
||||
INSERT OR IGNORE INTO t1 SELECT a+3,b+3 FROM t1;
|
||||
}
|
||||
} {3}
|
||||
do_test conflict-8.6.1 {
|
||||
db changes
|
||||
} {3}
|
||||
|
||||
do_test insert-99.1 {
|
||||
set x [execsql {PRAGMA integrity_check}]
|
||||
if {$x==""} {set x ok}
|
||||
|
||||
+7
-1
@@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing built-in functions.
|
||||
#
|
||||
# $Id: func.test,v 1.9 2002/03/02 17:04:09 drh Exp $
|
||||
# $Id: func.test,v 1.10 2002/04/06 14:10:47 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -230,5 +230,11 @@ do_test func-6.2 {
|
||||
execsql {SELECT coalesce(upper(a),'nil') FROM t2}
|
||||
} {1 nil 345 nil 67890}
|
||||
|
||||
# Test the last_insert_rowid() function
|
||||
#
|
||||
do_test func-7.1 {
|
||||
execsql {SELECT last_insert_rowid()}
|
||||
} [db last_insert_rowid]
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+16
-1
@@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the INSERT statement.
|
||||
#
|
||||
# $Id: insert.test,v 1.9 2002/02/19 13:39:23 drh Exp $
|
||||
# $Id: insert.test,v 1.10 2002/04/12 13:11:53 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -162,6 +162,8 @@ do_test insert-3.5 {
|
||||
set x
|
||||
} {ok}
|
||||
|
||||
# Test of expressions in the VALUES clause
|
||||
#
|
||||
do_test insert-4.1 {
|
||||
execsql {
|
||||
CREATE TABLE t3(a,b,c);
|
||||
@@ -192,5 +194,18 @@ do_test insert-4.5 {
|
||||
SELECT b,c FROM t3 WHERE a IS NULL;
|
||||
}
|
||||
} {6 7}
|
||||
do_test insert-4.6 {
|
||||
catchsql {
|
||||
INSERT INTO t3 VALUES(notafunc(2,3),2,3);
|
||||
}
|
||||
} {1 {no such function: notafunc}}
|
||||
do_test insert-4.7 {
|
||||
execsql {
|
||||
INSERT INTO t3 VALUES(min(1,2,3),max(1,2,3),99);
|
||||
SELECT * FROM t3 WHERE c=99;
|
||||
}
|
||||
} {1 3 99}
|
||||
|
||||
# Test
|
||||
|
||||
finish_test
|
||||
|
||||
+12
-1
@@ -12,7 +12,7 @@
|
||||
# focus of this file is testing the INSERT statement that takes is
|
||||
# result from a SELECT.
|
||||
#
|
||||
# $Id: insert2.test,v 1.8 2002/03/03 02:49:52 drh Exp $
|
||||
# $Id: insert2.test,v 1.9 2002/04/12 10:09:00 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -38,6 +38,9 @@ do_test insert2-1.1.1 {
|
||||
}
|
||||
} {6}
|
||||
do_test insert2-1.1.2 {
|
||||
db changes
|
||||
} {6}
|
||||
do_test insert2-1.1.3 {
|
||||
execsql {SELECT * FROM t1 ORDER BY log}
|
||||
} {0 1 1 1 2 2 3 4 4 8 5 4}
|
||||
|
||||
@@ -138,6 +141,11 @@ do_test insert2-3.2 {
|
||||
INSERT INTO t4 VALUES(9,18);
|
||||
INSERT INTO t4 VALUES(10,20);
|
||||
COMMIT;
|
||||
}
|
||||
db changes
|
||||
} {9}
|
||||
do_test insert2-3.2.1 {
|
||||
execsql {
|
||||
SELECT count(*) FROM t4;
|
||||
}
|
||||
} {10}
|
||||
@@ -182,5 +190,8 @@ do_test insert2-3.7 {
|
||||
ROLLBACK;
|
||||
}
|
||||
} {1}
|
||||
do_test insert2-3.8 {
|
||||
db changes
|
||||
} {159}
|
||||
|
||||
finish_test
|
||||
|
||||
+122
-1
@@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the SELECT statement.
|
||||
#
|
||||
# $Id: select1.test,v 1.22 2002/03/02 17:04:09 drh Exp $
|
||||
# $Id: select1.test,v 1.24 2002/04/06 13:57:43 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -544,5 +544,126 @@ do_test select1-10.6 {
|
||||
}
|
||||
} {11 22}
|
||||
|
||||
# Check the ability to specify "TABLE.*" in the result set of a SELECT
|
||||
#
|
||||
do_test select1-11.1 {
|
||||
execsql {
|
||||
DELETE FROM t3;
|
||||
DELETE FROM t4;
|
||||
INSERT INTO t3 VALUES(1,2);
|
||||
INSERT INTO t4 VALUES(3,4);
|
||||
SELECT * FROM t3, t4;
|
||||
}
|
||||
} {1 2 3 4}
|
||||
do_test select1-11.2 {
|
||||
execsql2 {
|
||||
SELECT * FROM t3, t4;
|
||||
}
|
||||
} {t3.a 1 t3.b 2 t4.a 3 t4.b 4}
|
||||
do_test select1-11.3 {
|
||||
execsql2 {
|
||||
SELECT * FROM t3 AS x, t4 AS y;
|
||||
}
|
||||
} {x.a 1 x.b 2 y.a 3 y.b 4}
|
||||
do_test select1-11.4 {
|
||||
execsql {
|
||||
SELECT t3.*, t4.b FROM t3, t4;
|
||||
}
|
||||
} {1 2 4}
|
||||
do_test select1-11.5 {
|
||||
execsql2 {
|
||||
SELECT t3.*, t4.b FROM t3, t4;
|
||||
}
|
||||
} {t3.a 1 t3.b 2 t4.b 4}
|
||||
do_test select1-11.6 {
|
||||
execsql2 {
|
||||
SELECT x.*, y.b FROM t3 AS x, t4 AS y;
|
||||
}
|
||||
} {x.a 1 x.b 2 y.b 4}
|
||||
do_test select1-11.7 {
|
||||
execsql {
|
||||
SELECT t3.b, t4.* FROM t3, t4;
|
||||
}
|
||||
} {2 3 4}
|
||||
do_test select1-11.8 {
|
||||
execsql2 {
|
||||
SELECT t3.b, t4.* FROM t3, t4;
|
||||
}
|
||||
} {t3.b 2 t4.a 3 t4.b 4}
|
||||
do_test select1-11.9 {
|
||||
execsql2 {
|
||||
SELECT x.b, y.* FROM t3 AS x, t4 AS y;
|
||||
}
|
||||
} {x.b 2 y.a 3 y.b 4}
|
||||
do_test select1-11.10 {
|
||||
catchsql {
|
||||
SELECT t5.* FROM t3, t4;
|
||||
}
|
||||
} {1 {no such table: t5}}
|
||||
do_test select1-11.11 {
|
||||
catchsql {
|
||||
SELECT t3.* FROM t3 AS x, t4;
|
||||
}
|
||||
} {1 {no such table: t3}}
|
||||
do_test select1-11.12 {
|
||||
execsql2 {
|
||||
SELECT t3.* FROM t3, (SELECT max(a), max(b) FROM t4)
|
||||
}
|
||||
} {t3.a 1 t3.b 2}
|
||||
do_test select1-11.13 {
|
||||
execsql2 {
|
||||
SELECT t3.* FROM (SELECT max(a), max(b) FROM t4), t3
|
||||
}
|
||||
} {t3.a 1 t3.b 2}
|
||||
do_test select1-11.14 {
|
||||
execsql2 {
|
||||
SELECT * FROM t3, (SELECT max(a), max(b) FROM t4)
|
||||
}
|
||||
} {t3.a 1 t3.b 2 max(a) 3 max(b) 4}
|
||||
do_test select1-11.15 {
|
||||
execsql2 {
|
||||
SELECT y.*, t3.* FROM t3, (SELECT max(a), max(b) FROM t4) AS y
|
||||
}
|
||||
} {y.max(a) 3 y.max(b) 4 t3.a 1 t3.b 2}
|
||||
|
||||
# Tests of SELECT statements without a FROM clause.
|
||||
#
|
||||
do_test select1-12.1 {
|
||||
execsql2 {
|
||||
SELECT 1+2+3
|
||||
}
|
||||
} {1+2+3 6}
|
||||
do_test select1-12.2 {
|
||||
execsql2 {
|
||||
SELECT 1,'hello',2
|
||||
}
|
||||
} {1 1 'hello' hello 2 2}
|
||||
do_test select1-12.3 {
|
||||
execsql2 {
|
||||
SELECT 1 AS 'a','hello' AS 'b',2 AS 'c'
|
||||
}
|
||||
} {a 1 b hello c 2}
|
||||
do_test select1-12.4 {
|
||||
execsql {
|
||||
DELETE FROM t3;
|
||||
INSERT INTO t3 VALUES(1,2);
|
||||
SELECT * FROM t3 UNION SELECT 3 AS 'a', 4 ORDER BY a;
|
||||
}
|
||||
} {1 2 3 4}
|
||||
do_test select1-12.5 {
|
||||
execsql {
|
||||
SELECT 3, 4 UNION SELECT * FROM t3;
|
||||
}
|
||||
} {1 2 3 4}
|
||||
do_test select1-12.6 {
|
||||
execsql {
|
||||
SELECT * FROM t3 WHERE a=(SELECT 1);
|
||||
}
|
||||
} {1 2}
|
||||
do_test select1-12.7 {
|
||||
execsql {
|
||||
SELECT * FROM t3 WHERE a=(SELECT 2);
|
||||
}
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@
|
||||
# interface is pretty well tested. This file contains some addition
|
||||
# tests for fringe issues that the main test suite does not cover.
|
||||
#
|
||||
# $Id: tclsqlite.test,v 1.5 2002/01/16 21:00:28 drh Exp $
|
||||
# $Id: tclsqlite.test,v 1.6 2002/04/12 10:09:00 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@@ -29,7 +29,7 @@ do_test tcl-1.1 {
|
||||
do_test tcl-1.2 {
|
||||
set v [catch {db bogus} msg]
|
||||
lappend v $msg
|
||||
} {1 {bad option "bogus": must be busy, close, complete, eval, last_insert_rowid, or timeout}}
|
||||
} {1 {bad option "bogus": must be busy, changes, close, complete, eval, last_insert_rowid, or timeout}}
|
||||
do_test tcl-1.3 {
|
||||
execsql {CREATE TABLE t1(a int, b int)}
|
||||
execsql {INSERT INTO t1 VALUES(10,20)}
|
||||
|
||||
+8
-8
@@ -32,10 +32,10 @@ proc runtest {title} {
|
||||
puts "</blockquote><table border=0 cellpadding=0 cellspacing=0>"
|
||||
set format {<tr><td>%s</td><td align="right"> %.3f</td></tr>}
|
||||
set delay 1000
|
||||
exec sync; after $delay;
|
||||
set t [time "exec psql drh <$sqlfile" 1]
|
||||
set t [expr {[lindex $t 0]/1000000.0}]
|
||||
puts [format $format PostgreSQL: $t]
|
||||
# exec sync; after $delay;
|
||||
# set t [time "exec psql drh <$sqlfile" 1]
|
||||
# set t [expr {[lindex $t 0]/1000000.0}]
|
||||
# puts [format $format PostgreSQL: $t]
|
||||
exec sync; after $delay;
|
||||
set t [time "exec mysql -f drh <$sqlfile" 1]
|
||||
set t [expr {[lindex $t 0]/1000000.0}]
|
||||
@@ -47,11 +47,11 @@ proc runtest {title} {
|
||||
# set t [expr {[lindex $t 0]/1000000.0}]
|
||||
# puts [format $format {SQLite 2.4 (cache=100):} $t]
|
||||
exec sync; after $delay;
|
||||
set t [time "exec ./sqlite240 s2k.db <$sqlfile" 1]
|
||||
set t [time "exec ./sqlite248 s2k.db <$sqlfile" 1]
|
||||
set t [expr {[lindex $t 0]/1000000.0}]
|
||||
puts [format $format {SQLite 2.4:} $t]
|
||||
exec sync; after $delay;
|
||||
set t [time "exec ./sqlite240 sns.db <$sqlfile" 1]
|
||||
set t [time "exec ./sqlite248 sns.db <$sqlfile" 1]
|
||||
set t [expr {[lindex $t 0]/1000000.0}]
|
||||
puts [format $format {SQLite 2.4 (nosync):} $t]
|
||||
# set t [time "exec ./sqlite-t1 st1.db <$sqlfile" 1]
|
||||
@@ -78,14 +78,14 @@ puts $fd {
|
||||
PRAGMA default_synchronous=on;
|
||||
}
|
||||
close $fd
|
||||
exec ./sqlite240 s2k.db <2kinit.sql
|
||||
exec ./sqlite248 s2k.db <2kinit.sql
|
||||
set fd [open nosync-init.sql w]
|
||||
puts $fd {
|
||||
PRAGMA default_cache_size=2000;
|
||||
PRAGMA default_synchronous=off;
|
||||
}
|
||||
close $fd
|
||||
exec ./sqlite240 sns.db <nosync-init.sql
|
||||
exec ./sqlite248 sns.db <nosync-init.sql
|
||||
set ones {zero one two three four five six seven eight nine
|
||||
ten eleven twelve thirteen fourteen fifteen sixteen seventeen
|
||||
eighteen nineteen}
|
||||
|
||||
+19
-1
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Run this Tcl script to generate the sqlite.html file.
|
||||
#
|
||||
set rcsid {$Id: c_interface.tcl,v 1.25 2002/03/04 02:26:17 drh Exp $}
|
||||
set rcsid {$Id: c_interface.tcl,v 1.26 2002/04/12 10:09:00 drh Exp $}
|
||||
|
||||
puts {<html>
|
||||
<head>
|
||||
@@ -307,6 +307,8 @@ useful interfaces. These extended routines are as follows:
|
||||
<blockquote><pre>
|
||||
int sqlite_last_insert_rowid(sqlite*);
|
||||
|
||||
int sqlite_changes(sqlite*);
|
||||
|
||||
int sqlite_get_table(
|
||||
sqlite*,
|
||||
char *sql,
|
||||
@@ -389,6 +391,22 @@ the key is automatically generated. You can find the value of the key
|
||||
for the most recent INSERT statement using the
|
||||
<b>sqlite_last_insert_rowid()</b> API function.</p>
|
||||
|
||||
<h2>The number of rows that changed</h2>
|
||||
|
||||
<p>The <b>sqlite_changes()</b> API function returns the number of rows
|
||||
that were inserted, deleted, or modified during the most recent
|
||||
<b>sqlite_exec()</b> call. The number reported includes any changes
|
||||
that were later undo by a ROLLBACK or ABORT. But rows that are
|
||||
deleted because of a DROP TABLE are <em>not</em> counted.</p>
|
||||
|
||||
<p>SQLite implements the command "<b>DELETE FROM table</b>" (without
|
||||
a WHERE clause) by dropping the table then recreating it.
|
||||
This is much faster than deleting the elements of the table individually.
|
||||
But it also means that the value returned from <b>sqlite_changes()</b>
|
||||
will be zero regardless of the number of elements that were originally
|
||||
in the table. If an accurate count of the number of elements deleted
|
||||
is necessary, use "<b>DELETE FROM table WHERE 1</b>" instead.</p>
|
||||
|
||||
<h2>Querying without using a callback function</h2>
|
||||
|
||||
<p>The <b>sqlite_get_table()</b> function is a wrapper around
|
||||
|
||||
@@ -25,6 +25,34 @@ proc chng {date desc} {
|
||||
puts "<DD><P><UL>$desc</UL></P></DD>"
|
||||
}
|
||||
|
||||
chng {2002 Apr 21 (2.4.9)} {
|
||||
<li>Fix a bug that was causing the precompiled binary of SQLITE.EXE to
|
||||
report "out of memory" under Windows 98.</li>
|
||||
}
|
||||
|
||||
chng {2002 Apr 20 (2.4.8)} {
|
||||
<li>Make sure VIEWs are created after their corresponding TABLEs in the
|
||||
output of the <b>.dump</b> command in the shell.</li>
|
||||
<li>Speed improvements: Do not do synchronous updates on TEMP tables.</li>
|
||||
<li>Many improvements and enhancements to the shell.</li>
|
||||
<li>Make the GLOB and LIKE operators functions that can be overridden
|
||||
by a programmer. This allows, for example, the LIKE operator to
|
||||
be changed to be case sensitive.</li>
|
||||
}
|
||||
|
||||
chng {2002 Apr 06 (2.4.7)} {
|
||||
<li>Add the ability to put TABLE.* in the column list of a
|
||||
SELECT statement.</li>
|
||||
<li>Permit SELECT statements without a FROM clause.</li>
|
||||
<li>Added the <b>last_insert_rowid()</b> SQL function.</li>
|
||||
<li>Do not count rows where the IGNORE conflict resultion occurs in
|
||||
the row count.</li>
|
||||
<li>Make sure functions expressions in the VALUES clause of an INSERT
|
||||
are correct.</li>
|
||||
<li>Added the <b>sqlite_changes()</b> API function to return the number
|
||||
of row that changed in the most recent operation.</li>
|
||||
}
|
||||
|
||||
chng {2002 Apr 02 (2.4.6)} {
|
||||
<li>Bug fix: Correctly handle terms in the WHERE clause of a join that
|
||||
do not contain a comparison operator.</li>
|
||||
|
||||
+22
-10
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Run this TCL script to generate HTML for the index.html file.
|
||||
#
|
||||
set rcsid {$Id: index.tcl,v 1.57 2002/04/01 12:15:02 drh Exp $}
|
||||
set rcsid {$Id: index.tcl,v 1.59 2002/04/12 13:11:53 drh Exp $}
|
||||
|
||||
puts {<html>
|
||||
<head><title>SQLite: An SQL Database Engine In A C Library</title></head>
|
||||
@@ -29,13 +29,20 @@ big database server. SQLite <b>is</b> the server. The SQLite
|
||||
library reads and writes directly to and from the database files
|
||||
on disk.</p>}
|
||||
|
||||
puts {<table align="right"hspace="10">
|
||||
<tr><td align="center" bgcolor="#8ee5ee">
|
||||
<table border="2"><tr><td align="center">
|
||||
<a href="download.html"><big><b>Download<br>SQLite
|
||||
puts {
|
||||
<table align="right" hspace="10" cellpadding=0 cellspacing=0 broder=0>
|
||||
<tr><td align="right" bgcolor="#cacae4">
|
||||
<table border="2" width="100%" cellspacing=0 cellpadding=5><tr><td align="left">
|
||||
Quick Links:
|
||||
<ul>
|
||||
<li><a href="download.html">Download</a></li>
|
||||
<li><a href="http://cvs.hwaci.com:2080/sqlite/timeline">Change Log</a></li>
|
||||
<li><a href="http://cvs.hwaci.com:2080/sqlite/tktnew">Report a bug</a></li>
|
||||
</ul>
|
||||
</td></tr></table>
|
||||
</td></tr>
|
||||
</table>}
|
||||
</table>
|
||||
}
|
||||
|
||||
puts {<h2>Features</h2>
|
||||
|
||||
@@ -63,10 +70,11 @@ puts {<h2>Current Status</h2>
|
||||
|
||||
<p>A <a href="changes.html">Change Summary</a> is available on this
|
||||
website. You can also access a detailed
|
||||
<a href="http://cvs.hwaci.com:2080/sqlite/timeline">change history</a>
|
||||
and a list of
|
||||
<a href="http://cvs.hwaci.com:2080/sqlite/rptview?rn=2">open bugs</a>
|
||||
from the
|
||||
<a href="http://cvs.hwaci.com:2080/sqlite/timeline">change history</a>,
|
||||
<a href="http://cvs.hwaci.com:2080/sqlite/rptview?rn=2">view open bugs</a>,
|
||||
or
|
||||
<a href="http://cvs.hwaci.com:2080/sqlite/tktnew">report new bugs</a>
|
||||
at the
|
||||
<a href="http://cvs.hwaci.com:2080/sqlite/">CVS server</a>.</p>
|
||||
|
||||
<p>Complete source code and precompiled binaries for the latest release are
|
||||
@@ -174,6 +182,10 @@ puts {<h2>Related Sites</h2>
|
||||
<li><p>An ODBC driver for SQLite can be found at
|
||||
<a href="http://www.ch-werner.de/sqliteodbc/">
|
||||
http://www.ch-werner.de/sqliteodbc/</a>.</p></li>
|
||||
|
||||
<li><p>A PHP module for SQLite can be found at
|
||||
<a href="http://freshmeat.net/projects/sqlite-php">
|
||||
http://freshmeat.net/projects/sqlite-php</a></li>
|
||||
</ul>}
|
||||
|
||||
puts {
|
||||
|
||||
+13
-2
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Run this Tcl script to generate the sqlite.html file.
|
||||
#
|
||||
set rcsid {$Id: lang.tcl,v 1.29 2002/03/28 14:20:08 drh Exp $}
|
||||
set rcsid {$Id: lang.tcl,v 1.32 2002/04/12 10:09:00 drh Exp $}
|
||||
|
||||
puts {<html>
|
||||
<head>
|
||||
@@ -566,6 +566,13 @@ their result across all rows of the result set.</p>
|
||||
all arguments are NULL then NULL is returned.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign="top" align="right">last_insert_rowid()</td>
|
||||
<td valign="top">Return the ROWID of the last row insert from this
|
||||
connection to the database. This is the same value that would be returned
|
||||
from the <b>sqlite_last_insert_rowid()</b> API function.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign="top" align="right">length(<i>X</i>)</td>
|
||||
<td valign="top">Return the string length of <i>X</i> in characters.
|
||||
@@ -836,6 +843,8 @@ with caution.</p>
|
||||
<p>When on, the COUNT_CHANGES pragma causes the callback function to
|
||||
be invoked once for each DELETE, INSERT, or UPDATE operation. The
|
||||
argument is the number of rows that were changed.</p>
|
||||
<p>This pragma may be removed from future versions of SQLite.
|
||||
Consider using the <b>sqlite_changes()</b> API function instead.</p></li>
|
||||
|
||||
<li><p><b>PRAGMA default_cache_size;
|
||||
<br>PRAGMA default_cache_size = </b><i>Number-of-pages</i><b>;</b></p>
|
||||
@@ -955,7 +964,7 @@ information.</p>
|
||||
Section SELECT select
|
||||
|
||||
Syntax {sql-statement} {
|
||||
SELECT <result> FROM <table-list>
|
||||
SELECT <result> [FROM <table-list>]
|
||||
[WHERE <expression>]
|
||||
[GROUP BY <expr-list>]
|
||||
[HAVING <expression>]
|
||||
@@ -993,6 +1002,8 @@ puts {for that one expression.</p>
|
||||
the FROM keyword. If more than one table is specified, then the
|
||||
query is against the (inner) join of the various tables. A sub-query
|
||||
in parentheses may be substituted for any table name in the FROM clause.
|
||||
The entire FROM clause may be omitted, in which case the result is a
|
||||
single row consisting of the values of the expression list.
|
||||
</p>
|
||||
|
||||
<p>The WHERE clause can be used to limit the number of rows over
|
||||
|
||||
+9
-2
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Run this Tcl script to generate the tclsqlite.html file.
|
||||
#
|
||||
set rcsid {$Id: tclsqlite.tcl,v 1.6 2002/01/16 21:00:28 drh Exp $}
|
||||
set rcsid {$Id: tclsqlite.tcl,v 1.7 2002/04/12 10:09:00 drh Exp $}
|
||||
|
||||
puts {<html>
|
||||
<head>
|
||||
@@ -50,12 +50,13 @@ the database is stored.
|
||||
|
||||
<p>
|
||||
Once an SQLite database is open, it can be controlled using
|
||||
methods of the <i>dbcmd</i>. There are currently 6 methods
|
||||
methods of the <i>dbcmd</i>. There are currently 7 methods
|
||||
defined:</p>
|
||||
|
||||
<p>
|
||||
<ul>
|
||||
<li> busy
|
||||
<li> changes
|
||||
<li> close
|
||||
<li> complete
|
||||
<li> eval
|
||||
@@ -248,6 +249,12 @@ should return "1" if it wants SQLite to abandon the current operation.
|
||||
<p>The "last_insert_rowid" method returns an integer which is the ROWID
|
||||
of the most recently inserted database row.</p>
|
||||
|
||||
<h2>The "changes" method</h2>
|
||||
|
||||
<p>The "changes" method returns an integer which is the number of rows
|
||||
in the database that were inserted, deleted, and/or modified by the most
|
||||
recent "eval" method.</p>
|
||||
|
||||
}
|
||||
|
||||
puts {
|
||||
|
||||
Reference in New Issue
Block a user