Changes to reduce the heap space consumed by triggers, views and tables in the in-memory representation of the schema. Also to reduce the space used by prepared statements slightly. (CVS 6305)
FossilOrigin-Name: d9f6ffbc5ea090ba0daac571fc9a6c68b9c864e4
This commit is contained in:
parent
076d4661a6
commit
6ab3a2ec8a
62
manifest
62
manifest
@ -1,5 +1,5 @@
|
|||||||
C Make\ssure\sthe\sauto_vacuum=INCREMENTAL\ssetting\sis\spreserved\sacross\sa\sVACUUM.\nTicket\s#3663.\s(CVS\s6304)
|
C Changes\sto\sreduce\sthe\sheap\sspace\sconsumed\sby\striggers,\sviews\sand\stables\sin\sthe\sin-memory\srepresentation\sof\sthe\sschema.\sAlso\sto\sreduce\sthe\sspace\sused\sby\sprepared\sstatements\sslightly.\s(CVS\s6305)
|
||||||
D 2009-02-18T20:31:18
|
D 2009-02-19T14:39:25
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in 1d83fa2b1fd326b9e121012bd1ff9740537e12b3
|
F Makefile.in 1d83fa2b1fd326b9e121012bd1ff9740537e12b3
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@ -98,8 +98,8 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
|||||||
F sqlite3.def a1be7b9a4b8b51ac41c6ff6e8e44a14ef66b338b
|
F sqlite3.def a1be7b9a4b8b51ac41c6ff6e8e44a14ef66b338b
|
||||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||||
F src/alter.c f93d13aae63ea1a5ee604d76041be354311d08a5
|
F src/alter.c f93d13aae63ea1a5ee604d76041be354311d08a5
|
||||||
F src/analyze.c fc6056826fe67aa0856d4e01591be8f9266ac415
|
F src/analyze.c 2ca143d83ce545992cab74efeb5e8a446c61ab4b
|
||||||
F src/attach.c 81d37d1948f409146a7b22b96998fd90649d1fd3
|
F src/attach.c d34589d5c85d81e755e4a8fc946d313915a6fa6d
|
||||||
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
||||||
F src/backup.c 2d3f31148d7b086c5c72d9edcd04fc2751b0aa6e
|
F src/backup.c 2d3f31148d7b086c5c72d9edcd04fc2751b0aa6e
|
||||||
F src/bitvec.c 44f7059ac1f874d364b34af31b9617e52223ba75
|
F src/bitvec.c 44f7059ac1f874d364b34af31b9617e52223ba75
|
||||||
@ -107,19 +107,19 @@ F src/btmutex.c 63c5cc4ad5715690767ffcb741e185d7bc35ec1a
|
|||||||
F src/btree.c 086fdb4505aa00275d6873829aeb51bf57da8d16
|
F src/btree.c 086fdb4505aa00275d6873829aeb51bf57da8d16
|
||||||
F src/btree.h 4eab72af6adf95f0b08b61a72ef9781bdb0bf63f
|
F src/btree.h 4eab72af6adf95f0b08b61a72ef9781bdb0bf63f
|
||||||
F src/btreeInt.h 0a4884e6152d7cae9c741e91b830064c19fd2c05
|
F src/btreeInt.h 0a4884e6152d7cae9c741e91b830064c19fd2c05
|
||||||
F src/build.c a394b2511c5c768f14a9d7c1c31606b9fa569f1b
|
F src/build.c 0860029ca6e29b2bfcadbbe90084e02af98d768f
|
||||||
F src/callback.c 5f10bca853e59a2c272bbfd5b720303f8b69e520
|
F src/callback.c 5f10bca853e59a2c272bbfd5b720303f8b69e520
|
||||||
F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
|
F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
|
||||||
F src/date.c 0d804df3bbda46329946a01ff5c75c3f4f135218
|
F src/date.c 0d804df3bbda46329946a01ff5c75c3f4f135218
|
||||||
F src/delete.c 6249005bdd8f85db6ec5f31ddb5c07de023693cc
|
F src/delete.c 8d2fb05b32b5dea65277a574fedb0ebaa5dd877c
|
||||||
F src/expr.c e60f69f624a03a8f493900b071b3affbfa699585
|
F src/expr.c 2e62c2621c0375125cacb93ad6686bb2911b629e
|
||||||
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
||||||
F src/func.c 35d6f4a98c5fd5d504fd92a9197bae3220bbac39
|
F src/func.c 2fb36cd7cc24e16845db203187d1e52811b0fa9c
|
||||||
F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
|
F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
|
||||||
F src/hash.c 5824e6ff7ba78cd34c8d6cd724367713583e5b55
|
F src/hash.c 5824e6ff7ba78cd34c8d6cd724367713583e5b55
|
||||||
F src/hash.h 28f38ebb1006a5beedcb013bcdfe31befe7437ae
|
F src/hash.h 28f38ebb1006a5beedcb013bcdfe31befe7437ae
|
||||||
F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb
|
F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb
|
||||||
F src/insert.c f6db1e6f43aae337e64a755208abb6ff124edc19
|
F src/insert.c 6bd2464ec48ddcb1d9c6fbfd294de91b5dd47075
|
||||||
F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
|
F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
|
||||||
F src/legacy.c 8b3b95d48d202614946d7ce7256e7ba898905c3b
|
F src/legacy.c 8b3b95d48d202614946d7ce7256e7ba898905c3b
|
||||||
F src/loadext.c 3f96631089fc4f3871a67f02f2e4fc7ea4d51edc
|
F src/loadext.c 3f96631089fc4f3871a67f02f2e4fc7ea4d51edc
|
||||||
@ -127,7 +127,7 @@ F src/main.c 4912460dab29e4d37e4ba1d78320c6a77bb95ad8
|
|||||||
F src/malloc.c 552d993ee414ead65cafcaa636e22c84085999cb
|
F src/malloc.c 552d993ee414ead65cafcaa636e22c84085999cb
|
||||||
F src/mem0.c f2f84062d1f35814d6535c9f9e33de3bfb3b132c
|
F src/mem0.c f2f84062d1f35814d6535c9f9e33de3bfb3b132c
|
||||||
F src/mem1.c 3bfb39e4f60b0179713a7c087b2d4f0dc205735f
|
F src/mem1.c 3bfb39e4f60b0179713a7c087b2d4f0dc205735f
|
||||||
F src/mem2.c 6f46eef2c2cce452ae38f5b98c2632712e858bc9
|
F src/mem2.c 692c5b50141f49c32d85d7c0c39c751f6d520093
|
||||||
F src/mem3.c 67153ec933e08b70714055e872efb58a6b287939
|
F src/mem3.c 67153ec933e08b70714055e872efb58a6b287939
|
||||||
F src/mem5.c 838309b521c96a2a34507f74a5a739d28de4aac6
|
F src/mem5.c 838309b521c96a2a34507f74a5a739d28de4aac6
|
||||||
F src/memjournal.c 17e9281ea5d7981e3e7b0dd3274921ecba4f773c
|
F src/memjournal.c 17e9281ea5d7981e3e7b0dd3274921ecba4f773c
|
||||||
@ -145,21 +145,21 @@ F src/os_unix.c 4e916cafbf5ec0166213ac62d680ebbe12b8c5a7
|
|||||||
F src/os_win.c 45cb430884da7e9360a55a0fcd5c2c44c22dd79d
|
F src/os_win.c 45cb430884da7e9360a55a0fcd5c2c44c22dd79d
|
||||||
F src/pager.c d62fd62f7c0ad257019c21158b597fdbb0182529
|
F src/pager.c d62fd62f7c0ad257019c21158b597fdbb0182529
|
||||||
F src/pager.h 0c9f3520c00d8a3b8e792ca56c9a11b6b02b4b0f
|
F src/pager.h 0c9f3520c00d8a3b8e792ca56c9a11b6b02b4b0f
|
||||||
F src/parse.y 4f4d16aee0d11f69fec2adb77dac88878043ed8d
|
F src/parse.y 5202dc712407fd6723f6639b88b86ddf8b33aef5
|
||||||
F src/pcache.c fcf7738c83c4d3e9d45836b2334c8a368cc41274
|
F src/pcache.c fcf7738c83c4d3e9d45836b2334c8a368cc41274
|
||||||
F src/pcache.h 9b927ccc5a538e31b4c3bc7eec4f976db42a1324
|
F src/pcache.h 9b927ccc5a538e31b4c3bc7eec4f976db42a1324
|
||||||
F src/pcache1.c dabb8ab14827e090321f17150ce96fda172974e8
|
F src/pcache1.c dabb8ab14827e090321f17150ce96fda172974e8
|
||||||
F src/pragma.c 04c13c79fd559d769f5bcb3aa661b32d484b1e7b
|
F src/pragma.c 9ed2acb94efee8059efcc52c2e2140b43170831e
|
||||||
F src/prepare.c 9ec504ddd4a8e34e5fb502033312da6a78f5f76a
|
F src/prepare.c d0bbb4b1a8b9c1db6d13788929839bb63764680e
|
||||||
F src/printf.c 9866a9a9c4a90f6d4147407f373df3fd5d5f9b6f
|
F src/printf.c 9866a9a9c4a90f6d4147407f373df3fd5d5f9b6f
|
||||||
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
|
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
|
||||||
F src/resolve.c 18dc9f0df1d60048e012ce6632251063e0dd356a
|
F src/resolve.c b3aa625ec135d53a7e80c86c25ad56de46e0b415
|
||||||
F src/rowset.c ba9375f37053d422dd76965a9c370a13b6e1aac4
|
F src/rowset.c ba9375f37053d422dd76965a9c370a13b6e1aac4
|
||||||
F src/select.c 164934bd8a9fae29e4d21530688dbac53b420da6
|
F src/select.c fc21f384db6207a987141859ac770d83c669c933
|
||||||
F src/shell.c f109ebbb50132926ebbc173a6c2d8838d5d78527
|
F src/shell.c f109ebbb50132926ebbc173a6c2d8838d5d78527
|
||||||
F src/sqlite.h.in 14f4d065bafed8500ea558a75a8e2be89c784d61
|
F src/sqlite.h.in 14f4d065bafed8500ea558a75a8e2be89c784d61
|
||||||
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
||||||
F src/sqliteInt.h 55cc7e45a7fcc166be62b984168dd69159d877eb
|
F src/sqliteInt.h 8bd8f5bb583832df68034525c1d763a35cd0365f
|
||||||
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
|
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
|
||||||
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
||||||
F src/table.c 332ab0ea691e63862e2a8bdfe2c0617ee61062a3
|
F src/table.c 332ab0ea691e63862e2a8bdfe2c0617ee61062a3
|
||||||
@ -195,21 +195,21 @@ F src/test_tclvar.c 9e42fa59d3d2f064b7ab8628e7ab2dc8a9fe93d4
|
|||||||
F src/test_thread.c adb9175c466e1f487295b5b957603fc0a88ea293
|
F src/test_thread.c adb9175c466e1f487295b5b957603fc0a88ea293
|
||||||
F src/test_wsd.c c297d7d6b8a990239e1bd25935e81d612d8ae31d
|
F src/test_wsd.c c297d7d6b8a990239e1bd25935e81d612d8ae31d
|
||||||
F src/tokenize.c 6987fb7f0d6a87ac53499aee568cabb05eb4bea8
|
F src/tokenize.c 6987fb7f0d6a87ac53499aee568cabb05eb4bea8
|
||||||
F src/trigger.c ca6d78f7c1314053800386ca64361e487774fda3
|
F src/trigger.c 9957e16e5445478f2cc60e26ac1bc836bb18d21a
|
||||||
F src/update.c 8c4925f9ca664effc8a1faaad67449d2074567b1
|
F src/update.c 9edb83cc4322fb2dc5b7a0087cdb8fa00391f402
|
||||||
F src/utf.c 1da9c832dba0fa8f865b5b902d93f420a1ee4245
|
F src/utf.c 1da9c832dba0fa8f865b5b902d93f420a1ee4245
|
||||||
F src/util.c 1363f64351f3b544790f3c523439354c02f8c4e9
|
F src/util.c 1363f64351f3b544790f3c523439354c02f8c4e9
|
||||||
F src/vacuum.c 4929a585ef0fb1dfaf46302f8a9c4aa30c2d9cf5
|
F src/vacuum.c 4929a585ef0fb1dfaf46302f8a9c4aa30c2d9cf5
|
||||||
F src/vdbe.c 02e70c48ffd11aa470060fa03a2bfa65d72bc8df
|
F src/vdbe.c d7b996a5b75753ade4471fbe0452a684dc047d72
|
||||||
F src/vdbe.h 03516f28bf5aca00a53c4dccd6c313f96adb94f6
|
F src/vdbe.h d70a68bee196ab228914a3902c79dbd24342a0f2
|
||||||
F src/vdbeInt.h 13cb4868ea579b5a8f6b6b5098caa99cd5a14078
|
F src/vdbeInt.h 9dd984cf80ef4f2970266b05f1dbb5622ac3817b
|
||||||
F src/vdbeapi.c b23c4b1686f150a0ddc36459c8e3876be62638e1
|
F src/vdbeapi.c f94fe2eb6f48687e918f0df7eed1409cff9dcf58
|
||||||
F src/vdbeaux.c 75c3ac2a3c37747ae66ea0935f8f48bb1879234a
|
F src/vdbeaux.c f636fd01adbab85675167a25cf194eddd58b13dd
|
||||||
F src/vdbeblob.c b0dcebfafedcf9c0addc7901ad98f6f986c08935
|
F src/vdbeblob.c b0dcebfafedcf9c0addc7901ad98f6f986c08935
|
||||||
F src/vdbemem.c 543a79d722734d2f8b7ad70f08218c30bcc5bbf5
|
F src/vdbemem.c 543a79d722734d2f8b7ad70f08218c30bcc5bbf5
|
||||||
F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43
|
F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43
|
||||||
F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d
|
F src/walker.c 42bd3f00ca2ef5ae842304ec0d59903ef051412d
|
||||||
F src/where.c 63bb752784b352d8e226dc6b1ec02f0d19fed916
|
F src/where.c 2284de47b03e285a142926bc8a8022983c455a76
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
|
F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
|
||||||
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
|
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
|
||||||
@ -299,7 +299,7 @@ F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
|
|||||||
F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272
|
F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272
|
||||||
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
|
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
|
||||||
F test/date.test bb2cc648333c04d09e8e23cfc0cddc398c334a92
|
F test/date.test bb2cc648333c04d09e8e23cfc0cddc398c334a92
|
||||||
F test/default.test 252298e42a680146b1dd64f563b95bdf088d94fb
|
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
|
||||||
F test/delete.test f171c1011395a8dd63169438fe1d8cc625eb7442
|
F test/delete.test f171c1011395a8dd63169438fe1d8cc625eb7442
|
||||||
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
|
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
|
||||||
F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab
|
F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab
|
||||||
@ -552,7 +552,7 @@ F test/tableapi.test 505031f15b18a750184d967d2c896cf88fcc969c
|
|||||||
F test/tclsqlite.test 413a8a887d89ea8fa7055e8d118ffb03b0a4c91a
|
F test/tclsqlite.test 413a8a887d89ea8fa7055e8d118ffb03b0a4c91a
|
||||||
F test/tempdb.test b88ac8a19823cf771d742bf61eef93ef337c06b1
|
F test/tempdb.test b88ac8a19823cf771d742bf61eef93ef337c06b1
|
||||||
F test/temptable.test 5d8ca46be28cc06c887c5a77df650843b7edbae1
|
F test/temptable.test 5d8ca46be28cc06c887c5a77df650843b7edbae1
|
||||||
F test/tester.tcl b28d5eb97e95b19eacdb5afb38db2c8558f398b0
|
F test/tester.tcl 66546f6766029384360b24cacb3896376c5f5f69
|
||||||
F test/thread001.test 06c45ed9597d478e7bbdc2a8937e1ebea2a20a32
|
F test/thread001.test 06c45ed9597d478e7bbdc2a8937e1ebea2a20a32
|
||||||
F test/thread002.test 3c03900f03fd2fe8e2fbb1bbdef7fa8206fdb7ad
|
F test/thread002.test 3c03900f03fd2fe8e2fbb1bbdef7fa8206fdb7ad
|
||||||
F test/thread003.test 6d360c15afe7f6ef6186801d2cb8407bccbe3aa3
|
F test/thread003.test 6d360c15afe7f6ef6186801d2cb8407bccbe3aa3
|
||||||
@ -701,7 +701,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
|||||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
P 419eb48b6b4238526850091eef28af503b6c4579
|
P ded04f12f41504e4a3ecd5164f0d4cbbde5e16f7
|
||||||
R 379eb6edfb0135905a7c816f1113ae71
|
R beea4442dc6507223c6db2a960f9f40a
|
||||||
U drh
|
U danielk1977
|
||||||
Z bfca2c680cc89c0b0c6a5ad192f03b32
|
Z 5a9e5027f061557095d1ee54ae664ed7
|
||||||
|
@ -1 +1 @@
|
|||||||
ded04f12f41504e4a3ecd5164f0d4cbbde5e16f7
|
d9f6ffbc5ea090ba0daac571fc9a6c68b9c864e4
|
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains code associated with the ANALYZE command.
|
** This file contains code associated with the ANALYZE command.
|
||||||
**
|
**
|
||||||
** @(#) $Id: analyze.c,v 1.48 2009/02/13 16:59:53 drh Exp $
|
** @(#) $Id: analyze.c,v 1.49 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef SQLITE_OMIT_ANALYZE
|
#ifndef SQLITE_OMIT_ANALYZE
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
@ -117,7 +117,7 @@ static void analyzeOneTable(
|
|||||||
/* Establish a read-lock on the table at the shared-cache level. */
|
/* Establish a read-lock on the table at the shared-cache level. */
|
||||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||||
|
|
||||||
iIdxCur = pParse->nTab;
|
iIdxCur = pParse->nTab++;
|
||||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||||
int regFields; /* Register block for building records */
|
int regFields; /* Register block for building records */
|
||||||
|
12
src/attach.c
12
src/attach.c
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains code used to implement the ATTACH and DETACH commands.
|
** This file contains code used to implement the ATTACH and DETACH commands.
|
||||||
**
|
**
|
||||||
** $Id: attach.c,v 1.82 2009/02/03 16:51:25 danielk1977 Exp $
|
** $Id: attach.c,v 1.83 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -488,11 +488,11 @@ int sqlite3FixExpr(
|
|||||||
Expr *pExpr /* The expression to be fixed to one database */
|
Expr *pExpr /* The expression to be fixed to one database */
|
||||||
){
|
){
|
||||||
while( pExpr ){
|
while( pExpr ){
|
||||||
if( sqlite3FixSelect(pFix, pExpr->pSelect) ){
|
if( ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanOnly) ) break;
|
||||||
return 1;
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||||
}
|
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
|
||||||
if( sqlite3FixExprList(pFix, pExpr->pList) ){
|
}else{
|
||||||
return 1;
|
if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
|
||||||
}
|
}
|
||||||
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
|
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
|
||||||
return 1;
|
return 1;
|
||||||
|
44
src/build.c
44
src/build.c
@ -22,7 +22,7 @@
|
|||||||
** COMMIT
|
** COMMIT
|
||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.518 2009/02/13 03:43:32 drh Exp $
|
** $Id: build.c,v 1.519 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -178,19 +178,6 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||||||
codeTableLocks(pParse);
|
codeTableLocks(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->cookieGoto);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->cookieGoto);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_TRACE
|
|
||||||
if( !db->init.busy ){
|
|
||||||
/* Change the P4 argument of the first opcode (which will always be
|
|
||||||
** an OP_Trace) to be the complete text of the current SQL statement.
|
|
||||||
*/
|
|
||||||
VdbeOp *pOp = sqlite3VdbeGetOp(v, 0);
|
|
||||||
if( pOp && pOp->opcode==OP_Trace ){
|
|
||||||
sqlite3VdbeChangeP4(v, 0, pParse->zSql,
|
|
||||||
(int)(pParse->zTail - pParse->zSql));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* SQLITE_OMIT_TRACE */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -202,8 +189,8 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||||||
sqlite3VdbeTrace(v, trace);
|
sqlite3VdbeTrace(v, trace);
|
||||||
#endif
|
#endif
|
||||||
assert( pParse->disableColCache==0 ); /* Disables and re-enables match */
|
assert( pParse->disableColCache==0 ); /* Disables and re-enables match */
|
||||||
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
|
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
|
||||||
pParse->nTab+3, pParse->explain);
|
pParse->nTab, pParse->explain);
|
||||||
pParse->rc = SQLITE_DONE;
|
pParse->rc = SQLITE_DONE;
|
||||||
pParse->colNamesSet = 0;
|
pParse->colNamesSet = 0;
|
||||||
}else if( pParse->rc==SQLITE_OK ){
|
}else if( pParse->rc==SQLITE_OK ){
|
||||||
@ -618,6 +605,9 @@ void sqlite3OpenMasterTable(Parse *p, int iDb){
|
|||||||
sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
|
sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
|
||||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 5);/* sqlite_master has 5 columns */
|
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 5);/* sqlite_master has 5 columns */
|
||||||
sqlite3VdbeAddOp3(v, OP_OpenWrite, 0, MASTER_ROOT, iDb);
|
sqlite3VdbeAddOp3(v, OP_OpenWrite, 0, MASTER_ROOT, iDb);
|
||||||
|
if( p->nTab==0 ){
|
||||||
|
p->nTab = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1116,12 +1106,12 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
|
|||||||
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
|
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
|
||||||
pCol->zName);
|
pCol->zName);
|
||||||
}else{
|
}else{
|
||||||
Expr *pCopy;
|
/* A copy of pExpr is used instead of the original, as pExpr contains
|
||||||
|
** tokens that point to volatile memory. The 'span' of the expression
|
||||||
|
** is required by pragma table_info.
|
||||||
|
*/
|
||||||
sqlite3ExprDelete(db, pCol->pDflt);
|
sqlite3ExprDelete(db, pCol->pDflt);
|
||||||
pCol->pDflt = pCopy = sqlite3ExprDup(db, pExpr);
|
pCol->pDflt = sqlite3ExprDup(db, pExpr, EXPRDUP_REDUCE|EXPRDUP_SPAN);
|
||||||
if( pCopy ){
|
|
||||||
sqlite3TokenCopy(db, &pCopy->span, &pExpr->span);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqlite3ExprDelete(db, pExpr);
|
sqlite3ExprDelete(db, pExpr);
|
||||||
@ -1217,7 +1207,7 @@ void sqlite3AddCheckConstraint(
|
|||||||
** to malloced space and not the (ephemeral) text of the CREATE TABLE
|
** to malloced space and not the (ephemeral) text of the CREATE TABLE
|
||||||
** statement */
|
** statement */
|
||||||
pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck,
|
pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck,
|
||||||
sqlite3ExprDup(db, pCheckExpr));
|
sqlite3ExprDup(db, pCheckExpr, 0));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sqlite3ExprDelete(db, pCheckExpr);
|
sqlite3ExprDelete(db, pCheckExpr);
|
||||||
@ -1540,7 +1530,7 @@ void sqlite3EndTable(
|
|||||||
SelectDest dest;
|
SelectDest dest;
|
||||||
Table *pSelTab;
|
Table *pSelTab;
|
||||||
|
|
||||||
assert(pParse->nTab==0);
|
assert(pParse->nTab==1);
|
||||||
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
|
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
|
||||||
sqlite3VdbeChangeP5(v, 1);
|
sqlite3VdbeChangeP5(v, 1);
|
||||||
pParse->nTab = 2;
|
pParse->nTab = 2;
|
||||||
@ -1701,7 +1691,7 @@ void sqlite3CreateView(
|
|||||||
** allocated rather than point to the input string - which means that
|
** allocated rather than point to the input string - which means that
|
||||||
** they will persist after the current sqlite3_exec() call returns.
|
** they will persist after the current sqlite3_exec() call returns.
|
||||||
*/
|
*/
|
||||||
p->pSelect = sqlite3SelectDup(db, pSelect);
|
p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
||||||
sqlite3SelectDelete(db, pSelect);
|
sqlite3SelectDelete(db, pSelect);
|
||||||
if( db->mallocFailed ){
|
if( db->mallocFailed ){
|
||||||
return;
|
return;
|
||||||
@ -1783,7 +1773,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|||||||
** statement that defines the view.
|
** statement that defines the view.
|
||||||
*/
|
*/
|
||||||
assert( pTable->pSelect );
|
assert( pTable->pSelect );
|
||||||
pSel = sqlite3SelectDup(db, pTable->pSelect);
|
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
|
||||||
if( pSel ){
|
if( pSel ){
|
||||||
n = pParse->nTab;
|
n = pParse->nTab;
|
||||||
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
|
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
|
||||||
@ -2277,8 +2267,8 @@ void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){
|
|||||||
*/
|
*/
|
||||||
static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||||
Table *pTab = pIndex->pTable; /* The table that is indexed */
|
Table *pTab = pIndex->pTable; /* The table that is indexed */
|
||||||
int iTab = pParse->nTab; /* Btree cursor used for pTab */
|
int iTab = pParse->nTab++; /* Btree cursor used for pTab */
|
||||||
int iIdx = pParse->nTab+1; /* Btree cursor used for pIndex */
|
int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
|
||||||
int addr1; /* Address of top of loop */
|
int addr1; /* Address of top of loop */
|
||||||
int tnum; /* Root page of index */
|
int tnum; /* Root page of index */
|
||||||
Vdbe *v; /* Generate code into this virtual machine */
|
Vdbe *v; /* Generate code into this virtual machine */
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** in order to generate code for DELETE FROM statements.
|
** in order to generate code for DELETE FROM statements.
|
||||||
**
|
**
|
||||||
** $Id: delete.c,v 1.191 2008/12/23 23:56:22 drh Exp $
|
** $Id: delete.c,v 1.192 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -99,12 +99,12 @@ void sqlite3MaterializeView(
|
|||||||
Select *pDup;
|
Select *pDup;
|
||||||
sqlite3 *db = pParse->db;
|
sqlite3 *db = pParse->db;
|
||||||
|
|
||||||
pDup = sqlite3SelectDup(db, pView->pSelect);
|
pDup = sqlite3SelectDup(db, pView->pSelect, 0);
|
||||||
if( pWhere ){
|
if( pWhere ){
|
||||||
SrcList *pFrom;
|
SrcList *pFrom;
|
||||||
Token viewName;
|
Token viewName;
|
||||||
|
|
||||||
pWhere = sqlite3ExprDup(db, pWhere);
|
pWhere = sqlite3ExprDup(db, pWhere, 0);
|
||||||
viewName.z = (u8*)pView->zName;
|
viewName.z = (u8*)pView->zName;
|
||||||
viewName.n = (unsigned int)sqlite3Strlen30((const char*)viewName.z);
|
viewName.n = (unsigned int)sqlite3Strlen30((const char*)viewName.z);
|
||||||
pFrom = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &viewName, pDup, 0,0);
|
pFrom = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &viewName, pDup, 0,0);
|
||||||
@ -174,7 +174,7 @@ Expr *sqlite3LimitWhere(
|
|||||||
|
|
||||||
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
|
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
|
||||||
** and the SELECT subtree. */
|
** and the SELECT subtree. */
|
||||||
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc);
|
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
|
||||||
if( pSelectSrc == 0 ) {
|
if( pSelectSrc == 0 ) {
|
||||||
sqlite3ExprListDelete(pParse->db, pEList);
|
sqlite3ExprListDelete(pParse->db, pEList);
|
||||||
goto limit_where_cleanup_2;
|
goto limit_where_cleanup_2;
|
||||||
|
381
src/expr.c
381
src/expr.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains routines used for analyzing expressions and
|
** This file contains routines used for analyzing expressions and
|
||||||
** for generating VDBE code that evaluates expressions in SQLite.
|
** for generating VDBE code that evaluates expressions in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: expr.c,v 1.411 2009/02/04 03:59:25 shane Exp $
|
** $Id: expr.c,v 1.412 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -35,7 +35,8 @@
|
|||||||
char sqlite3ExprAffinity(Expr *pExpr){
|
char sqlite3ExprAffinity(Expr *pExpr){
|
||||||
int op = pExpr->op;
|
int op = pExpr->op;
|
||||||
if( op==TK_SELECT ){
|
if( op==TK_SELECT ){
|
||||||
return sqlite3ExprAffinity(pExpr->pSelect->pEList->a[0].pExpr);
|
assert( pExpr->flags&EP_xIsSelect );
|
||||||
|
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
||||||
}
|
}
|
||||||
#ifndef SQLITE_OMIT_CAST
|
#ifndef SQLITE_OMIT_CAST
|
||||||
if( op==TK_CAST ){
|
if( op==TK_CAST ){
|
||||||
@ -155,11 +156,9 @@ static char comparisonAffinity(Expr *pExpr){
|
|||||||
aff = sqlite3ExprAffinity(pExpr->pLeft);
|
aff = sqlite3ExprAffinity(pExpr->pLeft);
|
||||||
if( pExpr->pRight ){
|
if( pExpr->pRight ){
|
||||||
aff = sqlite3CompareAffinity(pExpr->pRight, aff);
|
aff = sqlite3CompareAffinity(pExpr->pRight, aff);
|
||||||
}
|
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||||
else if( pExpr->pSelect ){
|
aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff);
|
||||||
aff = sqlite3CompareAffinity(pExpr->pSelect->pEList->a[0].pExpr, aff);
|
}else if( !aff ){
|
||||||
}
|
|
||||||
else if( !aff ){
|
|
||||||
aff = SQLITE_AFF_NONE;
|
aff = SQLITE_AFF_NONE;
|
||||||
}
|
}
|
||||||
return aff;
|
return aff;
|
||||||
@ -345,8 +344,11 @@ static void exprSetHeight(Expr *p){
|
|||||||
int nHeight = 0;
|
int nHeight = 0;
|
||||||
heightOfExpr(p->pLeft, &nHeight);
|
heightOfExpr(p->pLeft, &nHeight);
|
||||||
heightOfExpr(p->pRight, &nHeight);
|
heightOfExpr(p->pRight, &nHeight);
|
||||||
heightOfExprList(p->pList, &nHeight);
|
if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||||
heightOfSelect(p->pSelect, &nHeight);
|
heightOfSelect(p->x.pSelect, &nHeight);
|
||||||
|
}else{
|
||||||
|
heightOfExprList(p->x.pList, &nHeight);
|
||||||
|
}
|
||||||
p->nHeight = nHeight + 1;
|
p->nHeight = nHeight + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,7 +512,8 @@ Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pNew->op = TK_FUNCTION;
|
pNew->op = TK_FUNCTION;
|
||||||
pNew->pList = pList;
|
pNew->x.pList = pList;
|
||||||
|
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
|
||||||
assert( pToken->dyn==0 );
|
assert( pToken->dyn==0 );
|
||||||
pNew->token = *pToken;
|
pNew->token = *pToken;
|
||||||
pNew->span = pNew->token;
|
pNew->span = pNew->token;
|
||||||
@ -607,12 +610,22 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
|||||||
** Substructure is deleted.
|
** Substructure is deleted.
|
||||||
*/
|
*/
|
||||||
void sqlite3ExprClear(sqlite3 *db, Expr *p){
|
void sqlite3ExprClear(sqlite3 *db, Expr *p){
|
||||||
if( p->span.dyn ) sqlite3DbFree(db, (char*)p->span.z);
|
|
||||||
if( p->token.dyn ) sqlite3DbFree(db, (char*)p->token.z);
|
if( p->token.dyn ) sqlite3DbFree(db, (char*)p->token.z);
|
||||||
|
if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanOnly) ){
|
||||||
|
if( p->span.dyn ) sqlite3DbFree(db, (char*)p->span.z);
|
||||||
|
if( ExprHasProperty(p, EP_Reduced) ){
|
||||||
|
if( p->pLeft ) sqlite3ExprClear(db, p->pLeft);
|
||||||
|
if( p->pRight ) sqlite3ExprClear(db, p->pRight);
|
||||||
|
}else{
|
||||||
sqlite3ExprDelete(db, p->pLeft);
|
sqlite3ExprDelete(db, p->pLeft);
|
||||||
sqlite3ExprDelete(db, p->pRight);
|
sqlite3ExprDelete(db, p->pRight);
|
||||||
sqlite3ExprListDelete(db, p->pList);
|
}
|
||||||
sqlite3SelectDelete(db, p->pSelect);
|
if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||||
|
sqlite3SelectDelete(db, p->x.pSelect);
|
||||||
|
}else{
|
||||||
|
sqlite3ExprListDelete(db, p->x.pList);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -633,12 +646,190 @@ void sqlite3DequoteExpr(sqlite3 *db, Expr *p){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ExprSetProperty(p, EP_Dequoted);
|
ExprSetProperty(p, EP_Dequoted);
|
||||||
if( p->token.dyn==0 ){
|
if( p->token.dyn==0 && !ExprHasProperty(p, EP_Reduced) ){
|
||||||
sqlite3TokenCopy(db, &p->token, &p->token);
|
sqlite3TokenCopy(db, &p->token, &p->token);
|
||||||
}
|
}
|
||||||
sqlite3Dequote((char*)p->token.z);
|
sqlite3Dequote((char*)p->token.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return the number of bytes allocated for the expression structure
|
||||||
|
** passed as the first argument. This is always one of EXPR_FULLSIZE,
|
||||||
|
** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
|
||||||
|
*/
|
||||||
|
static int exprStructSize(Expr *p){
|
||||||
|
if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE;
|
||||||
|
if( ExprHasProperty(p, EP_SpanOnly) ) return EXPR_SPANONLYSIZE;
|
||||||
|
if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE;
|
||||||
|
return EXPR_FULLSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** sqlite3ExprDup() has been called to create a copy of expression p with
|
||||||
|
** the EXPRDUP_XXX flags passed as the second argument. This function
|
||||||
|
** returns the space required for the copy of the Expr structure only.
|
||||||
|
** This is always one of EXPR_FULLSIZE, EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
|
||||||
|
*/
|
||||||
|
static int dupedExprStructSize(Expr *p, int flags){
|
||||||
|
int nSize;
|
||||||
|
if( 0==(flags&EXPRDUP_REDUCE) ){
|
||||||
|
nSize = EXPR_FULLSIZE;
|
||||||
|
}else if( p->pLeft || p->pRight || p->pColl || p->x.pList ){
|
||||||
|
nSize = EXPR_REDUCEDSIZE;
|
||||||
|
}else if( flags&EXPRDUP_SPAN ){
|
||||||
|
nSize = EXPR_SPANONLYSIZE;
|
||||||
|
}else{
|
||||||
|
nSize = EXPR_TOKENONLYSIZE;
|
||||||
|
}
|
||||||
|
return nSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** sqlite3ExprDup() has been called to create a copy of expression p with
|
||||||
|
** the EXPRDUP_XXX passed as the second argument. This function returns
|
||||||
|
** the space in bytes required to store the copy of the Expr structure
|
||||||
|
** and the copies of the Expr.token.z and Expr.span.z (if applicable)
|
||||||
|
** string buffers.
|
||||||
|
*/
|
||||||
|
static int dupedExprNodeSize(Expr *p, int flags){
|
||||||
|
int nByte = dupedExprStructSize(p, flags) + (p->token.z ? p->token.n + 1 : 0);
|
||||||
|
if( flags&EXPRDUP_SPAN && (p->token.z!=p->span.z || p->token.n!=p->span.n) ){
|
||||||
|
nByte += p->span.n;
|
||||||
|
}
|
||||||
|
return (nByte+7)&~7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return the number of bytes required to create a duplicate of the
|
||||||
|
** expression passed as the first argument. The second argument is a
|
||||||
|
** mask containing EXPRDUP_XXX flags.
|
||||||
|
**
|
||||||
|
** The value returned includes space to create a copy of the Expr struct
|
||||||
|
** itself and the buffer referred to by Expr.token, if any. If the
|
||||||
|
** EXPRDUP_SPAN flag is set, then space to create a copy of the buffer
|
||||||
|
** refered to by Expr.span is also included.
|
||||||
|
**
|
||||||
|
** If the EXPRDUP_REDUCE flag is set, then the return value includes
|
||||||
|
** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
|
||||||
|
** and Expr.pRight variables (but not for any structures pointed to or
|
||||||
|
** descended from the Expr.x.pList or Expr.x.pSelect variables).
|
||||||
|
*/
|
||||||
|
static int dupedExprSize(Expr *p, int flags){
|
||||||
|
int nByte = 0;
|
||||||
|
if( p ){
|
||||||
|
nByte = dupedExprNodeSize(p, flags);
|
||||||
|
if( flags&EXPRDUP_REDUCE ){
|
||||||
|
int f = flags&(~EXPRDUP_SPAN);
|
||||||
|
nByte += dupedExprSize(p->pLeft, f) + dupedExprSize(p->pRight, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This function is similar to sqlite3ExprDup(), except that if pzBuffer
|
||||||
|
** is not NULL then *pzBuffer is assumed to point to a buffer large enough
|
||||||
|
** to store the copy of expression p, the copies of p->token and p->span
|
||||||
|
** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
|
||||||
|
** if any. Before returning, *pzBuffer is set to the first byte passed the
|
||||||
|
** portion of the buffer copied into by this function.
|
||||||
|
*/
|
||||||
|
static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
|
||||||
|
Expr *pNew = 0; /* Value to return */
|
||||||
|
if( p ){
|
||||||
|
const int isRequireSpan = (flags&EXPRDUP_SPAN);
|
||||||
|
const int isReduced = (flags&EXPRDUP_REDUCE);
|
||||||
|
u8 *zAlloc;
|
||||||
|
|
||||||
|
assert( pzBuffer==0 || isReduced );
|
||||||
|
|
||||||
|
/* Figure out where to write the new Expr structure. */
|
||||||
|
if( pzBuffer ){
|
||||||
|
zAlloc = *pzBuffer;
|
||||||
|
}else{
|
||||||
|
zAlloc = sqlite3DbMallocRaw(db, dupedExprSize(p, flags));
|
||||||
|
}
|
||||||
|
pNew = (Expr *)zAlloc;
|
||||||
|
|
||||||
|
if( pNew ){
|
||||||
|
/* Set nNewSize to the size allocated for the structure pointed to
|
||||||
|
** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
|
||||||
|
** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
|
||||||
|
** by the copy of the p->token.z string (if any).
|
||||||
|
*/
|
||||||
|
const int nNewSize = dupedExprStructSize(p, flags);
|
||||||
|
const int nToken = (p->token.z ? p->token.n + 1 : 0);
|
||||||
|
if( isReduced ){
|
||||||
|
assert( ExprHasProperty(p, EP_Reduced)==0 );
|
||||||
|
memcpy(zAlloc, p, nNewSize);
|
||||||
|
}else{
|
||||||
|
int nSize = exprStructSize(p);
|
||||||
|
memcpy(zAlloc, p, nSize);
|
||||||
|
memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the EP_Reduced and EP_TokenOnly flags appropriately. */
|
||||||
|
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_SpanOnly);
|
||||||
|
switch( nNewSize ){
|
||||||
|
case EXPR_REDUCEDSIZE: pNew->flags |= EP_Reduced; break;
|
||||||
|
case EXPR_TOKENONLYSIZE: pNew->flags |= EP_TokenOnly; break;
|
||||||
|
case EXPR_SPANONLYSIZE: pNew->flags |= EP_SpanOnly; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the p->token string, if any. */
|
||||||
|
if( nToken ){
|
||||||
|
unsigned char *zToken = &zAlloc[nNewSize];
|
||||||
|
memcpy(zToken, p->token.z, nToken-1);
|
||||||
|
zToken[nToken-1] = '\0';
|
||||||
|
pNew->token.dyn = 0;
|
||||||
|
pNew->token.z = zToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
|
||||||
|
/* Fill in the pNew->span token, if required. */
|
||||||
|
if( isRequireSpan ){
|
||||||
|
if( p->token.z!=p->span.z || p->token.n!=p->span.n ){
|
||||||
|
pNew->span.z = &zAlloc[nNewSize+nToken];
|
||||||
|
memcpy((char *)pNew->span.z, p->span.z, p->span.n);
|
||||||
|
pNew->span.dyn = 0;
|
||||||
|
}else{
|
||||||
|
pNew->span.z = pNew->token.z;
|
||||||
|
pNew->span.n = pNew->token.n;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
pNew->span.z = 0;
|
||||||
|
pNew->span.n = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_SpanOnly)) ){
|
||||||
|
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
|
||||||
|
if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||||
|
pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced);
|
||||||
|
}else{
|
||||||
|
pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, isReduced);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill in pNew->pLeft and pNew->pRight. */
|
||||||
|
if( ExprHasAnyProperty(pNew, EP_Reduced|EP_TokenOnly|EP_SpanOnly) ){
|
||||||
|
zAlloc += dupedExprNodeSize(p, flags);
|
||||||
|
if( ExprHasProperty(pNew, EP_Reduced) ){
|
||||||
|
pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
|
||||||
|
pNew->pRight = exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc);
|
||||||
|
}
|
||||||
|
if( pzBuffer ){
|
||||||
|
*pzBuffer = zAlloc;
|
||||||
|
}
|
||||||
|
}else if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanOnly) ){
|
||||||
|
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
|
||||||
|
pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pNew;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The following group of routines make deep copies of expressions,
|
** The following group of routines make deep copies of expressions,
|
||||||
** expression lists, ID lists, and select statements. The copies can
|
** expression lists, ID lists, and select statements. The copies can
|
||||||
@ -650,25 +841,19 @@ void sqlite3DequoteExpr(sqlite3 *db, Expr *p){
|
|||||||
** by subsequent calls to sqlite*ListAppend() routines.
|
** by subsequent calls to sqlite*ListAppend() routines.
|
||||||
**
|
**
|
||||||
** Any tables that the SrcList might point to are not duplicated.
|
** Any tables that the SrcList might point to are not duplicated.
|
||||||
|
**
|
||||||
|
** The flags parameter contains a combination of the EXPRDUP_XXX flags. If
|
||||||
|
** the EXPRDUP_SPAN flag is set in the argument parameter, then the
|
||||||
|
** Expr.span field of the input expression is copied. If EXPRDUP_SPAN is
|
||||||
|
** clear, then the Expr.span field of the returned expression structure
|
||||||
|
** is zeroed.
|
||||||
|
**
|
||||||
|
** If the EXPRDUP_REDUCE flag is set, then the structure returned is a
|
||||||
|
** truncated version of the usual Expr structure that will be stored as
|
||||||
|
** part of the in-memory representation of the database schema.
|
||||||
*/
|
*/
|
||||||
Expr *sqlite3ExprDup(sqlite3 *db, Expr *p){
|
Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
|
||||||
Expr *pNew;
|
return exprDup(db, p, flags, 0);
|
||||||
if( p==0 ) return 0;
|
|
||||||
pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
|
|
||||||
if( pNew==0 ) return 0;
|
|
||||||
memcpy(pNew, p, sizeof(*pNew));
|
|
||||||
if( p->token.z!=0 ){
|
|
||||||
pNew->token.z = (u8*)sqlite3DbStrNDup(db, (char*)p->token.z, p->token.n);
|
|
||||||
pNew->token.dyn = 1;
|
|
||||||
}else{
|
|
||||||
assert( pNew->token.z==0 );
|
|
||||||
}
|
|
||||||
pNew->span.z = 0;
|
|
||||||
pNew->pLeft = sqlite3ExprDup(db, p->pLeft);
|
|
||||||
pNew->pRight = sqlite3ExprDup(db, p->pRight);
|
|
||||||
pNew->pList = sqlite3ExprListDup(db, p->pList);
|
|
||||||
pNew->pSelect = sqlite3SelectDup(db, p->pSelect);
|
|
||||||
return pNew;
|
|
||||||
}
|
}
|
||||||
void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
|
void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
|
||||||
if( pTo->dyn ) sqlite3DbFree(db, (char*)pTo->z);
|
if( pTo->dyn ) sqlite3DbFree(db, (char*)pTo->z);
|
||||||
@ -680,7 +865,7 @@ void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
|
|||||||
pTo->z = 0;
|
pTo->z = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
|
ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
||||||
ExprList *pNew;
|
ExprList *pNew;
|
||||||
struct ExprList_item *pItem, *pOldItem;
|
struct ExprList_item *pItem, *pOldItem;
|
||||||
int i;
|
int i;
|
||||||
@ -696,17 +881,9 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
|
|||||||
}
|
}
|
||||||
pOldItem = p->a;
|
pOldItem = p->a;
|
||||||
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
|
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
|
||||||
Expr *pNewExpr, *pOldExpr;
|
Expr *pNewExpr;
|
||||||
pItem->pExpr = pNewExpr = sqlite3ExprDup(db, pOldExpr = pOldItem->pExpr);
|
Expr *pOldExpr = pOldItem->pExpr;
|
||||||
if( pOldExpr->span.z!=0 && pNewExpr ){
|
pItem->pExpr = pNewExpr = sqlite3ExprDup(db, pOldExpr, flags);
|
||||||
/* Always make a copy of the span for top-level expressions in the
|
|
||||||
** expression list. The logic in SELECT processing that determines
|
|
||||||
** the names of columns in the result set needs this information */
|
|
||||||
sqlite3TokenCopy(db, &pNewExpr->span, &pOldExpr->span);
|
|
||||||
}
|
|
||||||
assert( pNewExpr==0 || pNewExpr->span.z!=0
|
|
||||||
|| pOldExpr->span.z==0
|
|
||||||
|| db->mallocFailed );
|
|
||||||
pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
|
pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
|
||||||
pItem->sortOrder = pOldItem->sortOrder;
|
pItem->sortOrder = pOldItem->sortOrder;
|
||||||
pItem->done = 0;
|
pItem->done = 0;
|
||||||
@ -724,7 +901,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
|
|||||||
*/
|
*/
|
||||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
|
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
|
||||||
|| !defined(SQLITE_OMIT_SUBQUERY)
|
|| !defined(SQLITE_OMIT_SUBQUERY)
|
||||||
SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){
|
SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
|
||||||
SrcList *pNew;
|
SrcList *pNew;
|
||||||
int i;
|
int i;
|
||||||
int nByte;
|
int nByte;
|
||||||
@ -750,8 +927,8 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){
|
|||||||
if( pTab ){
|
if( pTab ){
|
||||||
pTab->nRef++;
|
pTab->nRef++;
|
||||||
}
|
}
|
||||||
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect);
|
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
|
||||||
pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn);
|
pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
|
||||||
pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
|
pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
|
||||||
pNewItem->colUsed = pOldItem->colUsed;
|
pNewItem->colUsed = pOldItem->colUsed;
|
||||||
}
|
}
|
||||||
@ -777,21 +954,24 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
|
|||||||
}
|
}
|
||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
Select *sqlite3SelectDup(sqlite3 *db, Select *p){
|
Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
||||||
Select *pNew;
|
Select *pNew;
|
||||||
if( p==0 ) return 0;
|
if( p==0 ) return 0;
|
||||||
pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
|
pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
|
||||||
if( pNew==0 ) return 0;
|
if( pNew==0 ) return 0;
|
||||||
pNew->pEList = sqlite3ExprListDup(db, p->pEList);
|
/* Always make a copy of the span for top-level expressions in the
|
||||||
pNew->pSrc = sqlite3SrcListDup(db, p->pSrc);
|
** expression list. The logic in SELECT processing that determines
|
||||||
pNew->pWhere = sqlite3ExprDup(db, p->pWhere);
|
** the names of columns in the result set needs this information */
|
||||||
pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy);
|
pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags|EXPRDUP_SPAN);
|
||||||
pNew->pHaving = sqlite3ExprDup(db, p->pHaving);
|
pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
|
||||||
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy);
|
pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
|
||||||
|
pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
|
||||||
|
pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
|
||||||
|
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
|
||||||
pNew->op = p->op;
|
pNew->op = p->op;
|
||||||
pNew->pPrior = sqlite3SelectDup(db, p->pPrior);
|
pNew->pPrior = sqlite3SelectDup(db, p->pPrior, flags);
|
||||||
pNew->pLimit = sqlite3ExprDup(db, p->pLimit);
|
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
|
||||||
pNew->pOffset = sqlite3ExprDup(db, p->pOffset);
|
pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
|
||||||
pNew->iLimit = 0;
|
pNew->iLimit = 0;
|
||||||
pNew->iOffset = 0;
|
pNew->iOffset = 0;
|
||||||
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
|
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
|
||||||
@ -802,7 +982,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p){
|
|||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
Select *sqlite3SelectDup(sqlite3 *db, Select *p){
|
Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
||||||
assert( p==0 );
|
assert( p==0 );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1143,7 +1323,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
|||||||
** If this is the case, it may be possible to use an existing table
|
** If this is the case, it may be possible to use an existing table
|
||||||
** or index instead of generating an epheremal table.
|
** or index instead of generating an epheremal table.
|
||||||
*/
|
*/
|
||||||
p = pX->pSelect;
|
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
|
||||||
if( isCandidateForInOpt(p) ){
|
if( isCandidateForInOpt(p) ){
|
||||||
sqlite3 *db = pParse->db;
|
sqlite3 *db = pParse->db;
|
||||||
Index *pIdx;
|
Index *pIdx;
|
||||||
@ -1222,7 +1402,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
|||||||
eType = IN_INDEX_EPH;
|
eType = IN_INDEX_EPH;
|
||||||
if( prNotFound ){
|
if( prNotFound ){
|
||||||
*prNotFound = rMayHaveNull = ++pParse->nMem;
|
*prNotFound = rMayHaveNull = ++pParse->nMem;
|
||||||
}else if( pX->pLeft->iColumn<0 && pX->pSelect==0 ){
|
}else if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){
|
||||||
eType = IN_INDEX_ROWID;
|
eType = IN_INDEX_ROWID;
|
||||||
}
|
}
|
||||||
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
|
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
|
||||||
@ -1311,7 +1491,7 @@ void sqlite3CodeSubselect(
|
|||||||
memset(&keyInfo, 0, sizeof(keyInfo));
|
memset(&keyInfo, 0, sizeof(keyInfo));
|
||||||
keyInfo.nField = 1;
|
keyInfo.nField = 1;
|
||||||
|
|
||||||
if( pExpr->pSelect ){
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||||
/* Case 1: expr IN (SELECT ...)
|
/* Case 1: expr IN (SELECT ...)
|
||||||
**
|
**
|
||||||
** Generate code to write the results of the select into the temporary
|
** Generate code to write the results of the select into the temporary
|
||||||
@ -1324,15 +1504,15 @@ void sqlite3CodeSubselect(
|
|||||||
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
|
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
|
||||||
dest.affinity = (u8)affinity;
|
dest.affinity = (u8)affinity;
|
||||||
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
||||||
if( sqlite3Select(pParse, pExpr->pSelect, &dest) ){
|
if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pEList = pExpr->pSelect->pEList;
|
pEList = pExpr->x.pSelect->pEList;
|
||||||
if( pEList && pEList->nExpr>0 ){
|
if( pEList && pEList->nExpr>0 ){
|
||||||
keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
|
keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
|
||||||
pEList->a[0].pExpr);
|
pEList->a[0].pExpr);
|
||||||
}
|
}
|
||||||
}else if( pExpr->pList ){
|
}else if( pExpr->x.pList ){
|
||||||
/* Case 2: expr IN (exprlist)
|
/* Case 2: expr IN (exprlist)
|
||||||
**
|
**
|
||||||
** For each expression, build an index key from the evaluation and
|
** For each expression, build an index key from the evaluation and
|
||||||
@ -1341,7 +1521,7 @@ void sqlite3CodeSubselect(
|
|||||||
** a column, use numeric affinity.
|
** a column, use numeric affinity.
|
||||||
*/
|
*/
|
||||||
int i;
|
int i;
|
||||||
ExprList *pList = pExpr->pList;
|
ExprList *pList = pExpr->x.pList;
|
||||||
struct ExprList_item *pItem;
|
struct ExprList_item *pItem;
|
||||||
int r1, r2, r3;
|
int r1, r2, r3;
|
||||||
|
|
||||||
@ -1401,7 +1581,8 @@ void sqlite3CodeSubselect(
|
|||||||
Select *pSel;
|
Select *pSel;
|
||||||
SelectDest dest;
|
SelectDest dest;
|
||||||
|
|
||||||
pSel = pExpr->pSelect;
|
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||||
|
pSel = pExpr->x.pSelect;
|
||||||
sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
|
sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
|
||||||
if( pExpr->op==TK_SELECT ){
|
if( pExpr->op==TK_SELECT ){
|
||||||
dest.eDest = SRT_Mem;
|
dest.eDest = SRT_Mem;
|
||||||
@ -1985,7 +2166,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
}
|
}
|
||||||
case TK_CONST_FUNC:
|
case TK_CONST_FUNC:
|
||||||
case TK_FUNCTION: {
|
case TK_FUNCTION: {
|
||||||
ExprList *pList = pExpr->pList;
|
ExprList *pList = (
|
||||||
|
ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanOnly) ? 0 : pExpr->x.pList
|
||||||
|
);
|
||||||
int nExpr = pList ? pList->nExpr : 0;
|
int nExpr = pList ? pList->nExpr : 0;
|
||||||
FuncDef *pDef;
|
FuncDef *pDef;
|
||||||
int nId;
|
int nId;
|
||||||
@ -1995,6 +2178,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
u8 enc = ENC(db);
|
u8 enc = ENC(db);
|
||||||
CollSeq *pColl = 0;
|
CollSeq *pColl = 0;
|
||||||
|
|
||||||
|
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||||
testcase( op==TK_CONST_FUNC );
|
testcase( op==TK_CONST_FUNC );
|
||||||
testcase( op==TK_FUNCTION );
|
testcase( op==TK_FUNCTION );
|
||||||
zId = (char*)pExpr->token.z;
|
zId = (char*)pExpr->token.z;
|
||||||
@ -2162,7 +2346,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
*/
|
*/
|
||||||
case TK_BETWEEN: {
|
case TK_BETWEEN: {
|
||||||
Expr *pLeft = pExpr->pLeft;
|
Expr *pLeft = pExpr->pLeft;
|
||||||
struct ExprList_item *pLItem = pExpr->pList->a;
|
struct ExprList_item *pLItem = pExpr->x.pList->a;
|
||||||
Expr *pRight = pLItem->pExpr;
|
Expr *pRight = pLItem->pExpr;
|
||||||
|
|
||||||
codeCompareOperands(pParse, pLeft, &r1, ®Free1,
|
codeCompareOperands(pParse, pLeft, &r1, ®Free1,
|
||||||
@ -2222,10 +2406,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
Expr *pX; /* The X expression */
|
Expr *pX; /* The X expression */
|
||||||
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
|
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
|
||||||
|
|
||||||
assert(pExpr->pList);
|
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
|
||||||
assert((pExpr->pList->nExpr % 2) == 0);
|
assert((pExpr->x.pList->nExpr % 2) == 0);
|
||||||
assert(pExpr->pList->nExpr > 0);
|
assert(pExpr->x.pList->nExpr > 0);
|
||||||
pEList = pExpr->pList;
|
pEList = pExpr->x.pList;
|
||||||
aListelem = pEList->a;
|
aListelem = pEList->a;
|
||||||
nExpr = pEList->nExpr;
|
nExpr = pEList->nExpr;
|
||||||
endLabel = sqlite3VdbeMakeLabel(v);
|
endLabel = sqlite3VdbeMakeLabel(v);
|
||||||
@ -2273,15 +2457,15 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
"RAISE() may only be used within a trigger-program");
|
"RAISE() may only be used within a trigger-program");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if( pExpr->iColumn!=OE_Ignore ){
|
if( pExpr->affinity!=OE_Ignore ){
|
||||||
assert( pExpr->iColumn==OE_Rollback ||
|
assert( pExpr->affinity==OE_Rollback ||
|
||||||
pExpr->iColumn == OE_Abort ||
|
pExpr->affinity == OE_Abort ||
|
||||||
pExpr->iColumn == OE_Fail );
|
pExpr->affinity == OE_Fail );
|
||||||
sqlite3DequoteExpr(db, pExpr);
|
sqlite3DequoteExpr(db, pExpr);
|
||||||
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn, 0,
|
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->affinity, 0,
|
||||||
(char*)pExpr->token.z, pExpr->token.n);
|
(char*)pExpr->token.z, pExpr->token.n);
|
||||||
} else {
|
} else {
|
||||||
assert( pExpr->iColumn == OE_Ignore );
|
assert( pExpr->affinity == OE_Ignore );
|
||||||
sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
|
||||||
VdbeComment((v, "raise(IGNORE)"));
|
VdbeComment((v, "raise(IGNORE)"));
|
||||||
@ -2438,7 +2622,8 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
|
|||||||
** Mark them this way to avoid generated unneeded OP_SCopy
|
** Mark them this way to avoid generated unneeded OP_SCopy
|
||||||
** instructions.
|
** instructions.
|
||||||
*/
|
*/
|
||||||
ExprList *pList = pExpr->pList;
|
ExprList *pList = pExpr->x.pList;
|
||||||
|
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||||
if( pList ){
|
if( pList ){
|
||||||
int i = pList->nExpr;
|
int i = pList->nExpr;
|
||||||
struct ExprList_item *pItem = pList->a;
|
struct ExprList_item *pItem = pList->a;
|
||||||
@ -2614,16 +2799,17 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
Expr compRight;
|
Expr compRight;
|
||||||
Expr exprX;
|
Expr exprX;
|
||||||
|
|
||||||
|
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||||
exprX = *pExpr->pLeft;
|
exprX = *pExpr->pLeft;
|
||||||
exprAnd.op = TK_AND;
|
exprAnd.op = TK_AND;
|
||||||
exprAnd.pLeft = &compLeft;
|
exprAnd.pLeft = &compLeft;
|
||||||
exprAnd.pRight = &compRight;
|
exprAnd.pRight = &compRight;
|
||||||
compLeft.op = TK_GE;
|
compLeft.op = TK_GE;
|
||||||
compLeft.pLeft = &exprX;
|
compLeft.pLeft = &exprX;
|
||||||
compLeft.pRight = pExpr->pList->a[0].pExpr;
|
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
|
||||||
compRight.op = TK_LE;
|
compRight.op = TK_LE;
|
||||||
compRight.pLeft = &exprX;
|
compRight.pLeft = &exprX;
|
||||||
compRight.pRight = pExpr->pList->a[1].pExpr;
|
compRight.pRight = pExpr->x.pList->a[1].pExpr;
|
||||||
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1);
|
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1);
|
||||||
testcase( regFree1==0 );
|
testcase( regFree1==0 );
|
||||||
exprX.op = TK_REGISTER;
|
exprX.op = TK_REGISTER;
|
||||||
@ -2765,16 +2951,17 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
Expr compRight;
|
Expr compRight;
|
||||||
Expr exprX;
|
Expr exprX;
|
||||||
|
|
||||||
|
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||||
exprX = *pExpr->pLeft;
|
exprX = *pExpr->pLeft;
|
||||||
exprAnd.op = TK_AND;
|
exprAnd.op = TK_AND;
|
||||||
exprAnd.pLeft = &compLeft;
|
exprAnd.pLeft = &compLeft;
|
||||||
exprAnd.pRight = &compRight;
|
exprAnd.pRight = &compRight;
|
||||||
compLeft.op = TK_GE;
|
compLeft.op = TK_GE;
|
||||||
compLeft.pLeft = &exprX;
|
compLeft.pLeft = &exprX;
|
||||||
compLeft.pRight = pExpr->pList->a[0].pExpr;
|
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
|
||||||
compRight.op = TK_LE;
|
compRight.op = TK_LE;
|
||||||
compRight.pLeft = &exprX;
|
compRight.pLeft = &exprX;
|
||||||
compRight.pRight = pExpr->pList->a[1].pExpr;
|
compRight.pRight = pExpr->x.pList->a[1].pExpr;
|
||||||
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1);
|
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, ®Free1);
|
||||||
testcase( regFree1==0 );
|
testcase( regFree1==0 );
|
||||||
exprX.op = TK_REGISTER;
|
exprX.op = TK_REGISTER;
|
||||||
@ -2813,22 +3000,25 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
|||||||
if( pA==0||pB==0 ){
|
if( pA==0||pB==0 ){
|
||||||
return pB==pA;
|
return pB==pA;
|
||||||
}
|
}
|
||||||
if( pA->op!=pB->op ) return 0;
|
if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
|
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
|
||||||
|
if( pA->op!=pB->op ) return 0;
|
||||||
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
|
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
|
||||||
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
|
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
|
||||||
if( pA->pList ){
|
|
||||||
if( pB->pList==0 ) return 0;
|
if( pA->x.pList && pB->x.pList ){
|
||||||
if( pA->pList->nExpr!=pB->pList->nExpr ) return 0;
|
if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 0;
|
||||||
for(i=0; i<pA->pList->nExpr; i++){
|
for(i=0; i<pA->x.pList->nExpr; i++){
|
||||||
if( !sqlite3ExprCompare(pA->pList->a[i].pExpr, pB->pList->a[i].pExpr) ){
|
Expr *pExprA = pA->x.pList->a[i].pExpr;
|
||||||
|
Expr *pExprB = pB->x.pList->a[i].pExpr;
|
||||||
|
if( !sqlite3ExprCompare(pExprA, pExprB) ) return 0;
|
||||||
|
}
|
||||||
|
}else if( pA->x.pList || pB->x.pList ){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}else if( pB->pList ){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if( pA->pSelect || pB->pSelect ) return 0;
|
|
||||||
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
|
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
|
||||||
if( pA->op!=TK_COLUMN && pA->token.z ){
|
if( pA->op!=TK_COLUMN && pA->token.z ){
|
||||||
if( pB->token.z==0 ) return 0;
|
if( pB->token.z==0 ) return 0;
|
||||||
@ -2976,12 +3166,13 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
|||||||
u8 enc = ENC(pParse->db);
|
u8 enc = ENC(pParse->db);
|
||||||
i = addAggInfoFunc(pParse->db, pAggInfo);
|
i = addAggInfoFunc(pParse->db, pAggInfo);
|
||||||
if( i>=0 ){
|
if( i>=0 ){
|
||||||
|
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||||
pItem = &pAggInfo->aFunc[i];
|
pItem = &pAggInfo->aFunc[i];
|
||||||
pItem->pExpr = pExpr;
|
pItem->pExpr = pExpr;
|
||||||
pItem->iMem = ++pParse->nMem;
|
pItem->iMem = ++pParse->nMem;
|
||||||
pItem->pFunc = sqlite3FindFunction(pParse->db,
|
pItem->pFunc = sqlite3FindFunction(pParse->db,
|
||||||
(char*)pExpr->token.z, pExpr->token.n,
|
(char*)pExpr->token.z, pExpr->token.n,
|
||||||
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
|
pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
|
||||||
if( pExpr->flags & EP_Distinct ){
|
if( pExpr->flags & EP_Distinct ){
|
||||||
pItem->iDistinct = pParse->nTab++;
|
pItem->iDistinct = pParse->nTab++;
|
||||||
}else{
|
}else{
|
||||||
|
11
src/func.c
11
src/func.c
@ -16,7 +16,7 @@
|
|||||||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||||
** All other code has file scope.
|
** All other code has file scope.
|
||||||
**
|
**
|
||||||
** $Id: func.c,v 1.222 2009/02/04 03:59:25 shane Exp $
|
** $Id: func.c,v 1.223 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -1323,12 +1323,13 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
|
|||||||
*/
|
*/
|
||||||
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
||||||
FuncDef *pDef;
|
FuncDef *pDef;
|
||||||
if( pExpr->op!=TK_FUNCTION || !pExpr->pList ){
|
if( pExpr->op!=TK_FUNCTION
|
||||||
return 0;
|
|| !pExpr->x.pList
|
||||||
}
|
|| pExpr->x.pList->nExpr!=2
|
||||||
if( pExpr->pList->nExpr!=2 ){
|
){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||||
pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2,
|
pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2,
|
||||||
SQLITE_UTF8, 0);
|
SQLITE_UTF8, 0);
|
||||||
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
|
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle INSERT statements in SQLite.
|
** to handle INSERT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: insert.c,v 1.256 2008/12/10 21:19:57 drh Exp $
|
** $Id: insert.c,v 1.257 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ static int autoIncBegin(
|
|||||||
if( pTab->tabFlags & TF_Autoincrement ){
|
if( pTab->tabFlags & TF_Autoincrement ){
|
||||||
Vdbe *v = pParse->pVdbe;
|
Vdbe *v = pParse->pVdbe;
|
||||||
Db *pDb = &pParse->db->aDb[iDb];
|
Db *pDb = &pParse->db->aDb[iDb];
|
||||||
int iCur = pParse->nTab;
|
int iCur = pParse->nTab++;
|
||||||
int addr; /* Address of the top of the loop */
|
int addr; /* Address of the top of the loop */
|
||||||
assert( v );
|
assert( v );
|
||||||
pParse->nMem++; /* Holds name of table */
|
pParse->nMem++; /* Holds name of table */
|
||||||
@ -217,7 +217,7 @@ static void autoIncEnd(
|
|||||||
int memId /* Memory cell holding the maximum rowid */
|
int memId /* Memory cell holding the maximum rowid */
|
||||||
){
|
){
|
||||||
if( pTab->tabFlags & TF_Autoincrement ){
|
if( pTab->tabFlags & TF_Autoincrement ){
|
||||||
int iCur = pParse->nTab;
|
int iCur = pParse->nTab++;
|
||||||
Vdbe *v = pParse->pVdbe;
|
Vdbe *v = pParse->pVdbe;
|
||||||
Db *pDb = &pParse->db->aDb[iDb];
|
Db *pDb = &pParse->db->aDb[iDb];
|
||||||
int j1;
|
int j1;
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
** This file contains implementations of the low-level memory allocation
|
** This file contains implementations of the low-level memory allocation
|
||||||
** routines specified in the sqlite3_mem_methods object.
|
** routines specified in the sqlite3_mem_methods object.
|
||||||
**
|
**
|
||||||
** $Id: mem2.c,v 1.43 2009/02/05 03:00:06 shane Exp $
|
** $Id: mem2.c,v 1.44 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -248,6 +248,7 @@ static void *sqlite3MemMalloc(int nByte){
|
|||||||
void *aAddr[40];
|
void *aAddr[40];
|
||||||
pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
|
pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
|
||||||
memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*));
|
memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*));
|
||||||
|
assert(pBt[0]);
|
||||||
if( mem.xBacktrace ){
|
if( mem.xBacktrace ){
|
||||||
mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]);
|
mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]);
|
||||||
}
|
}
|
||||||
|
24
src/parse.y
24
src/parse.y
@ -14,7 +14,7 @@
|
|||||||
** the parser. Lemon will also generate a header file containing
|
** the parser. Lemon will also generate a header file containing
|
||||||
** numeric codes for all of the tokens.
|
** numeric codes for all of the tokens.
|
||||||
**
|
**
|
||||||
** @(#) $Id: parse.y,v 1.268 2009/01/29 19:27:47 drh Exp $
|
** @(#) $Id: parse.y,v 1.269 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// All token codes are small integers with #defines that begin with "TK_"
|
// All token codes are small integers with #defines that begin with "TK_"
|
||||||
@ -824,7 +824,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
|||||||
pList = sqlite3ExprListAppend(pParse,pList, Y, 0);
|
pList = sqlite3ExprListAppend(pParse,pList, Y, 0);
|
||||||
A = sqlite3PExpr(pParse, TK_BETWEEN, W, 0, 0);
|
A = sqlite3PExpr(pParse, TK_BETWEEN, W, 0, 0);
|
||||||
if( A ){
|
if( A ){
|
||||||
A->pList = pList;
|
A->x.pList = pList;
|
||||||
}else{
|
}else{
|
||||||
sqlite3ExprListDelete(pParse->db, pList);
|
sqlite3ExprListDelete(pParse->db, pList);
|
||||||
}
|
}
|
||||||
@ -838,7 +838,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
|||||||
expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] {
|
expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] {
|
||||||
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
|
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
|
||||||
if( A ){
|
if( A ){
|
||||||
A->pList = Y;
|
A->x.pList = Y;
|
||||||
sqlite3ExprSetHeight(pParse, A);
|
sqlite3ExprSetHeight(pParse, A);
|
||||||
}else{
|
}else{
|
||||||
sqlite3ExprListDelete(pParse->db, Y);
|
sqlite3ExprListDelete(pParse->db, Y);
|
||||||
@ -849,7 +849,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
|||||||
expr(A) ::= LP(B) select(X) RP(E). {
|
expr(A) ::= LP(B) select(X) RP(E). {
|
||||||
A = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
|
A = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
|
||||||
if( A ){
|
if( A ){
|
||||||
A->pSelect = X;
|
A->x.pSelect = X;
|
||||||
|
ExprSetProperty(A, EP_xIsSelect);
|
||||||
sqlite3ExprSetHeight(pParse, A);
|
sqlite3ExprSetHeight(pParse, A);
|
||||||
}else{
|
}else{
|
||||||
sqlite3SelectDelete(pParse->db, X);
|
sqlite3SelectDelete(pParse->db, X);
|
||||||
@ -859,7 +860,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
|||||||
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
|
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
|
||||||
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
|
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
|
||||||
if( A ){
|
if( A ){
|
||||||
A->pSelect = Y;
|
A->x.pSelect = Y;
|
||||||
|
ExprSetProperty(A, EP_xIsSelect);
|
||||||
sqlite3ExprSetHeight(pParse, A);
|
sqlite3ExprSetHeight(pParse, A);
|
||||||
}else{
|
}else{
|
||||||
sqlite3SelectDelete(pParse->db, Y);
|
sqlite3SelectDelete(pParse->db, Y);
|
||||||
@ -871,7 +873,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
|||||||
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
|
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
|
||||||
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
|
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
|
||||||
if( A ){
|
if( A ){
|
||||||
A->pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
|
A->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
|
||||||
|
ExprSetProperty(A, EP_xIsSelect);
|
||||||
sqlite3ExprSetHeight(pParse, A);
|
sqlite3ExprSetHeight(pParse, A);
|
||||||
}else{
|
}else{
|
||||||
sqlite3SrcListDelete(pParse->db, pSrc);
|
sqlite3SrcListDelete(pParse->db, pSrc);
|
||||||
@ -882,7 +885,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
|||||||
expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
|
expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
|
||||||
Expr *p = A = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
|
Expr *p = A = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
|
||||||
if( p ){
|
if( p ){
|
||||||
p->pSelect = Y;
|
p->x.pSelect = Y;
|
||||||
|
ExprSetProperty(A, EP_xIsSelect);
|
||||||
sqlite3ExprSpan(p,&B,&E);
|
sqlite3ExprSpan(p,&B,&E);
|
||||||
sqlite3ExprSetHeight(pParse, A);
|
sqlite3ExprSetHeight(pParse, A);
|
||||||
}else{
|
}else{
|
||||||
@ -895,7 +899,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
|||||||
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
|
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
|
||||||
A = sqlite3PExpr(pParse, TK_CASE, X, Z, 0);
|
A = sqlite3PExpr(pParse, TK_CASE, X, Z, 0);
|
||||||
if( A ){
|
if( A ){
|
||||||
A->pList = Y;
|
A->x.pList = Y;
|
||||||
sqlite3ExprSetHeight(pParse, A);
|
sqlite3ExprSetHeight(pParse, A);
|
||||||
}else{
|
}else{
|
||||||
sqlite3ExprListDelete(pParse->db, Y);
|
sqlite3ExprListDelete(pParse->db, Y);
|
||||||
@ -1100,14 +1104,14 @@ trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(pParse->db, X); }
|
|||||||
expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
|
expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
|
||||||
A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
|
A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
|
||||||
if( A ){
|
if( A ){
|
||||||
A->iColumn = OE_Ignore;
|
A->affinity = OE_Ignore;
|
||||||
sqlite3ExprSpan(A, &X, &Y);
|
sqlite3ExprSpan(A, &X, &Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
|
expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
|
||||||
A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z);
|
A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z);
|
||||||
if( A ) {
|
if( A ) {
|
||||||
A->iColumn = T;
|
A->affinity = T;
|
||||||
sqlite3ExprSpan(A, &X, &Y);
|
sqlite3ExprSpan(A, &X, &Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains code used to implement the PRAGMA command.
|
** This file contains code used to implement the PRAGMA command.
|
||||||
**
|
**
|
||||||
** $Id: pragma.c,v 1.202 2009/01/20 16:53:41 danielk1977 Exp $
|
** $Id: pragma.c,v 1.203 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -831,7 +831,6 @@ void sqlite3Pragma(
|
|||||||
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", SQLITE_STATIC);
|
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", SQLITE_STATIC);
|
||||||
sqlite3ViewGetColumnNames(pParse, pTab);
|
sqlite3ViewGetColumnNames(pParse, pTab);
|
||||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||||
const Token *pDflt;
|
|
||||||
if( IsHiddenColumn(pCol) ){
|
if( IsHiddenColumn(pCol) ){
|
||||||
nHidden++;
|
nHidden++;
|
||||||
continue;
|
continue;
|
||||||
@ -842,9 +841,9 @@ void sqlite3Pragma(
|
|||||||
pCol->zType ? pCol->zType : "", 0);
|
pCol->zType ? pCol->zType : "", 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, (pCol->notNull ? 1 : 0), 4);
|
sqlite3VdbeAddOp2(v, OP_Integer, (pCol->notNull ? 1 : 0), 4);
|
||||||
if( pCol->pDflt ){
|
if( pCol->pDflt ){
|
||||||
pDflt = &pCol->pDflt->span;
|
const Token *p = &pCol->pDflt->span;
|
||||||
assert( pDflt->z );
|
assert( p->z );
|
||||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pDflt->z, pDflt->n);
|
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)p->z, p->n);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
** interface, and routines that contribute to loading the database schema
|
** interface, and routines that contribute to loading the database schema
|
||||||
** from disk.
|
** from disk.
|
||||||
**
|
**
|
||||||
** $Id: prepare.c,v 1.105 2009/01/20 16:53:41 danielk1977 Exp $
|
** $Id: prepare.c,v 1.106 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -621,8 +621,10 @@ static int sqlite3Prepare(
|
|||||||
rc = SQLITE_MISUSE;
|
rc = SQLITE_MISUSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( saveSqlFlag ){
|
assert( db->init.busy==0 || saveSqlFlag==0 );
|
||||||
sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail - zSql));
|
if( db->init.busy==0 ){
|
||||||
|
Vdbe *pVdbe = sParse.pVdbe;
|
||||||
|
sqlite3VdbeSetSql(pVdbe, zSql, (int)(sParse.zTail-zSql), saveSqlFlag);
|
||||||
}
|
}
|
||||||
if( rc!=SQLITE_OK || db->mallocFailed ){
|
if( rc!=SQLITE_OK || db->mallocFailed ){
|
||||||
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
|
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
** resolve all identifiers by associating them with a particular
|
** resolve all identifiers by associating them with a particular
|
||||||
** table and column.
|
** table and column.
|
||||||
**
|
**
|
||||||
** $Id: resolve.c,v 1.15 2008/12/10 19:26:24 drh Exp $
|
** $Id: resolve.c,v 1.16 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -63,7 +63,7 @@ static void resolveAlias(
|
|||||||
assert( pOrig!=0 );
|
assert( pOrig!=0 );
|
||||||
assert( pOrig->flags & EP_Resolved );
|
assert( pOrig->flags & EP_Resolved );
|
||||||
db = pParse->db;
|
db = pParse->db;
|
||||||
pDup = sqlite3ExprDup(db, pOrig);
|
pDup = sqlite3ExprDup(db, pOrig, 0);
|
||||||
if( pDup==0 ) return;
|
if( pDup==0 ) return;
|
||||||
if( pDup->op!=TK_COLUMN && zType[0]!='G' ){
|
if( pDup->op!=TK_COLUMN && zType[0]!='G' ){
|
||||||
pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
|
pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
|
||||||
@ -282,8 +282,8 @@ static int lookupName(
|
|||||||
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
|
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
|
||||||
Expr *pOrig;
|
Expr *pOrig;
|
||||||
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
||||||
assert( pExpr->pList==0 );
|
assert( pExpr->x.pList==0 );
|
||||||
assert( pExpr->pSelect==0 );
|
assert( pExpr->x.pSelect==0 );
|
||||||
pOrig = pEList->a[j].pExpr;
|
pOrig = pEList->a[j].pExpr;
|
||||||
if( !pNC->allowAgg && ExprHasProperty(pOrig, EP_Agg) ){
|
if( !pNC->allowAgg && ExprHasProperty(pOrig, EP_Agg) ){
|
||||||
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
|
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
|
||||||
@ -474,7 +474,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||||||
*/
|
*/
|
||||||
case TK_CONST_FUNC:
|
case TK_CONST_FUNC:
|
||||||
case TK_FUNCTION: {
|
case TK_FUNCTION: {
|
||||||
ExprList *pList = pExpr->pList; /* The argument list */
|
ExprList *pList = pExpr->x.pList; /* The argument list */
|
||||||
int n = pList ? pList->nExpr : 0; /* Number of arguments */
|
int n = pList ? pList->nExpr : 0; /* Number of arguments */
|
||||||
int no_such_func = 0; /* True if no such function exists */
|
int no_such_func = 0; /* True if no such function exists */
|
||||||
int wrong_num_args = 0; /* True if wrong number of arguments */
|
int wrong_num_args = 0; /* True if wrong number of arguments */
|
||||||
@ -485,6 +485,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||||||
FuncDef *pDef; /* Information about the function */
|
FuncDef *pDef; /* Information about the function */
|
||||||
u8 enc = ENC(pParse->db); /* The database encoding */
|
u8 enc = ENC(pParse->db); /* The database encoding */
|
||||||
|
|
||||||
|
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||||
zId = (char*)pExpr->token.z;
|
zId = (char*)pExpr->token.z;
|
||||||
nId = pExpr->token.n;
|
nId = pExpr->token.n;
|
||||||
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
|
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
|
||||||
@ -541,14 +542,14 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||||||
case TK_EXISTS:
|
case TK_EXISTS:
|
||||||
#endif
|
#endif
|
||||||
case TK_IN: {
|
case TK_IN: {
|
||||||
if( pExpr->pSelect ){
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||||
int nRef = pNC->nRef;
|
int nRef = pNC->nRef;
|
||||||
#ifndef SQLITE_OMIT_CHECK
|
#ifndef SQLITE_OMIT_CHECK
|
||||||
if( pNC->isCheck ){
|
if( pNC->isCheck ){
|
||||||
sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints");
|
sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sqlite3WalkSelect(pWalker, pExpr->pSelect);
|
sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
|
||||||
assert( pNC->nRef>=nRef );
|
assert( pNC->nRef>=nRef );
|
||||||
if( nRef!=pNC->nRef ){
|
if( nRef!=pNC->nRef ){
|
||||||
ExprSetProperty(pExpr, EP_VarSelect);
|
ExprSetProperty(pExpr, EP_VarSelect);
|
||||||
@ -736,7 +737,7 @@ static int resolveCompoundOrderBy(
|
|||||||
}else{
|
}else{
|
||||||
iCol = resolveAsName(pParse, pEList, pE);
|
iCol = resolveAsName(pParse, pEList, pE);
|
||||||
if( iCol==0 ){
|
if( iCol==0 ){
|
||||||
pDup = sqlite3ExprDup(db, pE);
|
pDup = sqlite3ExprDup(db, pE, 0);
|
||||||
if( !db->mallocFailed ){
|
if( !db->mallocFailed ){
|
||||||
assert(pDup);
|
assert(pDup);
|
||||||
iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup);
|
iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup);
|
||||||
|
62
src/select.c
62
src/select.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** to handle SELECT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: select.c,v 1.499 2009/02/09 13:19:28 drh Exp $
|
** $Id: select.c,v 1.500 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -987,8 +987,9 @@ static const char *columnType(
|
|||||||
** statement.
|
** statement.
|
||||||
*/
|
*/
|
||||||
NameContext sNC;
|
NameContext sNC;
|
||||||
Select *pS = pExpr->pSelect;
|
Select *pS = pExpr->x.pSelect;
|
||||||
Expr *p = pS->pEList->a[0].pExpr;
|
Expr *p = pS->pEList->a[0].pExpr;
|
||||||
|
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||||
sNC.pSrcList = pS->pSrc;
|
sNC.pSrcList = pS->pSrc;
|
||||||
sNC.pNext = pNC;
|
sNC.pNext = pNC;
|
||||||
sNC.pParse = pNC->pParse;
|
sNC.pParse = pNC->pParse;
|
||||||
@ -2141,7 +2142,7 @@ static int multiSelectOrderBy(
|
|||||||
/* Reattach the ORDER BY clause to the query.
|
/* Reattach the ORDER BY clause to the query.
|
||||||
*/
|
*/
|
||||||
p->pOrderBy = pOrderBy;
|
p->pOrderBy = pOrderBy;
|
||||||
pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy);
|
pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0);
|
||||||
|
|
||||||
/* Allocate a range of temporary registers and the KeyInfo needed
|
/* Allocate a range of temporary registers and the KeyInfo needed
|
||||||
** for the logic that removes duplicate result rows when the
|
** for the logic that removes duplicate result rows when the
|
||||||
@ -2392,23 +2393,26 @@ static void substExpr(
|
|||||||
}else{
|
}else{
|
||||||
Expr *pNew;
|
Expr *pNew;
|
||||||
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
|
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
|
||||||
assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
|
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
||||||
pNew = pEList->a[pExpr->iColumn].pExpr;
|
pNew = pEList->a[pExpr->iColumn].pExpr;
|
||||||
assert( pNew!=0 );
|
assert( pNew!=0 );
|
||||||
pExpr->op = pNew->op;
|
pExpr->op = pNew->op;
|
||||||
assert( pExpr->pLeft==0 );
|
assert( pExpr->pLeft==0 );
|
||||||
pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft);
|
pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft, 0);
|
||||||
assert( pExpr->pRight==0 );
|
assert( pExpr->pRight==0 );
|
||||||
pExpr->pRight = sqlite3ExprDup(db, pNew->pRight);
|
pExpr->pRight = sqlite3ExprDup(db, pNew->pRight, 0);
|
||||||
assert( pExpr->pList==0 );
|
|
||||||
pExpr->pList = sqlite3ExprListDup(db, pNew->pList);
|
|
||||||
pExpr->iTable = pNew->iTable;
|
pExpr->iTable = pNew->iTable;
|
||||||
pExpr->pTab = pNew->pTab;
|
pExpr->pTab = pNew->pTab;
|
||||||
pExpr->iColumn = pNew->iColumn;
|
pExpr->iColumn = pNew->iColumn;
|
||||||
pExpr->iAgg = pNew->iAgg;
|
pExpr->iAgg = pNew->iAgg;
|
||||||
sqlite3TokenCopy(db, &pExpr->token, &pNew->token);
|
sqlite3TokenCopy(db, &pExpr->token, &pNew->token);
|
||||||
sqlite3TokenCopy(db, &pExpr->span, &pNew->span);
|
sqlite3TokenCopy(db, &pExpr->span, &pNew->span);
|
||||||
pExpr->pSelect = sqlite3SelectDup(db, pNew->pSelect);
|
assert( pExpr->x.pList==0 && pExpr->x.pSelect==0 );
|
||||||
|
if( ExprHasProperty(pNew, EP_xIsSelect) ){
|
||||||
|
pExpr->x.pSelect = sqlite3SelectDup(db, pNew->x.pSelect, 0);
|
||||||
|
}else{
|
||||||
|
pExpr->x.pList = sqlite3ExprListDup(db, pNew->x.pList, 0);
|
||||||
|
}
|
||||||
pExpr->flags = pNew->flags;
|
pExpr->flags = pNew->flags;
|
||||||
pExpr->pAggInfo = pNew->pAggInfo;
|
pExpr->pAggInfo = pNew->pAggInfo;
|
||||||
pNew->pAggInfo = 0;
|
pNew->pAggInfo = 0;
|
||||||
@ -2416,8 +2420,11 @@ static void substExpr(
|
|||||||
}else{
|
}else{
|
||||||
substExpr(db, pExpr->pLeft, iTable, pEList);
|
substExpr(db, pExpr->pLeft, iTable, pEList);
|
||||||
substExpr(db, pExpr->pRight, iTable, pEList);
|
substExpr(db, pExpr->pRight, iTable, pEList);
|
||||||
substSelect(db, pExpr->pSelect, iTable, pEList);
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||||
substExprList(db, pExpr->pList, iTable, pEList);
|
substSelect(db, pExpr->x.pSelect, iTable, pEList);
|
||||||
|
}else{
|
||||||
|
substExprList(db, pExpr->x.pList, iTable, pEList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void substExprList(
|
static void substExprList(
|
||||||
@ -2729,7 +2736,7 @@ static int flattenSubquery(
|
|||||||
p->pSrc = 0;
|
p->pSrc = 0;
|
||||||
p->pPrior = 0;
|
p->pPrior = 0;
|
||||||
p->pLimit = 0;
|
p->pLimit = 0;
|
||||||
pNew = sqlite3SelectDup(db, p);
|
pNew = sqlite3SelectDup(db, p, 0);
|
||||||
p->pLimit = pLimit;
|
p->pLimit = pLimit;
|
||||||
p->pOrderBy = pOrderBy;
|
p->pOrderBy = pOrderBy;
|
||||||
p->pSrc = pSrc;
|
p->pSrc = pSrc;
|
||||||
@ -2873,7 +2880,7 @@ static int flattenSubquery(
|
|||||||
substExprList(db, pParent->pOrderBy, iParent, pSub->pEList);
|
substExprList(db, pParent->pOrderBy, iParent, pSub->pEList);
|
||||||
}
|
}
|
||||||
if( pSub->pWhere ){
|
if( pSub->pWhere ){
|
||||||
pWhere = sqlite3ExprDup(db, pSub->pWhere);
|
pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
|
||||||
}else{
|
}else{
|
||||||
pWhere = 0;
|
pWhere = 0;
|
||||||
}
|
}
|
||||||
@ -2883,9 +2890,9 @@ static int flattenSubquery(
|
|||||||
pParent->pWhere = pWhere;
|
pParent->pWhere = pWhere;
|
||||||
substExpr(db, pParent->pHaving, iParent, pSub->pEList);
|
substExpr(db, pParent->pHaving, iParent, pSub->pEList);
|
||||||
pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
|
pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
|
||||||
sqlite3ExprDup(db, pSub->pHaving));
|
sqlite3ExprDup(db, pSub->pHaving, 0));
|
||||||
assert( pParent->pGroupBy==0 );
|
assert( pParent->pGroupBy==0 );
|
||||||
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy);
|
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
|
||||||
}else{
|
}else{
|
||||||
substExpr(db, pParent->pWhere, iParent, pSub->pEList);
|
substExpr(db, pParent->pWhere, iParent, pSub->pEList);
|
||||||
pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
|
pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
|
||||||
@ -2934,7 +2941,8 @@ static u8 minMaxQuery(Select *p){
|
|||||||
|
|
||||||
if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL;
|
if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL;
|
||||||
pExpr = pEList->a[0].pExpr;
|
pExpr = pEList->a[0].pExpr;
|
||||||
pEList = pExpr->pList;
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ) return 0;
|
||||||
|
pEList = pExpr->x.pList;
|
||||||
if( pExpr->op!=TK_AGG_FUNCTION || pEList==0 || pEList->nExpr!=1 ) return 0;
|
if( pExpr->op!=TK_AGG_FUNCTION || pEList==0 || pEList->nExpr!=1 ) return 0;
|
||||||
if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL;
|
if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL;
|
||||||
if( pExpr->token.n!=3 ) return WHERE_ORDERBY_NORMAL;
|
if( pExpr->token.n!=3 ) return WHERE_ORDERBY_NORMAL;
|
||||||
@ -3065,7 +3073,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|||||||
** in the inner view.
|
** in the inner view.
|
||||||
*/
|
*/
|
||||||
if( pFrom->pSelect==0 ){
|
if( pFrom->pSelect==0 ){
|
||||||
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect);
|
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
|
||||||
sqlite3WalkSelect(pWalker, pFrom->pSelect);
|
sqlite3WalkSelect(pWalker, pFrom->pSelect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3364,12 +3372,13 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
|||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pFunc->iMem);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, pFunc->iMem);
|
||||||
if( pFunc->iDistinct>=0 ){
|
if( pFunc->iDistinct>=0 ){
|
||||||
Expr *pE = pFunc->pExpr;
|
Expr *pE = pFunc->pExpr;
|
||||||
if( pE->pList==0 || pE->pList->nExpr!=1 ){
|
assert( !ExprHasProperty(pE, EP_xIsSelect) );
|
||||||
|
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
|
||||||
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
|
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
|
||||||
"argument");
|
"argument");
|
||||||
pFunc->iDistinct = -1;
|
pFunc->iDistinct = -1;
|
||||||
}else{
|
}else{
|
||||||
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList);
|
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList);
|
||||||
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
|
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
|
||||||
(char*)pKeyInfo, P4_KEYINFO_HANDOFF);
|
(char*)pKeyInfo, P4_KEYINFO_HANDOFF);
|
||||||
}
|
}
|
||||||
@ -3386,7 +3395,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
|
|||||||
int i;
|
int i;
|
||||||
struct AggInfo_func *pF;
|
struct AggInfo_func *pF;
|
||||||
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
|
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
|
||||||
ExprList *pList = pF->pExpr->pList;
|
ExprList *pList = pF->pExpr->x.pList;
|
||||||
|
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
|
||||||
sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
|
sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
|
||||||
(void*)pF->pFunc, P4_FUNCDEF);
|
(void*)pF->pFunc, P4_FUNCDEF);
|
||||||
}
|
}
|
||||||
@ -3407,7 +3417,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
|||||||
int nArg;
|
int nArg;
|
||||||
int addrNext = 0;
|
int addrNext = 0;
|
||||||
int regAgg;
|
int regAgg;
|
||||||
ExprList *pList = pF->pExpr->pList;
|
ExprList *pList = pF->pExpr->x.pList;
|
||||||
|
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
|
||||||
if( pList ){
|
if( pList ){
|
||||||
nArg = pList->nExpr;
|
nArg = pList->nExpr;
|
||||||
regAgg = sqlite3GetTempRange(pParse, nArg);
|
regAgg = sqlite3GetTempRange(pParse, nArg);
|
||||||
@ -3657,7 +3668,7 @@ int sqlite3Select(
|
|||||||
** GROUP BY might use an index, DISTINCT never does.
|
** GROUP BY might use an index, DISTINCT never does.
|
||||||
*/
|
*/
|
||||||
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct && !p->pGroupBy ){
|
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct && !p->pGroupBy ){
|
||||||
p->pGroupBy = sqlite3ExprListDup(db, p->pEList);
|
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
|
||||||
pGroupBy = p->pGroupBy;
|
pGroupBy = p->pGroupBy;
|
||||||
p->selFlags &= ~SF_Distinct;
|
p->selFlags &= ~SF_Distinct;
|
||||||
isDistinct = 0;
|
isDistinct = 0;
|
||||||
@ -3780,7 +3791,8 @@ int sqlite3Select(
|
|||||||
}
|
}
|
||||||
sAggInfo.nAccumulator = sAggInfo.nColumn;
|
sAggInfo.nAccumulator = sAggInfo.nColumn;
|
||||||
for(i=0; i<sAggInfo.nFunc; i++){
|
for(i=0; i<sAggInfo.nFunc; i++){
|
||||||
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList);
|
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
|
||||||
|
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
|
||||||
}
|
}
|
||||||
if( db->mallocFailed ) goto select_end;
|
if( db->mallocFailed ) goto select_end;
|
||||||
|
|
||||||
@ -4018,7 +4030,9 @@ int sqlite3Select(
|
|||||||
*/
|
*/
|
||||||
flag = minMaxQuery(p);
|
flag = minMaxQuery(p);
|
||||||
if( flag ){
|
if( flag ){
|
||||||
pDel = pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->pList);
|
assert( !ExprHasProperty(p->pEList->a[0].pExpr, EP_xIsSelect) );
|
||||||
|
pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->x.pList,0);
|
||||||
|
pDel = pMinMax;
|
||||||
if( pMinMax && !db->mallocFailed ){
|
if( pMinMax && !db->mallocFailed ){
|
||||||
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
|
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
|
||||||
pMinMax->a[0].pExpr->op = TK_COLUMN;
|
pMinMax->a[0].pExpr->op = TK_COLUMN;
|
||||||
|
112
src/sqliteInt.h
112
src/sqliteInt.h
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.833 2009/02/05 16:53:43 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.834 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@ -1369,13 +1369,21 @@ struct AggInfo {
|
|||||||
** to represent the greater-than-or-equal-to operator in the expression
|
** to represent the greater-than-or-equal-to operator in the expression
|
||||||
** tree.
|
** tree.
|
||||||
**
|
**
|
||||||
** Expr.pRight and Expr.pLeft are subexpressions. Expr.pList is a list
|
** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
|
||||||
** of argument if the expression is a function.
|
** or TK_STRING), then Expr.token contains the text of the SQL literal. If
|
||||||
|
** the expression is a variable (TK_VARIABLE), then Expr.token contains the
|
||||||
|
** variable name. Finally, if the expression is an SQL function (TK_FUNCTION),
|
||||||
|
** then Expr.token contains the name of the function.
|
||||||
**
|
**
|
||||||
** Expr.token is the operator token for this node. For some expressions
|
** Expr.pRight and Expr.pLeft are the left and right subexpressions of a
|
||||||
** that have subexpressions, Expr.token can be the complete text that gave
|
** binary operator. Either or both may be NULL.
|
||||||
** rise to the Expr. In the latter case, the token is marked as being
|
**
|
||||||
** a compound token.
|
** Expr.x.pList is a list of arguments if the expression is an SQL function,
|
||||||
|
** a CASE expression or an IN expression of the form "<lhs> IN (<y>, <z>...)".
|
||||||
|
** Expr.x.pSelect is used if the expression is a sub-select or an expression of
|
||||||
|
** the form "<lhs> IN (SELECT ...)". If the EP_xIsSelect bit is set in the
|
||||||
|
** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
|
||||||
|
** valid.
|
||||||
**
|
**
|
||||||
** An expression of the form ID or ID.ID refers to a column in a table.
|
** An expression of the form ID or ID.ID refers to a column in a table.
|
||||||
** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is
|
** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is
|
||||||
@ -1385,10 +1393,9 @@ struct AggInfo {
|
|||||||
** value is also stored in the Expr.iAgg column in the aggregate so that
|
** value is also stored in the Expr.iAgg column in the aggregate so that
|
||||||
** it can be accessed after all aggregates are computed.
|
** it can be accessed after all aggregates are computed.
|
||||||
**
|
**
|
||||||
** If the expression is a function, the Expr.iTable is an integer code
|
** If the expression is an unbound variable marker (a question mark
|
||||||
** representing which function. If the expression is an unbound variable
|
** character '?' in the original SQL) then the Expr.iTable holds the index
|
||||||
** marker (a question mark character '?' in the original SQL) then the
|
** number for that variable.
|
||||||
** Expr.iTable holds the index number for that variable.
|
|
||||||
**
|
**
|
||||||
** If the expression is a subquery then Expr.iColumn holds an integer
|
** If the expression is a subquery then Expr.iColumn holds an integer
|
||||||
** register number containing the result of the subquery. If the
|
** register number containing the result of the subquery. If the
|
||||||
@ -1396,32 +1403,62 @@ struct AggInfo {
|
|||||||
** gives a different answer at different times during statement processing
|
** gives a different answer at different times during statement processing
|
||||||
** then iTable is the address of a subroutine that computes the subquery.
|
** then iTable is the address of a subroutine that computes the subquery.
|
||||||
**
|
**
|
||||||
** The Expr.pSelect field points to a SELECT statement. The SELECT might
|
|
||||||
** be the right operand of an IN operator. Or, if a scalar SELECT appears
|
|
||||||
** in an expression the opcode is TK_SELECT and Expr.pSelect is the only
|
|
||||||
** operand.
|
|
||||||
**
|
|
||||||
** If the Expr is of type OP_Column, and the table it is selecting from
|
** If the Expr is of type OP_Column, and the table it is selecting from
|
||||||
** is a disk table or the "old.*" pseudo-table, then pTab points to the
|
** is a disk table or the "old.*" pseudo-table, then pTab points to the
|
||||||
** corresponding table definition.
|
** corresponding table definition.
|
||||||
|
**
|
||||||
|
** ALLOCATION NOTES:
|
||||||
|
**
|
||||||
|
** Expr structures may be stored as part of the in-memory database schema,
|
||||||
|
** for example as part of trigger, view or table definitions. In this case,
|
||||||
|
** the amount of memory consumed by complex expressions may be significant.
|
||||||
|
** For this reason, less than sizeof(Expr) bytes may be allocated for some
|
||||||
|
** Expr structs stored as part of the in-memory database schema.
|
||||||
|
**
|
||||||
|
** If the EP_Reduced flag is set in Expr.flags, then only EXPR_REDUCEDSIZE
|
||||||
|
** bytes of space are allocated for the expression structure. This is enough
|
||||||
|
** space to store all fields up to and including the "Token span;" field.
|
||||||
|
**
|
||||||
|
** If the EP_TokenOnly flag is set in Expr.flags, then only EXPR_TOKENONLYSIZE
|
||||||
|
** bytes of space are allocated for the expression structure. This is enough
|
||||||
|
** space to store all fields up to and including the "Token token;" field.
|
||||||
*/
|
*/
|
||||||
struct Expr {
|
struct Expr {
|
||||||
u8 op; /* Operation performed by this node */
|
u8 op; /* Operation performed by this node */
|
||||||
char affinity; /* The affinity of the column or 0 if not a column */
|
char affinity; /* The affinity of the column or 0 if not a column */
|
||||||
u16 flags; /* Various flags. See below */
|
u16 flags; /* Various flags. See below */
|
||||||
CollSeq *pColl; /* The collation type of the column or 0 */
|
|
||||||
Expr *pLeft, *pRight; /* Left and right subnodes */
|
|
||||||
ExprList *pList; /* A list of expressions used as function arguments
|
|
||||||
** or in "<expr> IN (<expr-list)" */
|
|
||||||
Token token; /* An operand token */
|
Token token; /* An operand token */
|
||||||
|
|
||||||
|
/* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
|
||||||
|
** space is allocated for the fields below this point. An attempt to
|
||||||
|
** access them will result in a segfault or malfunction.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
Token span; /* Complete text of the expression */
|
Token span; /* Complete text of the expression */
|
||||||
|
|
||||||
|
/* If the EP_SpanOnly flag is set in the Expr.flags mask, then no
|
||||||
|
** space is allocated for the fields below this point. An attempt to
|
||||||
|
** access them will result in a segfault or malfunction.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
Expr *pLeft; /* Left subnode */
|
||||||
|
Expr *pRight; /* Right subnode */
|
||||||
|
union {
|
||||||
|
ExprList *pList; /* Function arguments or in "<expr> IN (<expr-list)" */
|
||||||
|
Select *pSelect; /* Used for sub-selects and "<expr> IN (<select>)" */
|
||||||
|
} x;
|
||||||
|
CollSeq *pColl; /* The collation type of the column or 0 */
|
||||||
|
|
||||||
|
/* If the EP_Reduced flag is set in the Expr.flags mask, then no
|
||||||
|
** space is allocated for the fields below this point. An attempt to
|
||||||
|
** access them will result in a segfault or malfunction.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
|
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
|
||||||
** iColumn-th field of the iTable-th table. */
|
** iColumn-th field of the iTable-th table. */
|
||||||
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
|
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
|
||||||
int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
|
int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
|
||||||
int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
|
int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
|
||||||
Select *pSelect; /* When the expression is a sub-select. Also the
|
|
||||||
** right side of "<expr> IN (<select>)" */
|
|
||||||
Table *pTab; /* Table for TK_COLUMN expressions. */
|
Table *pTab; /* Table for TK_COLUMN expressions. */
|
||||||
#if SQLITE_MAX_EXPR_DEPTH>0
|
#if SQLITE_MAX_EXPR_DEPTH>0
|
||||||
int nHeight; /* Height of the tree headed by this node */
|
int nHeight; /* Height of the tree headed by this node */
|
||||||
@ -1443,6 +1480,12 @@ struct Expr {
|
|||||||
#define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */
|
#define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */
|
||||||
#define EP_FixedDest 0x0400 /* Result needed in a specific register */
|
#define EP_FixedDest 0x0400 /* Result needed in a specific register */
|
||||||
#define EP_IntValue 0x0800 /* Integer value contained in iTable */
|
#define EP_IntValue 0x0800 /* Integer value contained in iTable */
|
||||||
|
#define EP_xIsSelect 0x1000 /* x.pSelect is valid (otherwise x.pList is) */
|
||||||
|
|
||||||
|
#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
|
||||||
|
#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
|
||||||
|
#define EP_SpanOnly 0x8000 /* Expr struct is EXPR_SPANONLYSIZE bytes only */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** These macros can be used to test, set, or clear bits in the
|
** These macros can be used to test, set, or clear bits in the
|
||||||
** Expr.flags field.
|
** Expr.flags field.
|
||||||
@ -1452,6 +1495,23 @@ struct Expr {
|
|||||||
#define ExprSetProperty(E,P) (E)->flags|=(P)
|
#define ExprSetProperty(E,P) (E)->flags|=(P)
|
||||||
#define ExprClearProperty(E,P) (E)->flags&=~(P)
|
#define ExprClearProperty(E,P) (E)->flags&=~(P)
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Macros to determine the number of bytes required by a normal Expr
|
||||||
|
** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
|
||||||
|
** and an Expr struct with the EP_TokenOnly flag set.
|
||||||
|
*/
|
||||||
|
#define EXPR_FULLSIZE sizeof(Expr)
|
||||||
|
#define EXPR_REDUCEDSIZE ((int)(&((Expr*)(0))->iTable))
|
||||||
|
#define EXPR_TOKENONLYSIZE ((int)(&((Expr*)(0))->span))
|
||||||
|
#define EXPR_SPANONLYSIZE ((int)(&((Expr*)(0))->pLeft))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Flags passed to the sqlite3ExprDup() function. See the header comment
|
||||||
|
** above sqlite3ExprDup() for details.
|
||||||
|
*/
|
||||||
|
#define EXPRDUP_REDUCE 0x0001
|
||||||
|
#define EXPRDUP_SPAN 0x0002
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A list of expressions. Each expression may optionally have a
|
** A list of expressions. Each expression may optionally have a
|
||||||
** name. An expr/name combination can be used in several ways, such
|
** name. An expr/name combination can be used in several ways, such
|
||||||
@ -2379,12 +2439,12 @@ void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
|
|||||||
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
|
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
|
||||||
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
|
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
|
||||||
void sqlite3BeginWriteOperation(Parse*, int, int);
|
void sqlite3BeginWriteOperation(Parse*, int, int);
|
||||||
Expr *sqlite3ExprDup(sqlite3*,Expr*);
|
Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
|
||||||
void sqlite3TokenCopy(sqlite3*,Token*, Token*);
|
void sqlite3TokenCopy(sqlite3*,Token*, Token*);
|
||||||
ExprList *sqlite3ExprListDup(sqlite3*,ExprList*);
|
ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
|
||||||
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*);
|
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
|
||||||
IdList *sqlite3IdListDup(sqlite3*,IdList*);
|
IdList *sqlite3IdListDup(sqlite3*,IdList*);
|
||||||
Select *sqlite3SelectDup(sqlite3*,Select*);
|
Select *sqlite3SelectDup(sqlite3*,Select*,int);
|
||||||
void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
|
void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
|
||||||
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int);
|
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int);
|
||||||
void sqlite3RegisterBuiltinFunctions(sqlite3*);
|
void sqlite3RegisterBuiltinFunctions(sqlite3*);
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
** $Id: trigger.c,v 1.133 2008/12/26 07:56:39 danielk1977 Exp $
|
** $Id: trigger.c,v 1.134 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ void sqlite3BeginTrigger(
|
|||||||
pTrigger->pTabSchema = pTab->pSchema;
|
pTrigger->pTabSchema = pTab->pSchema;
|
||||||
pTrigger->op = (u8)op;
|
pTrigger->op = (u8)op;
|
||||||
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
|
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
|
||||||
pTrigger->pWhen = sqlite3ExprDup(db, pWhen);
|
pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
|
||||||
pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
|
pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
|
||||||
sqlite3TokenCopy(db, &pTrigger->nameToken,pName);
|
sqlite3TokenCopy(db, &pTrigger->nameToken,pName);
|
||||||
assert( pParse->pNewTrigger==0 );
|
assert( pParse->pNewTrigger==0 );
|
||||||
@ -292,17 +292,17 @@ static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){
|
|||||||
p->target.dyn = 1;
|
p->target.dyn = 1;
|
||||||
}
|
}
|
||||||
if( p->pSelect ){
|
if( p->pSelect ){
|
||||||
Select *pNew = sqlite3SelectDup(db, p->pSelect);
|
Select *pNew = sqlite3SelectDup(db, p->pSelect, 1);
|
||||||
sqlite3SelectDelete(db, p->pSelect);
|
sqlite3SelectDelete(db, p->pSelect);
|
||||||
p->pSelect = pNew;
|
p->pSelect = pNew;
|
||||||
}
|
}
|
||||||
if( p->pWhere ){
|
if( p->pWhere ){
|
||||||
Expr *pNew = sqlite3ExprDup(db, p->pWhere);
|
Expr *pNew = sqlite3ExprDup(db, p->pWhere, EXPRDUP_REDUCE);
|
||||||
sqlite3ExprDelete(db, p->pWhere);
|
sqlite3ExprDelete(db, p->pWhere);
|
||||||
p->pWhere = pNew;
|
p->pWhere = pNew;
|
||||||
}
|
}
|
||||||
if( p->pExprList ){
|
if( p->pExprList ){
|
||||||
ExprList *pNew = sqlite3ExprListDup(db, p->pExprList);
|
ExprList *pNew = sqlite3ExprListDup(db, p->pExprList, 1);
|
||||||
sqlite3ExprListDelete(db, p->pExprList);
|
sqlite3ExprListDelete(db, p->pExprList);
|
||||||
p->pExprList = pNew;
|
p->pExprList = pNew;
|
||||||
}
|
}
|
||||||
@ -546,6 +546,9 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
|||||||
sqlite3ChangeCookie(pParse, iDb);
|
sqlite3ChangeCookie(pParse, iDb);
|
||||||
sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
|
||||||
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->name, 0);
|
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->name, 0);
|
||||||
|
if( pParse->nMem<3 ){
|
||||||
|
pParse->nMem = 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,7 +680,7 @@ static int codeTriggerProgram(
|
|||||||
pParse->trigStack->orconf = orconf;
|
pParse->trigStack->orconf = orconf;
|
||||||
switch( pTriggerStep->op ){
|
switch( pTriggerStep->op ){
|
||||||
case TK_SELECT: {
|
case TK_SELECT: {
|
||||||
Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect);
|
Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect, 0);
|
||||||
if( ss ){
|
if( ss ){
|
||||||
SelectDest dest;
|
SelectDest dest;
|
||||||
|
|
||||||
@ -692,8 +695,8 @@ static int codeTriggerProgram(
|
|||||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||||
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
|
||||||
sqlite3Update(pParse, pSrc,
|
sqlite3Update(pParse, pSrc,
|
||||||
sqlite3ExprListDup(db, pTriggerStep->pExprList),
|
sqlite3ExprListDup(db, pTriggerStep->pExprList, 0),
|
||||||
sqlite3ExprDup(db, pTriggerStep->pWhere), orconf);
|
sqlite3ExprDup(db, pTriggerStep->pWhere, 0), orconf);
|
||||||
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
|
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -702,8 +705,8 @@ static int codeTriggerProgram(
|
|||||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||||
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
|
||||||
sqlite3Insert(pParse, pSrc,
|
sqlite3Insert(pParse, pSrc,
|
||||||
sqlite3ExprListDup(db, pTriggerStep->pExprList),
|
sqlite3ExprListDup(db, pTriggerStep->pExprList, 0),
|
||||||
sqlite3SelectDup(db, pTriggerStep->pSelect),
|
sqlite3SelectDup(db, pTriggerStep->pSelect, 0),
|
||||||
sqlite3IdListDup(db, pTriggerStep->pIdList), orconf);
|
sqlite3IdListDup(db, pTriggerStep->pIdList), orconf);
|
||||||
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
|
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
|
||||||
break;
|
break;
|
||||||
@ -713,7 +716,7 @@ static int codeTriggerProgram(
|
|||||||
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
|
||||||
pSrc = targetSrcList(pParse, pTriggerStep);
|
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||||
sqlite3DeleteFrom(pParse, pSrc,
|
sqlite3DeleteFrom(pParse, pSrc,
|
||||||
sqlite3ExprDup(db, pTriggerStep->pWhere));
|
sqlite3ExprDup(db, pTriggerStep->pWhere, 0));
|
||||||
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
|
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -830,7 +833,7 @@ int sqlite3CodeRowTrigger(
|
|||||||
|
|
||||||
/* code the WHEN clause */
|
/* code the WHEN clause */
|
||||||
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
|
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
|
||||||
whenExpr = sqlite3ExprDup(db, p->pWhen);
|
whenExpr = sqlite3ExprDup(db, p->pWhen, 0);
|
||||||
if( db->mallocFailed || sqlite3ResolveExprNames(&sNC, whenExpr) ){
|
if( db->mallocFailed || sqlite3ResolveExprNames(&sNC, whenExpr) ){
|
||||||
pParse->trigStack = trigStackEntry.pNext;
|
pParse->trigStack = trigStackEntry.pNext;
|
||||||
sqlite3ExprDelete(db, whenExpr);
|
sqlite3ExprDelete(db, whenExpr);
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle UPDATE statements.
|
** to handle UPDATE statements.
|
||||||
**
|
**
|
||||||
** $Id: update.c,v 1.191 2008/12/23 23:56:22 drh Exp $
|
** $Id: update.c,v 1.192 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -633,12 +633,12 @@ static void updateVirtualTable(
|
|||||||
sqlite3CreateIdExpr(pParse, "_rowid_"), 0);
|
sqlite3CreateIdExpr(pParse, "_rowid_"), 0);
|
||||||
if( pRowid ){
|
if( pRowid ){
|
||||||
pEList = sqlite3ExprListAppend(pParse, pEList,
|
pEList = sqlite3ExprListAppend(pParse, pEList,
|
||||||
sqlite3ExprDup(db, pRowid), 0);
|
sqlite3ExprDup(db, pRowid, 0), 0);
|
||||||
}
|
}
|
||||||
assert( pTab->iPKey<0 );
|
assert( pTab->iPKey<0 );
|
||||||
for(i=0; i<pTab->nCol; i++){
|
for(i=0; i<pTab->nCol; i++){
|
||||||
if( aXRef[i]>=0 ){
|
if( aXRef[i]>=0 ){
|
||||||
pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr);
|
pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0);
|
||||||
}else{
|
}else{
|
||||||
pExpr = sqlite3CreateIdExpr(pParse, pTab->aCol[i].zName);
|
pExpr = sqlite3CreateIdExpr(pParse, pTab->aCol[i].zName);
|
||||||
}
|
}
|
||||||
|
35
src/vdbe.c
35
src/vdbe.c
@ -43,7 +43,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** commenting and indentation practices when changing or adding code.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.817 2009/02/16 17:55:47 shane Exp $
|
** $Id: vdbe.c,v 1.818 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "vdbeInt.h"
|
#include "vdbeInt.h"
|
||||||
@ -1002,15 +1002,14 @@ case OP_Move: {
|
|||||||
int n = pOp->p3;
|
int n = pOp->p3;
|
||||||
int p1 = pOp->p1;
|
int p1 = pOp->p1;
|
||||||
int p2 = pOp->p2;
|
int p2 = pOp->p2;
|
||||||
assert( n>0 );
|
assert( n>0 && p1>0 && p2>0 );
|
||||||
assert( p1>0 );
|
|
||||||
assert( p1+n<p->nMem );
|
|
||||||
pIn1 = &p->aMem[p1];
|
|
||||||
assert( p2>0 );
|
|
||||||
assert( p2+n<p->nMem );
|
|
||||||
pOut = &p->aMem[p2];
|
|
||||||
assert( p1+n<=p2 || p2+n<=p1 );
|
assert( p1+n<=p2 || p2+n<=p1 );
|
||||||
|
|
||||||
|
pIn1 = &p->aMem[p1];
|
||||||
|
pOut = &p->aMem[p2];
|
||||||
while( n-- ){
|
while( n-- ){
|
||||||
|
assert( pOut<=&p->aMem[p->nMem] );
|
||||||
|
assert( pIn1<=&p->aMem[p->nMem] );
|
||||||
zMalloc = pOut->zMalloc;
|
zMalloc = pOut->zMalloc;
|
||||||
pOut->zMalloc = 0;
|
pOut->zMalloc = 0;
|
||||||
sqlite3VdbeMemMove(pOut, pIn1);
|
sqlite3VdbeMemMove(pOut, pIn1);
|
||||||
@ -1076,7 +1075,7 @@ case OP_ResultRow: {
|
|||||||
int i;
|
int i;
|
||||||
assert( p->nResColumn==pOp->p2 );
|
assert( p->nResColumn==pOp->p2 );
|
||||||
assert( pOp->p1>0 );
|
assert( pOp->p1>0 );
|
||||||
assert( pOp->p1+pOp->p2<=p->nMem );
|
assert( pOp->p1+pOp->p2<=p->nMem+1 );
|
||||||
|
|
||||||
/* Invalidate all ephemeral cursor row caches */
|
/* Invalidate all ephemeral cursor row caches */
|
||||||
p->cacheCtr = (p->cacheCtr + 2)|1;
|
p->cacheCtr = (p->cacheCtr + 2)|1;
|
||||||
@ -1095,7 +1094,6 @@ case OP_ResultRow: {
|
|||||||
|
|
||||||
/* Return SQLITE_ROW
|
/* Return SQLITE_ROW
|
||||||
*/
|
*/
|
||||||
p->nCallback++;
|
|
||||||
p->pc = pc + 1;
|
p->pc = pc + 1;
|
||||||
rc = SQLITE_ROW;
|
rc = SQLITE_ROW;
|
||||||
goto vdbe_return;
|
goto vdbe_return;
|
||||||
@ -1300,7 +1298,7 @@ case OP_Function: {
|
|||||||
apVal = p->apArg;
|
apVal = p->apArg;
|
||||||
assert( apVal || n==0 );
|
assert( apVal || n==0 );
|
||||||
|
|
||||||
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem) );
|
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) );
|
||||||
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
|
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
|
||||||
pArg = &p->aMem[pOp->p2];
|
pArg = &p->aMem[pOp->p2];
|
||||||
for(i=0; i<n; i++, pArg++){
|
for(i=0; i<n; i++, pArg++){
|
||||||
@ -1736,9 +1734,9 @@ case OP_Compare: {
|
|||||||
assert( n>0 );
|
assert( n>0 );
|
||||||
assert( pKeyInfo!=0 );
|
assert( pKeyInfo!=0 );
|
||||||
p1 = pOp->p1;
|
p1 = pOp->p1;
|
||||||
assert( p1>0 && p1+n-1<p->nMem );
|
assert( p1>0 && p1+n<=p->nMem+1 );
|
||||||
p2 = pOp->p2;
|
p2 = pOp->p2;
|
||||||
assert( p2>0 && p2+n-1<p->nMem );
|
assert( p2>0 && p2+n<=p->nMem+1 );
|
||||||
for(i=0; i<n; i++){
|
for(i=0; i<n; i++){
|
||||||
int idx = aPermute ? aPermute[i] : i;
|
int idx = aPermute ? aPermute[i] : i;
|
||||||
CollSeq *pColl; /* Collating sequence to use on this term */
|
CollSeq *pColl; /* Collating sequence to use on this term */
|
||||||
@ -2253,7 +2251,7 @@ case OP_MakeRecord: {
|
|||||||
|
|
||||||
nField = pOp->p1;
|
nField = pOp->p1;
|
||||||
zAffinity = pOp->p4.z;
|
zAffinity = pOp->p4.z;
|
||||||
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem );
|
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem+1 );
|
||||||
pData0 = &p->aMem[nField];
|
pData0 = &p->aMem[nField];
|
||||||
nField = pOp->p2;
|
nField = pOp->p2;
|
||||||
pLast = &pData0[nField-1];
|
pLast = &pData0[nField-1];
|
||||||
@ -4066,7 +4064,7 @@ case OP_IdxDelete: {
|
|||||||
VdbeCursor *pC;
|
VdbeCursor *pC;
|
||||||
BtCursor *pCrsr;
|
BtCursor *pCrsr;
|
||||||
assert( pOp->p3>0 );
|
assert( pOp->p3>0 );
|
||||||
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem );
|
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem+1 );
|
||||||
assert( i>=0 && i<p->nCursor );
|
assert( i>=0 && i<p->nCursor );
|
||||||
assert( p->apCsr[i]!=0 );
|
assert( p->apCsr[i]!=0 );
|
||||||
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
|
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
|
||||||
@ -5204,13 +5202,14 @@ case OP_Pagecount: { /* out2-prerelease */
|
|||||||
** the UTF-8 string contained in P4 is emitted on the trace callback.
|
** the UTF-8 string contained in P4 is emitted on the trace callback.
|
||||||
*/
|
*/
|
||||||
case OP_Trace: {
|
case OP_Trace: {
|
||||||
if( pOp->p4.z ){
|
char *zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
|
||||||
|
if( zTrace ){
|
||||||
if( db->xTrace ){
|
if( db->xTrace ){
|
||||||
db->xTrace(db->pTraceArg, pOp->p4.z);
|
db->xTrace(db->pTraceArg, zTrace);
|
||||||
}
|
}
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
if( (db->flags & SQLITE_SqlTrace)!=0 ){
|
if( (db->flags & SQLITE_SqlTrace)!=0 ){
|
||||||
sqlite3DebugPrintf("SQL-trace: %s\n", pOp->p4.z);
|
sqlite3DebugPrintf("SQL-trace: %s\n", zTrace);
|
||||||
}
|
}
|
||||||
#endif /* SQLITE_DEBUG */
|
#endif /* SQLITE_DEBUG */
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||||
** simple program to access and modify the underlying database.
|
** simple program to access and modify the underlying database.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.h,v 1.139 2008/10/31 10:53:23 danielk1977 Exp $
|
** $Id: vdbe.h,v 1.140 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE_VDBE_H_
|
#ifndef _SQLITE_VDBE_H_
|
||||||
#define _SQLITE_VDBE_H_
|
#define _SQLITE_VDBE_H_
|
||||||
@ -181,7 +181,7 @@ void sqlite3VdbeSetNumCols(Vdbe*,int);
|
|||||||
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
|
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
|
||||||
void sqlite3VdbeCountChanges(Vdbe*);
|
void sqlite3VdbeCountChanges(Vdbe*);
|
||||||
sqlite3 *sqlite3VdbeDb(Vdbe*);
|
sqlite3 *sqlite3VdbeDb(Vdbe*);
|
||||||
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
|
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
|
||||||
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
** 6000 lines long) it was split up into several smaller files and
|
** 6000 lines long) it was split up into several smaller files and
|
||||||
** this header information was factored out.
|
** this header information was factored out.
|
||||||
**
|
**
|
||||||
** $Id: vdbeInt.h,v 1.162 2009/02/03 15:39:01 drh Exp $
|
** $Id: vdbeInt.h,v 1.163 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _VDBEINT_H_
|
#ifndef _VDBEINT_H_
|
||||||
#define _VDBEINT_H_
|
#define _VDBEINT_H_
|
||||||
@ -279,16 +279,13 @@ struct Vdbe {
|
|||||||
u32 magic; /* Magic number for sanity checking */
|
u32 magic; /* Magic number for sanity checking */
|
||||||
int nMem; /* Number of memory locations currently allocated */
|
int nMem; /* Number of memory locations currently allocated */
|
||||||
Mem *aMem; /* The memory locations */
|
Mem *aMem; /* The memory locations */
|
||||||
int nCallback; /* Number of callbacks invoked so far */
|
|
||||||
int cacheCtr; /* VdbeCursor row cache generation counter */
|
int cacheCtr; /* VdbeCursor row cache generation counter */
|
||||||
int contextStackTop; /* Index of top element in the context stack */
|
int contextStackTop; /* Index of top element in the context stack */
|
||||||
int contextStackDepth; /* The size of the "context" stack */
|
int contextStackDepth; /* The size of the "context" stack */
|
||||||
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
|
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
|
||||||
int pc; /* The program counter */
|
int pc; /* The program counter */
|
||||||
int rc; /* Value to return */
|
int rc; /* Value to return */
|
||||||
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
|
|
||||||
int errorAction; /* Recovery action to do in case of an error */
|
int errorAction; /* Recovery action to do in case of an error */
|
||||||
int inTempTrans; /* True if temp database is transactioned */
|
|
||||||
int nResColumn; /* Number of columns in one row of the result set */
|
int nResColumn; /* Number of columns in one row of the result set */
|
||||||
char **azResColumn; /* Values for one row of result */
|
char **azResColumn; /* Values for one row of result */
|
||||||
char *zErrMsg; /* Error message written here */
|
char *zErrMsg; /* Error message written here */
|
||||||
@ -300,12 +297,12 @@ struct Vdbe {
|
|||||||
u8 inVtabMethod; /* See comments above */
|
u8 inVtabMethod; /* See comments above */
|
||||||
u8 usesStmtJournal; /* True if uses a statement journal */
|
u8 usesStmtJournal; /* True if uses a statement journal */
|
||||||
u8 readOnly; /* True for read-only statements */
|
u8 readOnly; /* True for read-only statements */
|
||||||
|
u8 isPrepareV2; /* True if prepared with prepare_v2() */
|
||||||
int nChange; /* Number of db changes made since last reset */
|
int nChange; /* Number of db changes made since last reset */
|
||||||
i64 startTime; /* Time when query started - used for profiling */
|
i64 startTime; /* Time when query started - used for profiling */
|
||||||
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
|
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
|
||||||
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
|
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
|
||||||
int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
|
int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
|
||||||
int nSql; /* Number of bytes in zSql */
|
|
||||||
char *zSql; /* Text of the SQL statement that generated this */
|
char *zSql; /* Text of the SQL statement that generated this */
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
FILE *trace; /* Write an execution trace here, if not NULL */
|
FILE *trace; /* Write an execution trace here, if not NULL */
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
** This file contains code use to implement APIs that are part of the
|
** This file contains code use to implement APIs that are part of the
|
||||||
** VDBE.
|
** VDBE.
|
||||||
**
|
**
|
||||||
** $Id: vdbeapi.c,v 1.151 2009/02/04 03:59:25 shane Exp $
|
** $Id: vdbeapi.c,v 1.152 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "vdbeInt.h"
|
#include "vdbeInt.h"
|
||||||
@ -488,15 +488,14 @@ static int sqlite3Step(Vdbe *p){
|
|||||||
#ifndef SQLITE_OMIT_TRACE
|
#ifndef SQLITE_OMIT_TRACE
|
||||||
/* Invoke the profile callback if there is one
|
/* Invoke the profile callback if there is one
|
||||||
*/
|
*/
|
||||||
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->nOp>0
|
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
|
||||||
&& p->aOp[0].opcode==OP_Trace && p->aOp[0].p4.z!=0 ){
|
|
||||||
double rNow;
|
double rNow;
|
||||||
u64 elapseTime;
|
u64 elapseTime;
|
||||||
|
|
||||||
sqlite3OsCurrentTime(db->pVfs, &rNow);
|
sqlite3OsCurrentTime(db->pVfs, &rNow);
|
||||||
elapseTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
|
elapseTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
|
||||||
elapseTime -= p->startTime;
|
elapseTime -= p->startTime;
|
||||||
db->xProfile(db->pProfileArg, p->aOp[0].p4.z, elapseTime);
|
db->xProfile(db->pProfileArg, p->zSql, elapseTime);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -505,7 +504,7 @@ static int sqlite3Step(Vdbe *p){
|
|||||||
p->rc = sqlite3ApiExit(p->db, p->rc);
|
p->rc = sqlite3ApiExit(p->db, p->rc);
|
||||||
end_of_step:
|
end_of_step:
|
||||||
assert( (rc&0xff)==rc );
|
assert( (rc&0xff)==rc );
|
||||||
if( p->zSql && (rc&0xff)<SQLITE_ROW ){
|
if( p->isPrepareV2 && (rc&0xff)<SQLITE_ROW ){
|
||||||
/* This behavior occurs if sqlite3_prepare_v2() was used to build
|
/* This behavior occurs if sqlite3_prepare_v2() was used to build
|
||||||
** the prepared statement. Return error codes directly */
|
** the prepared statement. Return error codes directly */
|
||||||
p->db->errCode = p->rc;
|
p->db->errCode = p->rc;
|
||||||
@ -549,7 +548,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
|||||||
sqlite3_reset(pStmt);
|
sqlite3_reset(pStmt);
|
||||||
v->expired = 0;
|
v->expired = 0;
|
||||||
}
|
}
|
||||||
if( rc==SQLITE_SCHEMA && v->zSql && db->pErr ){
|
if( rc==SQLITE_SCHEMA && v->isPrepareV2 && db->pErr ){
|
||||||
/* This case occurs after failing to recompile an sql statement.
|
/* This case occurs after failing to recompile an sql statement.
|
||||||
** The error message from the SQL compiler has already been loaded
|
** The error message from the SQL compiler has already been loaded
|
||||||
** into the database handle. This block copies the error message
|
** into the database handle. This block copies the error message
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
** to version 2.8.7, all this code was combined into the vdbe.c source file.
|
** to version 2.8.7, all this code was combined into the vdbe.c source file.
|
||||||
** But that file was getting too big so this subroutines were split out.
|
** But that file was getting too big so this subroutines were split out.
|
||||||
**
|
**
|
||||||
** $Id: vdbeaux.c,v 1.435 2009/02/03 16:51:25 danielk1977 Exp $
|
** $Id: vdbeaux.c,v 1.436 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "vdbeInt.h"
|
#include "vdbeInt.h"
|
||||||
@ -52,17 +52,22 @@ Vdbe *sqlite3VdbeCreate(sqlite3 *db){
|
|||||||
/*
|
/*
|
||||||
** Remember the SQL string for a prepared statement.
|
** Remember the SQL string for a prepared statement.
|
||||||
*/
|
*/
|
||||||
void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n){
|
void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
|
||||||
if( p==0 ) return;
|
if( p==0 ) return;
|
||||||
|
#ifdef SQLITE_OMIT_TRACE
|
||||||
|
if( !isPrepareV2 ) return;
|
||||||
|
#endif
|
||||||
assert( p->zSql==0 );
|
assert( p->zSql==0 );
|
||||||
p->zSql = sqlite3DbStrNDup(p->db, z, n);
|
p->zSql = sqlite3DbStrNDup(p->db, z, n);
|
||||||
|
p->isPrepareV2 = isPrepareV2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return the SQL associated with a prepared statement
|
** Return the SQL associated with a prepared statement
|
||||||
*/
|
*/
|
||||||
const char *sqlite3_sql(sqlite3_stmt *pStmt){
|
const char *sqlite3_sql(sqlite3_stmt *pStmt){
|
||||||
return ((Vdbe *)pStmt)->zSql;
|
Vdbe *p = (Vdbe *)pStmt;
|
||||||
|
return (p->isPrepareV2 ? p->zSql : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -71,7 +76,6 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt){
|
|||||||
void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
|
void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
|
||||||
Vdbe tmp, *pTmp;
|
Vdbe tmp, *pTmp;
|
||||||
char *zTmp;
|
char *zTmp;
|
||||||
int nTmp;
|
|
||||||
tmp = *pA;
|
tmp = *pA;
|
||||||
*pA = *pB;
|
*pA = *pB;
|
||||||
*pB = tmp;
|
*pB = tmp;
|
||||||
@ -84,9 +88,7 @@ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
|
|||||||
zTmp = pA->zSql;
|
zTmp = pA->zSql;
|
||||||
pA->zSql = pB->zSql;
|
pA->zSql = pB->zSql;
|
||||||
pB->zSql = zTmp;
|
pB->zSql = zTmp;
|
||||||
nTmp = pA->nSql;
|
pB->isPrepareV2 = pA->isPrepareV2;
|
||||||
pA->nSql = pB->nSql;
|
|
||||||
pB->nSql = nTmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
@ -1007,6 +1009,14 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){
|
|||||||
**
|
**
|
||||||
** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
|
** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
|
||||||
** VDBE_MAGIC_RUN.
|
** VDBE_MAGIC_RUN.
|
||||||
|
**
|
||||||
|
** This function may be called more than once on a single virtual machine.
|
||||||
|
** The first call is made while compiling the SQL statement. Subsequent
|
||||||
|
** calls are made as part of the process of resetting a statement to be
|
||||||
|
** re-executed (from a call to sqlite3_reset()). The nVar, nMem, nCursor
|
||||||
|
** and isExplain parameters are only passed correct values the first time
|
||||||
|
** the function is called. On subsequent calls, from sqlite3_reset(), nVar
|
||||||
|
** is passed -1 and nMem, nCursor and isExplain are all passed zero.
|
||||||
*/
|
*/
|
||||||
void sqlite3VdbeMakeReady(
|
void sqlite3VdbeMakeReady(
|
||||||
Vdbe *p, /* The VDBE */
|
Vdbe *p, /* The VDBE */
|
||||||
@ -1039,23 +1049,26 @@ void sqlite3VdbeMakeReady(
|
|||||||
*/
|
*/
|
||||||
nMem += nCursor;
|
nMem += nCursor;
|
||||||
|
|
||||||
/*
|
/* Allocate space for memory registers, SQL variables, VDBE cursors and
|
||||||
** Allocation space for registers.
|
** an array to marshal SQL function arguments in. This is only done the
|
||||||
|
** first time this function is called for a given VDBE, not when it is
|
||||||
|
** being called from sqlite3_reset() to reset the virtual machine.
|
||||||
*/
|
*/
|
||||||
if( p->aMem==0 ){
|
if( nVar>=0 ){
|
||||||
|
int nByte;
|
||||||
int nArg; /* Maximum number of args passed to a user function. */
|
int nArg; /* Maximum number of args passed to a user function. */
|
||||||
resolveP2Values(p, &nArg);
|
resolveP2Values(p, &nArg);
|
||||||
assert( nVar>=0 );
|
|
||||||
if( isExplain && nMem<10 ){
|
if( isExplain && nMem<10 ){
|
||||||
nMem = 10;
|
nMem = 10;
|
||||||
}
|
}
|
||||||
p->aMem = sqlite3DbMallocZero(db,
|
nByte = nMem*sizeof(Mem) /* aMem */
|
||||||
nMem*sizeof(Mem) /* aMem */
|
|
||||||
+ nVar*sizeof(Mem) /* aVar */
|
+ nVar*sizeof(Mem) /* aVar */
|
||||||
+ nArg*sizeof(Mem*) /* apArg */
|
+ nArg*sizeof(Mem*) /* apArg */
|
||||||
+ nVar*sizeof(char*) /* azVar */
|
+ nVar*sizeof(char*) /* azVar */
|
||||||
+ nCursor*sizeof(VdbeCursor*)+1 /* apCsr */
|
+ nCursor*sizeof(VdbeCursor*); /* apCsr */
|
||||||
);
|
if( nByte ){
|
||||||
|
p->aMem = sqlite3DbMallocZero(db, nByte);
|
||||||
|
}
|
||||||
if( !db->mallocFailed ){
|
if( !db->mallocFailed ){
|
||||||
p->aMem--; /* aMem[] goes from 1..nMem */
|
p->aMem--; /* aMem[] goes from 1..nMem */
|
||||||
p->nMem = nMem; /* not from 0..nMem-1 */
|
p->nMem = nMem; /* not from 0..nMem-1 */
|
||||||
@ -1084,7 +1097,6 @@ void sqlite3VdbeMakeReady(
|
|||||||
|
|
||||||
p->pc = -1;
|
p->pc = -1;
|
||||||
p->rc = SQLITE_OK;
|
p->rc = SQLITE_OK;
|
||||||
p->uniqueCnt = 0;
|
|
||||||
p->errorAction = OE_Abort;
|
p->errorAction = OE_Abort;
|
||||||
p->explain |= isExplain;
|
p->explain |= isExplain;
|
||||||
p->magic = VDBE_MAGIC_RUN;
|
p->magic = VDBE_MAGIC_RUN;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
** This file contains routines used for walking the parser tree for
|
** This file contains routines used for walking the parser tree for
|
||||||
** an SQL statement.
|
** an SQL statement.
|
||||||
**
|
**
|
||||||
** $Id: walker.c,v 1.1 2008/08/20 16:35:10 drh Exp $
|
** $Id: walker.c,v 1.2 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -45,9 +45,10 @@ int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
|
|||||||
if( rc==WRC_Continue ){
|
if( rc==WRC_Continue ){
|
||||||
if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
|
if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
|
||||||
if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
|
if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
|
||||||
if( sqlite3WalkExprList(pWalker, pExpr->pList) ) return WRC_Abort;
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||||
if( sqlite3WalkSelect(pWalker, pExpr->pSelect) ){
|
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
|
||||||
return WRC_Abort;
|
}else{
|
||||||
|
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc & WRC_Abort;
|
return rc & WRC_Abort;
|
||||||
|
65
src/where.c
65
src/where.c
@ -16,7 +16,7 @@
|
|||||||
** so is applicable. Because this module is responsible for selecting
|
** so is applicable. Because this module is responsible for selecting
|
||||||
** indices, you might also think of this module as the "query optimizer".
|
** indices, you might also think of this module as the "query optimizer".
|
||||||
**
|
**
|
||||||
** $Id: where.c,v 1.368 2009/02/04 03:59:25 shane Exp $
|
** $Id: where.c,v 1.369 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -431,8 +431,11 @@ static Bitmask exprTableUsage(WhereMaskSet *pMaskSet, Expr *p){
|
|||||||
}
|
}
|
||||||
mask = exprTableUsage(pMaskSet, p->pRight);
|
mask = exprTableUsage(pMaskSet, p->pRight);
|
||||||
mask |= exprTableUsage(pMaskSet, p->pLeft);
|
mask |= exprTableUsage(pMaskSet, p->pLeft);
|
||||||
mask |= exprListTableUsage(pMaskSet, p->pList);
|
if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||||
mask |= exprSelectTableUsage(pMaskSet, p->pSelect);
|
mask |= exprSelectTableUsage(pMaskSet, p->x.pSelect);
|
||||||
|
}else{
|
||||||
|
mask |= exprListTableUsage(pMaskSet, p->x.pList);
|
||||||
|
}
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
static Bitmask exprListTableUsage(WhereMaskSet *pMaskSet, ExprList *pList){
|
static Bitmask exprListTableUsage(WhereMaskSet *pMaskSet, ExprList *pList){
|
||||||
@ -634,7 +637,7 @@ static int isLikeOrGlob(
|
|||||||
#ifdef SQLITE_EBCDIC
|
#ifdef SQLITE_EBCDIC
|
||||||
if( *pnoCase ) return 0;
|
if( *pnoCase ) return 0;
|
||||||
#endif
|
#endif
|
||||||
pList = pExpr->pList;
|
pList = pExpr->x.pList;
|
||||||
pRight = pList->a[0].pExpr;
|
pRight = pList->a[0].pExpr;
|
||||||
if( pRight->op!=TK_STRING ){
|
if( pRight->op!=TK_STRING ){
|
||||||
return 0;
|
return 0;
|
||||||
@ -689,7 +692,7 @@ static int isMatchOfColumn(
|
|||||||
sqlite3StrNICmp((const char*)pExpr->token.z,"match",5)!=0 ){
|
sqlite3StrNICmp((const char*)pExpr->token.z,"match",5)!=0 ){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pList = pExpr->pList;
|
pList = pExpr->x.pList;
|
||||||
if( pList->nExpr!=2 ){
|
if( pList->nExpr!=2 ){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -953,17 +956,18 @@ static void exprAnalyzeOrTerm(
|
|||||||
assert( pOrTerm->eOperator==WO_EQ );
|
assert( pOrTerm->eOperator==WO_EQ );
|
||||||
assert( pOrTerm->leftCursor==iCursor );
|
assert( pOrTerm->leftCursor==iCursor );
|
||||||
assert( pOrTerm->u.leftColumn==iColumn );
|
assert( pOrTerm->u.leftColumn==iColumn );
|
||||||
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight);
|
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
|
||||||
pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup, 0);
|
pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup, 0);
|
||||||
pLeft = pOrTerm->pExpr->pLeft;
|
pLeft = pOrTerm->pExpr->pLeft;
|
||||||
}
|
}
|
||||||
assert( pLeft!=0 );
|
assert( pLeft!=0 );
|
||||||
pDup = sqlite3ExprDup(db, pLeft);
|
pDup = sqlite3ExprDup(db, pLeft, 0);
|
||||||
pNew = sqlite3Expr(db, TK_IN, pDup, 0, 0);
|
pNew = sqlite3Expr(db, TK_IN, pDup, 0, 0);
|
||||||
if( pNew ){
|
if( pNew ){
|
||||||
int idxNew;
|
int idxNew;
|
||||||
transferJoinMarkings(pNew, pExpr);
|
transferJoinMarkings(pNew, pExpr);
|
||||||
pNew->pList = pList;
|
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
|
||||||
|
pNew->x.pList = pList;
|
||||||
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
|
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||||
testcase( idxNew==0 );
|
testcase( idxNew==0 );
|
||||||
exprAnalyze(pSrc, pWC, idxNew);
|
exprAnalyze(pSrc, pWC, idxNew);
|
||||||
@ -1026,8 +1030,11 @@ static void exprAnalyze(
|
|||||||
op = pExpr->op;
|
op = pExpr->op;
|
||||||
if( op==TK_IN ){
|
if( op==TK_IN ){
|
||||||
assert( pExpr->pRight==0 );
|
assert( pExpr->pRight==0 );
|
||||||
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList)
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||||
| exprSelectTableUsage(pMaskSet, pExpr->pSelect);
|
pTerm->prereqRight = exprSelectTableUsage(pMaskSet, pExpr->x.pSelect);
|
||||||
|
}else{
|
||||||
|
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->x.pList);
|
||||||
|
}
|
||||||
}else if( op==TK_ISNULL ){
|
}else if( op==TK_ISNULL ){
|
||||||
pTerm->prereqRight = 0;
|
pTerm->prereqRight = 0;
|
||||||
}else{
|
}else{
|
||||||
@ -1057,7 +1064,7 @@ static void exprAnalyze(
|
|||||||
Expr *pDup;
|
Expr *pDup;
|
||||||
if( pTerm->leftCursor>=0 ){
|
if( pTerm->leftCursor>=0 ){
|
||||||
int idxNew;
|
int idxNew;
|
||||||
pDup = sqlite3ExprDup(db, pExpr);
|
pDup = sqlite3ExprDup(db, pExpr, 0);
|
||||||
if( db->mallocFailed ){
|
if( db->mallocFailed ){
|
||||||
sqlite3ExprDelete(db, pDup);
|
sqlite3ExprDelete(db, pDup);
|
||||||
return;
|
return;
|
||||||
@ -1100,7 +1107,7 @@ static void exprAnalyze(
|
|||||||
** BETWEEN term is skipped.
|
** BETWEEN term is skipped.
|
||||||
*/
|
*/
|
||||||
else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){
|
else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){
|
||||||
ExprList *pList = pExpr->pList;
|
ExprList *pList = pExpr->x.pList;
|
||||||
int i;
|
int i;
|
||||||
static const u8 ops[] = {TK_GE, TK_LE};
|
static const u8 ops[] = {TK_GE, TK_LE};
|
||||||
assert( pList!=0 );
|
assert( pList!=0 );
|
||||||
@ -1108,8 +1115,8 @@ static void exprAnalyze(
|
|||||||
for(i=0; i<2; i++){
|
for(i=0; i<2; i++){
|
||||||
Expr *pNewExpr;
|
Expr *pNewExpr;
|
||||||
int idxNew;
|
int idxNew;
|
||||||
pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft),
|
pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft, 0),
|
||||||
sqlite3ExprDup(db, pList->a[i].pExpr), 0);
|
sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
|
||||||
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||||
testcase( idxNew==0 );
|
testcase( idxNew==0 );
|
||||||
exprAnalyze(pSrc, pWC, idxNew);
|
exprAnalyze(pSrc, pWC, idxNew);
|
||||||
@ -1148,18 +1155,18 @@ static void exprAnalyze(
|
|||||||
Expr *pNewExpr1, *pNewExpr2;
|
Expr *pNewExpr1, *pNewExpr2;
|
||||||
int idxNew1, idxNew2;
|
int idxNew1, idxNew2;
|
||||||
|
|
||||||
pLeft = pExpr->pList->a[1].pExpr;
|
pLeft = pExpr->x.pList->a[1].pExpr;
|
||||||
pRight = pExpr->pList->a[0].pExpr;
|
pRight = pExpr->x.pList->a[0].pExpr;
|
||||||
pStr1 = sqlite3PExpr(pParse, TK_STRING, 0, 0, 0);
|
pStr1 = sqlite3PExpr(pParse, TK_STRING, 0, 0, 0);
|
||||||
if( pStr1 ){
|
if( pStr1 ){
|
||||||
sqlite3TokenCopy(db, &pStr1->token, &pRight->token);
|
sqlite3TokenCopy(db, &pStr1->token, &pRight->token);
|
||||||
pStr1->token.n = nPattern;
|
pStr1->token.n = nPattern;
|
||||||
pStr1->flags = EP_Dequoted;
|
pStr1->flags = EP_Dequoted;
|
||||||
}
|
}
|
||||||
pStr2 = sqlite3ExprDup(db, pStr1);
|
pStr2 = sqlite3ExprDup(db, pStr1, 0);
|
||||||
if( !db->mallocFailed ){
|
if( !db->mallocFailed ){
|
||||||
u8 c, *pC;
|
u8 c, *pC;
|
||||||
assert( pStr2->token.dyn );
|
/* assert( pStr2->token.dyn ); */
|
||||||
pC = (u8*)&pStr2->token.z[nPattern-1];
|
pC = (u8*)&pStr2->token.z[nPattern-1];
|
||||||
c = *pC;
|
c = *pC;
|
||||||
if( noCase ){
|
if( noCase ){
|
||||||
@ -1168,11 +1175,11 @@ static void exprAnalyze(
|
|||||||
}
|
}
|
||||||
*pC = c + 1;
|
*pC = c + 1;
|
||||||
}
|
}
|
||||||
pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft), pStr1, 0);
|
pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft,0),pStr1,0);
|
||||||
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
|
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||||
testcase( idxNew1==0 );
|
testcase( idxNew1==0 );
|
||||||
exprAnalyze(pSrc, pWC, idxNew1);
|
exprAnalyze(pSrc, pWC, idxNew1);
|
||||||
pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft), pStr2, 0);
|
pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft,0),pStr2,0);
|
||||||
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
|
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||||
testcase( idxNew2==0 );
|
testcase( idxNew2==0 );
|
||||||
exprAnalyze(pSrc, pWC, idxNew2);
|
exprAnalyze(pSrc, pWC, idxNew2);
|
||||||
@ -1198,13 +1205,13 @@ static void exprAnalyze(
|
|||||||
WhereTerm *pNewTerm;
|
WhereTerm *pNewTerm;
|
||||||
Bitmask prereqColumn, prereqExpr;
|
Bitmask prereqColumn, prereqExpr;
|
||||||
|
|
||||||
pRight = pExpr->pList->a[0].pExpr;
|
pRight = pExpr->x.pList->a[0].pExpr;
|
||||||
pLeft = pExpr->pList->a[1].pExpr;
|
pLeft = pExpr->x.pList->a[1].pExpr;
|
||||||
prereqExpr = exprTableUsage(pMaskSet, pRight);
|
prereqExpr = exprTableUsage(pMaskSet, pRight);
|
||||||
prereqColumn = exprTableUsage(pMaskSet, pLeft);
|
prereqColumn = exprTableUsage(pMaskSet, pLeft);
|
||||||
if( (prereqExpr & prereqColumn)==0 ){
|
if( (prereqExpr & prereqColumn)==0 ){
|
||||||
Expr *pNewExpr;
|
Expr *pNewExpr;
|
||||||
pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight), 0);
|
pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight, 0), 0);
|
||||||
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||||
testcase( idxNew==0 );
|
testcase( idxNew==0 );
|
||||||
pNewTerm = &pWC->a[idxNew];
|
pNewTerm = &pWC->a[idxNew];
|
||||||
@ -1776,10 +1783,12 @@ static void bestIndex(
|
|||||||
pCost->rCost = 0;
|
pCost->rCost = 0;
|
||||||
pCost->nRow = 1;
|
pCost->nRow = 1;
|
||||||
return;
|
return;
|
||||||
}else if( (pExpr = pTerm->pExpr)->pList!=0 ){
|
}else if( !ExprHasProperty((pExpr = pTerm->pExpr), EP_xIsSelect)
|
||||||
|
&& pExpr->x.pList
|
||||||
|
){
|
||||||
/* Rowid IN (LIST): cost is NlogN where N is the number of list
|
/* Rowid IN (LIST): cost is NlogN where N is the number of list
|
||||||
** elements. */
|
** elements. */
|
||||||
pCost->rCost = pCost->nRow = pExpr->pList->nExpr;
|
pCost->rCost = pCost->nRow = pExpr->x.pList->nExpr;
|
||||||
pCost->rCost *= estLog(pCost->rCost);
|
pCost->rCost *= estLog(pCost->rCost);
|
||||||
}else{
|
}else{
|
||||||
/* Rowid IN (SELECT): cost is NlogN where N is the number of rows
|
/* Rowid IN (SELECT): cost is NlogN where N is the number of rows
|
||||||
@ -1925,10 +1934,10 @@ static void bestIndex(
|
|||||||
if( pTerm->eOperator & WO_IN ){
|
if( pTerm->eOperator & WO_IN ){
|
||||||
Expr *pExpr = pTerm->pExpr;
|
Expr *pExpr = pTerm->pExpr;
|
||||||
wsFlags |= WHERE_COLUMN_IN;
|
wsFlags |= WHERE_COLUMN_IN;
|
||||||
if( pExpr->pSelect!=0 ){
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||||
inMultiplier *= 25;
|
inMultiplier *= 25;
|
||||||
}else if( pExpr->pList ){
|
}else if( pExpr->x.pList ){
|
||||||
inMultiplier *= pExpr->pList->nExpr + 1;
|
inMultiplier *= pExpr->x.pList->nExpr + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
# focus of this file is testing corner cases of the DEFAULT syntax
|
# focus of this file is testing corner cases of the DEFAULT syntax
|
||||||
# on table definitions.
|
# on table definitions.
|
||||||
#
|
#
|
||||||
# $Id: default.test,v 1.2 2005/08/20 03:03:04 drh Exp $
|
# $Id: default.test,v 1.3 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
#
|
#
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
@ -49,4 +49,19 @@ do_test default-1.3 {
|
|||||||
}
|
}
|
||||||
} {1 {default value of column [y] is not constant}}
|
} {1 {default value of column [y] is not constant}}
|
||||||
|
|
||||||
|
ifcapable pragma {
|
||||||
|
do_test default-2.1 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t4(c DEFAULT 'abc');
|
||||||
|
PRAGMA table_info(t4);
|
||||||
|
}
|
||||||
|
} {0 c {} 0 'abc' 0}
|
||||||
|
do_test default-2.2 {
|
||||||
|
execsql {
|
||||||
|
INSERT INTO t4 DEFAULT VALUES;
|
||||||
|
PRAGMA table_info(t4);
|
||||||
|
}
|
||||||
|
} {0 c {} 0 'abc' 0}
|
||||||
|
}
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
# This file implements some common TCL routines used for regression
|
# This file implements some common TCL routines used for regression
|
||||||
# testing the SQLite library
|
# testing the SQLite library
|
||||||
#
|
#
|
||||||
# $Id: tester.tcl,v 1.139 2009/02/05 16:31:46 drh Exp $
|
# $Id: tester.tcl,v 1.140 2009/02/19 14:39:25 danielk1977 Exp $
|
||||||
|
|
||||||
#
|
#
|
||||||
# What for user input before continuing. This gives an opportunity
|
# What for user input before continuing. This gives an opportunity
|
||||||
@ -895,16 +895,16 @@ proc memdebug_log_sql {{filename mallocs.sql}} {
|
|||||||
|
|
||||||
set database temp
|
set database temp
|
||||||
|
|
||||||
set tbl "CREATE TABLE ${database}.malloc(nCall, nByte"
|
set tbl "CREATE TABLE ${database}.malloc(zTest, nCall, nByte, lStack);"
|
||||||
for {set ii 1} {$ii <= $nFrame} {incr ii} {
|
|
||||||
append tbl ", f${ii}"
|
|
||||||
}
|
|
||||||
append tbl ");\n"
|
|
||||||
|
|
||||||
set sql ""
|
set sql ""
|
||||||
foreach e $data {
|
foreach e $data {
|
||||||
append sql "INSERT INTO ${database}.malloc VALUES([join $e ,]);\n"
|
set nCall [lindex $e 0]
|
||||||
foreach f [lrange $e 2 end] {
|
set nByte [lindex $e 1]
|
||||||
|
set lStack [lrange $e 2 end]
|
||||||
|
append sql "INSERT INTO ${database}.malloc VALUES"
|
||||||
|
append sql "('test', $nCall, $nByte, '$lStack');\n"
|
||||||
|
foreach f $lStack {
|
||||||
set frames($f) 1
|
set frames($f) 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user