diff --git a/.golangci.yml b/.golangci.yml index 82d0e46694e1d..3aa9afe556d27 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -86,7 +86,7 @@ issues: - path: models/issue_comment_list.go linters: - dupl - # "Destroy" is misspelled in github.com/go-macaron/session/session.go:213 so it's not our responsability to fix it + # "Destroy" is misspelled in gitea.com/macaron/session/session.go:213 so it's not our responsability to fix it - path: modules/session/virtual.go linters: - misspell diff --git a/go.mod b/go.mod index 510447c930030..bd5b91982b33f 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module code.gitea.io/gitea go 1.12 require ( + gitea.com/macaron/cache v0.0.0-20190801013118-abcd497fea65 + gitea.com/macaron/session v0.0.0-20190801013118-80603dfc0b9d github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34 github.com/RoaringBitmap/roaring v0.4.7 // indirect github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca @@ -16,18 +18,13 @@ require ( github.com/blevesearch/go-porterstemmer v0.0.0-20141230013033-23a2c8e5cf1f // indirect github.com/blevesearch/segment v0.0.0-20160105220820-db70c57796cc // indirect github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26 // indirect - github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a // indirect github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f - github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c // indirect - github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a // indirect github.com/couchbase/vellum v0.0.0-20190111184608-e91b68ff3efe // indirect - github.com/couchbaselabs/go-couchbase v0.0.0-20190117181324-d904413d884d // indirect github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect github.com/denisenkom/go-mssqldb v0.0.0-20190724012636-11b2859924c1 github.com/dgrijalva/jwt-go v3.2.0+incompatible - github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 // indirect github.com/emirpasic/gods v1.12.0 github.com/etcd-io/bbolt v1.3.2 // indirect github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a @@ -43,13 +40,13 @@ require ( github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd // indirect github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 - github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 + github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 // indirect github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 github.com/go-macaron/csrf v0.0.0-20190131233648-3751b136073c github.com/go-macaron/i18n v0.0.0-20190131234336-56731837a73b github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 - github.com/go-macaron/session v0.0.0-20190131233854-0a0a789bf193 + github.com/go-macaron/session v0.0.0-20190131233854-0a0a789bf193 // indirect github.com/go-macaron/toolbox v0.0.0-20180818072302-a77f45a7ce90 github.com/go-redis/redis v6.15.2+incompatible github.com/go-sql-driver/mysql v1.4.1 @@ -69,15 +66,13 @@ require ( github.com/klauspost/cpuid v0.0.0-20160302075316-09cded8978dc // indirect github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 // indirect github.com/lafriks/xormstore v1.1.0 - github.com/lib/pq v1.1.0 + github.com/lib/pq v1.2.0 github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 github.com/lunny/levelqueue v0.0.0-20190217115915-02b525a4418e - github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de // indirect - github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af // indirect github.com/markbates/goth v1.49.0 github.com/mattn/go-isatty v0.0.7 github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d // indirect - github.com/mattn/go-sqlite3 v1.10.0 + github.com/mattn/go-sqlite3 v1.11.0 github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae // indirect @@ -95,8 +90,6 @@ require ( github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc // indirect github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd - github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d // indirect - github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff // indirect github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect github.com/stretchr/testify v1.3.0 github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect @@ -114,13 +107,11 @@ require ( golang.org/x/tools v0.0.0-20190730215328-ed3277de2799 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect - gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect gopkg.in/editorconfig/editorconfig-core-go.v1 v1.2.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df - gopkg.in/ini.v1 v1.42.0 + gopkg.in/ini.v1 v1.44.0 gopkg.in/ldap.v3 v3.0.2 gopkg.in/macaron.v1 v1.3.2 - gopkg.in/redis.v2 v2.3.2 // indirect gopkg.in/src-d/go-billy.v4 v4.3.2 gopkg.in/src-d/go-git.v4 v4.13.0 gopkg.in/stretchr/testify.v1 v1.2.2 // indirect diff --git a/go.sum b/go.sum index f8854dac7dd18..81db1f59b5b82 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,10 @@ cloud.google.com/go v0.30.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= +gitea.com/macaron/cache v0.0.0-20190801013118-abcd497fea65 h1:usQHpW8O5qaS/W/0BdORneZoHRvnebzyzJ1etvv65qQ= +gitea.com/macaron/cache v0.0.0-20190801013118-abcd497fea65/go.mod h1:Of5o0HfJoOC7luU1o6TEgoQj4o5b7Mm1sWyRAmA13kA= +gitea.com/macaron/session v0.0.0-20190801013118-80603dfc0b9d h1:9C630WW80aLH0VVgM1dXF9yL74pw4hk5FPxnaq1Ee/Y= +gitea.com/macaron/session v0.0.0-20190801013118-80603dfc0b9d/go.mod h1:xvHfSEoWjFdzK8t1f4Ef0mtP49fzDdVcDm5rUyTPTC8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -46,23 +50,24 @@ github.com/blevesearch/segment v0.0.0-20160105220820-db70c57796cc h1:7OfDAkuAGx7 github.com/blevesearch/segment v0.0.0-20160105220820-db70c57796cc/go.mod h1:IInt5XRvpiGE09KOk9mmCMLjHhydIhNPKPPFLFBB7L8= github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26 h1:NGpwhs9FOwddM6TptNrq2ycby4s24TcppSe5uG4DA/Q= github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a h1:k5TuEkqEYCRs8+66WdOkswWOj+L/YbP5ruainvn94wg= -github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= +github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= +github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f h1:REH9VH5ubNR0skLaOxK7TRJeRbE2dDfvaouQo8FsRcA= github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f/go.mod h1:6QaC0vFoKWYDth94dHFNgRT2YkT5FHdQp/Yx15aAAi0= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c h1:K4FIibkr4//ziZKOKmt4RL0YImuTjLLBtwElf+F2lSQ= -github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= -github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a h1:Y5XsLCEhtEI8qbD9RP3Qlv5FXdTDHxZM9UPUnMRgBp8= -github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= +github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d h1:XMf4E1U+b9E3ElF0mjvfXZdflBRZz4gLp16nQ/QSHQM= +github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= +github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b h1:bZ9rKU2/V8sY+NulSfxDOnXTWcs1rySqdF1sVepihvo= +github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/couchbase/vellum v0.0.0-20190111184608-e91b68ff3efe h1:2o6Y7KMjJNsuMTF8f2H2eTKRhqH7+bQbjr+D+LnhE5M= github.com/couchbase/vellum v0.0.0-20190111184608-e91b68ff3efe/go.mod h1:prYTC8EgTu3gwbqJihkud9zRXISvyulAplQ6exdCo1g= -github.com/couchbaselabs/go-couchbase v0.0.0-20190117181324-d904413d884d h1:lsBRLJe/ET6DjCaRblGwls80dOcOzhFVNJrO6uaMrMQ= -github.com/couchbaselabs/go-couchbase v0.0.0-20190117181324-d904413d884d/go.mod h1:mby/05p8HE5yHEAKiIH/555NoblMs7PtW6NrYshDruc= +github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7 h1:1XjEY/gnjQ+AfXef2U6dxCquhiRzkEpxZuWqs+QxTL8= +github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7/go.mod h1:mby/05p8HE5yHEAKiIH/555NoblMs7PtW6NrYshDruc= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8= github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso= @@ -81,8 +86,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8= -github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/etcd-io/bbolt v1.3.2 h1:RLRQ0TKLX7DlBRXAJHvbmXL17Q3KNnTBtZ9B6Qo+/Y0= @@ -236,8 +241,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lafriks/xormstore v1.1.0 h1:oq1+gjesu46VkxbCQFGdTPwYyUTeom7aBRziuOSDkw0= github.com/lafriks/xormstore v1.1.0/go.mod h1:wqtf8B94a8EtE463Ka1MaUT9ZDRl8FICA0nr65xr2wM= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0 h1:/5u4a+KGJptBRqGzPvYQL9p0d/tPR4S31+Tnzj9lEO4= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 h1:uNwtsDp7ci48vBTTxDuwcoTXz4lwtDTe7TjCQ0noaWY= github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96/go.mod h1:mmIfjCSQlGYXmJ95jFN84AkQFnVABtKuJL8IrzwvUKQ= github.com/lunny/levelqueue v0.0.0-20190217115915-02b525a4418e h1:GSprKUrG9wNgwQgROvjPGXmcZrg4OLslOuZGB0uJjx8= @@ -255,6 +260,8 @@ github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d h1:m+dSK37rFf2fqppZh github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d/go.mod h1:/M9VLO+lUPmxvoOK2PfWRZ8mTtB4q1Hy9lEGijv9Nr8= github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 h1:Pijfgr7ZuvX7QIQiEwLdRVr3RoMG+i0SbBO1Qu+7yVk= @@ -278,11 +285,16 @@ github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -329,15 +341,18 @@ github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc h1: github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d h1:qQWKKOvHN7Q9c6GdmUteCef2F9ubxMpxY1IKwpIKz68= github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= +github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= +github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= -github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff h1:86HlEv0yBCry9syNuylzqznKXDK11p6D0DT596yNMys= -github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= +github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 h1:N8Bg45zpk/UcpNGnfJt2y/3lRWASHNTUET8owPYCgYI= +github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= @@ -351,6 +366,8 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66 h1:AwmkkZT+TucFotNCL+aNJ/0KCMsRtlXN9fs8uoOMSRk= github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 h1:HOxvxvnntLiPn123Fk+twfUhCQdMDaqmb0cclArW0T0= github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tinylib/msgp v0.0.0-20180516164116-c8cf64dff200 h1:ZVvr38DYEyOPyelySqvF0I9I++85NnUMsWkroBDS4fs= @@ -376,6 +393,7 @@ golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -391,6 +409,7 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -415,6 +434,7 @@ golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190730183949-1393eb018365 h1:SaXEMXhWzMJThc05vu6uh61Q245r4KaWMrsTedk0FDc= golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -428,6 +448,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190730215328-ed3277de2799 h1:rvNf5qrBjmtxebJHK+blZSkGIv+Yg6UlDnl2ApkB6m4= golang.org/x/tools v0.0.0-20190730215328-ed3277de2799/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= @@ -436,6 +458,8 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -446,8 +470,6 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gG gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 h1:nn6Zav2sOQHCFJHEspya8KqxhFwKci30UxHy3HXPTyQ= gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= -gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e h1:wGA78yza6bu/mWcc4QfBuIEHEtc06xdiU0X8sY36yUU= -gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e/go.mod h1:xsQCaysVCudhrYTfzYWe577fCe7Ceci+6qjO2Rdc0Z4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -459,12 +481,12 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AW gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= +gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w= gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= gopkg.in/macaron.v1 v1.3.2 h1:AvWIaPmwBUA87/OWzePkoxeaw6YJWDfBt1pDFPBnLf8= gopkg.in/macaron.v1 v1.3.2/go.mod h1:PrsiawTWAGZs6wFbT5hlr7SQ2Ns9h7cUVtcUu4lQOVo= -gopkg.in/redis.v2 v2.3.2 h1:GPVIIB/JnL1wvfULefy3qXmPu1nfNu2d0yA09FHgwfs= -gopkg.in/redis.v2 v2.3.2/go.mod h1:4wl9PJ/CqzeHk3LVq1hNLHH8krm3+AXEgut4jVc++LU= gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= diff --git a/integrations/create_no_session_test.go b/integrations/create_no_session_test.go index 0cdf7e2310218..2d21f2500515e 100644 --- a/integrations/create_no_session_test.go +++ b/integrations/create_no_session_test.go @@ -16,7 +16,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers/routes" - "github.com/go-macaron/session" + "gitea.com/macaron/session" "github.com/stretchr/testify/assert" ) diff --git a/modules/auth/auth.go b/modules/auth/auth.go index 2a2ee404928cb..9317e9e28efc7 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -10,9 +10,9 @@ import ( "strings" "time" + "gitea.com/macaron/session" "github.com/Unknwon/com" "github.com/go-macaron/binding" - "github.com/go-macaron/session" gouuid "github.com/satori/go.uuid" "gopkg.in/macaron.v1" diff --git a/modules/cache/cache.go b/modules/cache/cache.go index a7412f109f108..ceb5772fcf921 100644 --- a/modules/cache/cache.go +++ b/modules/cache/cache.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/modules/setting" - mc "github.com/go-macaron/cache" + mc "gitea.com/macaron/cache" ) var conn mc.Cache diff --git a/modules/context/context.go b/modules/context/context.go index b7c77ac4605ee..dbcef3bb38788 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -20,11 +20,11 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" + "gitea.com/macaron/cache" + "gitea.com/macaron/session" "github.com/Unknwon/com" - "github.com/go-macaron/cache" "github.com/go-macaron/csrf" "github.com/go-macaron/i18n" - "github.com/go-macaron/session" "gopkg.in/macaron.v1" ) diff --git a/modules/session/memory.go b/modules/session/memory.go index 9c493bfe15b94..f00af1caf0b99 100644 --- a/modules/session/memory.go +++ b/modules/session/memory.go @@ -22,7 +22,7 @@ import ( "sync" "time" - "github.com/go-macaron/session" + "gitea.com/macaron/session" ) // MemStore represents a in-memory session store implementation. diff --git a/modules/session/virtual.go b/modules/session/virtual.go index b8ddd2f71bdd1..9345853c85380 100644 --- a/modules/session/virtual.go +++ b/modules/session/virtual.go @@ -10,13 +10,13 @@ import ( "fmt" "sync" - "github.com/go-macaron/session" - couchbase "github.com/go-macaron/session/couchbase" - memcache "github.com/go-macaron/session/memcache" - mysql "github.com/go-macaron/session/mysql" - nodb "github.com/go-macaron/session/nodb" - postgres "github.com/go-macaron/session/postgres" - redis "github.com/go-macaron/session/redis" + "gitea.com/macaron/session" + couchbase "gitea.com/macaron/session/couchbase" + memcache "gitea.com/macaron/session/memcache" + mysql "gitea.com/macaron/session/mysql" + nodb "gitea.com/macaron/session/nodb" + postgres "gitea.com/macaron/session/postgres" + redis "gitea.com/macaron/session/redis" ) // VirtualSessionProvider represents a shadowed session provider implementation. diff --git a/modules/setting/cache.go b/modules/setting/cache.go index 1f79404e0044d..7be24b865fdcf 100644 --- a/modules/setting/cache.go +++ b/modules/setting/cache.go @@ -10,8 +10,8 @@ import ( "code.gitea.io/gitea/modules/log" - _ "github.com/go-macaron/cache/memcache" // memcache plugin for cache - _ "github.com/go-macaron/cache/redis" + _ "gitea.com/macaron/cache/memcache" // memcache plugin for cache + _ "gitea.com/macaron/cache/redis" ) // Cache represents cache settings diff --git a/modules/setting/session.go b/modules/setting/session.go index bed3a9d8c077e..6e5a28bb754e3 100644 --- a/modules/setting/session.go +++ b/modules/setting/session.go @@ -12,7 +12,7 @@ import ( "code.gitea.io/gitea/modules/log" - "github.com/go-macaron/session" + "gitea.com/macaron/session" ) var ( diff --git a/modules/test/context_tests.go b/modules/test/context_tests.go index d5a800d360985..639ee53ac2747 100644 --- a/modules/test/context_tests.go +++ b/modules/test/context_tests.go @@ -14,7 +14,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" - "github.com/go-macaron/session" + "gitea.com/macaron/session" "github.com/stretchr/testify/assert" "gopkg.in/macaron.v1" ) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 6169aa563c099..40dc2f6ceb6fe 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -38,12 +38,12 @@ import ( // to registers all internal adapters _ "code.gitea.io/gitea/modules/session" + "gitea.com/macaron/cache" + "gitea.com/macaron/session" "github.com/go-macaron/binding" - "github.com/go-macaron/cache" "github.com/go-macaron/captcha" "github.com/go-macaron/csrf" "github.com/go-macaron/i18n" - "github.com/go-macaron/session" "github.com/go-macaron/toolbox" "github.com/prometheus/client_golang/prometheus" "github.com/tstranex/u2f" diff --git a/vendor/gitea.com/macaron/cache/.drone.yml b/vendor/gitea.com/macaron/cache/.drone.yml new file mode 100644 index 0000000000000..b37bc2ee5069c --- /dev/null +++ b/vendor/gitea.com/macaron/cache/.drone.yml @@ -0,0 +1,10 @@ +kind: pipeline +name: default + +steps: +- name: test + image: golang:1.12 + commands: + - go get -u + - go build -v + - go test -v -race -coverprofile=coverage.txt -covermode=atomic \ No newline at end of file diff --git a/vendor/gitea.com/macaron/cache/.gitignore b/vendor/gitea.com/macaron/cache/.gitignore new file mode 100644 index 0000000000000..5c84e85ffc410 --- /dev/null +++ b/vendor/gitea.com/macaron/cache/.gitignore @@ -0,0 +1,5 @@ +nodb/cache +ledis/tmp.db/ +nodb/tmp.db/ +/vendor +/.idea diff --git a/vendor/gitea.com/macaron/cache/LICENSE b/vendor/gitea.com/macaron/cache/LICENSE new file mode 100644 index 0000000000000..8405e89a0b120 --- /dev/null +++ b/vendor/gitea.com/macaron/cache/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/vendor/gitea.com/macaron/cache/README.md b/vendor/gitea.com/macaron/cache/README.md new file mode 100644 index 0000000000000..e9eac9611541b --- /dev/null +++ b/vendor/gitea.com/macaron/cache/README.md @@ -0,0 +1,20 @@ +# cache + +Middleware cache provides cache management for [Macaron](https://github.com/go-macaron/macaron). It can use many cache adapters, including memory, file, Redis, Memcache, PostgreSQL, MySQL, Ledis and Nodb. + +### Installation + + go get gitea.com/macaron/cache + +## Getting Help + +- [API Reference](https://gowalker.org/gitea.com/macaron/cache) +- [Documentation](http://go-macaron.com/docs/middlewares/cache) + +## Credits + +This package is a modified version of [go-macaron/cache](github.com/go-macaron/cache). + +## License + +This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text. \ No newline at end of file diff --git a/vendor/gitea.com/macaron/cache/cache.go b/vendor/gitea.com/macaron/cache/cache.go new file mode 100644 index 0000000000000..7742a3245bcd0 --- /dev/null +++ b/vendor/gitea.com/macaron/cache/cache.go @@ -0,0 +1,122 @@ +// Copyright 2013 Beego Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +// Package cache is a middleware that provides the cache management of Macaron. +package cache + +import ( + "fmt" + + "gopkg.in/macaron.v1" +) + +const _VERSION = "0.3.0" + +func Version() string { + return _VERSION +} + +// Cache is the interface that operates the cache data. +type Cache interface { + // Put puts value into cache with key and expire time. + Put(key string, val interface{}, timeout int64) error + // Get gets cached value by given key. + Get(key string) interface{} + // Delete deletes cached value by given key. + Delete(key string) error + // Incr increases cached int-type value by given key as a counter. + Incr(key string) error + // Decr decreases cached int-type value by given key as a counter. + Decr(key string) error + // IsExist returns true if cached value exists. + IsExist(key string) bool + // Flush deletes all cached data. + Flush() error + // StartAndGC starts GC routine based on config string settings. + StartAndGC(opt Options) error +} + +// Options represents a struct for specifying configuration options for the cache middleware. +type Options struct { + // Name of adapter. Default is "memory". + Adapter string + // Adapter configuration, it's corresponding to adapter. + AdapterConfig string + // GC interval time in seconds. Default is 60. + Interval int + // Occupy entire database. Default is false. + OccupyMode bool + // Configuration section name. Default is "cache". + Section string +} + +func prepareOptions(options []Options) Options { + var opt Options + if len(options) > 0 { + opt = options[0] + } + if len(opt.Section) == 0 { + opt.Section = "cache" + } + sec := macaron.Config().Section(opt.Section) + + if len(opt.Adapter) == 0 { + opt.Adapter = sec.Key("ADAPTER").MustString("memory") + } + if opt.Interval == 0 { + opt.Interval = sec.Key("INTERVAL").MustInt(60) + } + if len(opt.AdapterConfig) == 0 { + opt.AdapterConfig = sec.Key("ADAPTER_CONFIG").MustString("data/caches") + } + + return opt +} + +// NewCacher creates and returns a new cacher by given adapter name and configuration. +// It panics when given adapter isn't registered and starts GC automatically. +func NewCacher(name string, opt Options) (Cache, error) { + adapter, ok := adapters[name] + if !ok { + return nil, fmt.Errorf("cache: unknown adapter '%s'(forgot to import?)", name) + } + return adapter, adapter.StartAndGC(opt) +} + +// Cacher is a middleware that maps a cache.Cache service into the Macaron handler chain. +// An single variadic cache.Options struct can be optionally provided to configure. +func Cacher(options ...Options) macaron.Handler { + opt := prepareOptions(options) + cache, err := NewCacher(opt.Adapter, opt) + if err != nil { + panic(err) + } + return func(ctx *macaron.Context) { + ctx.Map(cache) + } +} + +var adapters = make(map[string]Cache) + +// Register registers a adapter. +func Register(name string, adapter Cache) { + if adapter == nil { + panic("cache: cannot register adapter with nil value") + } + if _, dup := adapters[name]; dup { + panic(fmt.Errorf("cache: cannot register adapter '%s' twice", name)) + } + adapters[name] = adapter +} diff --git a/vendor/gitea.com/macaron/cache/file.go b/vendor/gitea.com/macaron/cache/file.go new file mode 100644 index 0000000000000..8cbfaa10b58a2 --- /dev/null +++ b/vendor/gitea.com/macaron/cache/file.go @@ -0,0 +1,208 @@ +// Copyright 2013 Beego Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package cache + +import ( + "crypto/md5" + "encoding/hex" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "sync" + "time" + + "github.com/Unknwon/com" + "gopkg.in/macaron.v1" +) + +// Item represents a cache item. +type Item struct { + Val interface{} + Created int64 + Expire int64 +} + +func (item *Item) hasExpired() bool { + return item.Expire > 0 && + (time.Now().Unix()-item.Created) >= item.Expire +} + +// FileCacher represents a file cache adapter implementation. +type FileCacher struct { + lock sync.Mutex + rootPath string + interval int // GC interval. +} + +// NewFileCacher creates and returns a new file cacher. +func NewFileCacher() *FileCacher { + return &FileCacher{} +} + +func (c *FileCacher) filepath(key string) string { + m := md5.Sum([]byte(key)) + hash := hex.EncodeToString(m[:]) + return filepath.Join(c.rootPath, string(hash[0]), string(hash[1]), hash) +} + +// Put puts value into cache with key and expire time. +// If expired is 0, it will be deleted by next GC operation. +func (c *FileCacher) Put(key string, val interface{}, expire int64) error { + filename := c.filepath(key) + item := &Item{val, time.Now().Unix(), expire} + data, err := EncodeGob(item) + if err != nil { + return err + } + + os.MkdirAll(filepath.Dir(filename), os.ModePerm) + return ioutil.WriteFile(filename, data, os.ModePerm) +} + +func (c *FileCacher) read(key string) (*Item, error) { + filename := c.filepath(key) + + data, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + + item := new(Item) + return item, DecodeGob(data, item) +} + +// Get gets cached value by given key. +func (c *FileCacher) Get(key string) interface{} { + item, err := c.read(key) + if err != nil { + return nil + } + + if item.hasExpired() { + os.Remove(c.filepath(key)) + return nil + } + return item.Val +} + +// Delete deletes cached value by given key. +func (c *FileCacher) Delete(key string) error { + return os.Remove(c.filepath(key)) +} + +// Incr increases cached int-type value by given key as a counter. +func (c *FileCacher) Incr(key string) error { + item, err := c.read(key) + if err != nil { + return err + } + + item.Val, err = Incr(item.Val) + if err != nil { + return err + } + + return c.Put(key, item.Val, item.Expire) +} + +// Decrease cached int value. +func (c *FileCacher) Decr(key string) error { + item, err := c.read(key) + if err != nil { + return err + } + + item.Val, err = Decr(item.Val) + if err != nil { + return err + } + + return c.Put(key, item.Val, item.Expire) +} + +// IsExist returns true if cached value exists. +func (c *FileCacher) IsExist(key string) bool { + return com.IsExist(c.filepath(key)) +} + +// Flush deletes all cached data. +func (c *FileCacher) Flush() error { + return os.RemoveAll(c.rootPath) +} + +func (c *FileCacher) startGC() { + c.lock.Lock() + defer c.lock.Unlock() + + if c.interval < 1 { + return + } + + if err := filepath.Walk(c.rootPath, func(path string, fi os.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("Walk: %v", err) + } + + if fi.IsDir() { + return nil + } + + data, err := ioutil.ReadFile(path) + if err != nil && !os.IsNotExist(err) { + fmt.Errorf("ReadFile: %v", err) + } + + item := new(Item) + if err = DecodeGob(data, item); err != nil { + return err + } + if item.hasExpired() { + if err = os.Remove(path); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("Remove: %v", err) + } + } + return nil + }); err != nil { + log.Printf("error garbage collecting cache files: %v", err) + } + + time.AfterFunc(time.Duration(c.interval)*time.Second, func() { c.startGC() }) +} + +// StartAndGC starts GC routine based on config string settings. +func (c *FileCacher) StartAndGC(opt Options) error { + c.lock.Lock() + c.rootPath = opt.AdapterConfig + c.interval = opt.Interval + + if !filepath.IsAbs(c.rootPath) { + c.rootPath = filepath.Join(macaron.Root, c.rootPath) + } + c.lock.Unlock() + + if err := os.MkdirAll(c.rootPath, os.ModePerm); err != nil { + return err + } + + go c.startGC() + return nil +} + +func init() { + Register("file", NewFileCacher()) +} diff --git a/vendor/gitea.com/macaron/cache/go.mod b/vendor/gitea.com/macaron/cache/go.mod new file mode 100644 index 0000000000000..1be435a23be10 --- /dev/null +++ b/vendor/gitea.com/macaron/cache/go.mod @@ -0,0 +1,32 @@ +module gitea.com/macaron/cache + +go 1.11 + +require ( + github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 + github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 + github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 // indirect + github.com/edsrzf/mmap-go v1.0.0 // indirect + github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 // indirect + github.com/go-redis/redis v6.15.2+incompatible + github.com/go-sql-driver/mysql v1.4.1 + github.com/lib/pq v1.2.0 + github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de // indirect + github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af + github.com/mattn/go-sqlite3 v1.11.0 // indirect + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect + github.com/pelletier/go-toml v1.4.0 // indirect + github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect + github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d // indirect + github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 + github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d // indirect + github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 + github.com/syndtr/goleveldb v1.0.0 // indirect + golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect + golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect + golang.org/x/sys v0.0.0-20190730183949-1393eb018365 // indirect + google.golang.org/appengine v1.6.1 // indirect + gopkg.in/ini.v1 v1.44.0 + gopkg.in/macaron.v1 v1.3.2 +) diff --git a/vendor/gitea.com/macaron/cache/go.sum b/vendor/gitea.com/macaron/cache/go.sum new file mode 100644 index 0000000000000..706a81c4fbcc1 --- /dev/null +++ b/vendor/gitea.com/macaron/cache/go.sum @@ -0,0 +1,105 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 h1:1B7wb36fHLSwZfHg6ngZhhtIEHQjiC5H4p7qQGBEffg= +github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68= +github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= +github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 h1:Lgdd/Qp96Qj8jqLpq2cI1I1X7BJnu06efS+XkhRoLUQ= +github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI= +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw= +github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= +github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de h1:nyxwRdWHAVxpFcDThedEgQ07DbcRc5xgNObtbTp76fk= +github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ= +github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af h1:UaWHNBdukWrSG3DRvHFR/hyfg681fceqQDYVTBncKfQ= +github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0= +github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM= +github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= +github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d h1:qQWKKOvHN7Q9c6GdmUteCef2F9ubxMpxY1IKwpIKz68= +github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= +github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 h1:qvsJwGToa8rxb42cDRhkbKeX2H5N8BH+s2aUikGt8mI= +github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= +github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d h1:NVwnfyR3rENtlz62bcrkXME3INVUa4lcdGt+opvxExs= +github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 h1:N8Bg45zpk/UcpNGnfJt2y/3lRWASHNTUET8owPYCgYI= +github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190730183949-1393eb018365 h1:SaXEMXhWzMJThc05vu6uh61Q245r4KaWMrsTedk0FDc= +golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= +gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/macaron.v1 v1.3.2 h1:AvWIaPmwBUA87/OWzePkoxeaw6YJWDfBt1pDFPBnLf8= +gopkg.in/macaron.v1 v1.3.2/go.mod h1:PrsiawTWAGZs6wFbT5hlr7SQ2Ns9h7cUVtcUu4lQOVo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/go-macaron/cache/memcache/memcache.go b/vendor/gitea.com/macaron/cache/memcache/memcache.go similarity index 98% rename from vendor/github.com/go-macaron/cache/memcache/memcache.go rename to vendor/gitea.com/macaron/cache/memcache/memcache.go index f8a99097f5bf0..041fa8ac340aa 100644 --- a/vendor/github.com/go-macaron/cache/memcache/memcache.go +++ b/vendor/gitea.com/macaron/cache/memcache/memcache.go @@ -21,7 +21,7 @@ import ( "github.com/Unknwon/com" "github.com/bradfitz/gomemcache/memcache" - "github.com/go-macaron/cache" + "gitea.com/macaron/cache" ) // MemcacheCacher represents a memcache cache adapter implementation. diff --git a/vendor/github.com/go-macaron/cache/memcache/memcache.goconvey b/vendor/gitea.com/macaron/cache/memcache/memcache.goconvey similarity index 100% rename from vendor/github.com/go-macaron/cache/memcache/memcache.goconvey rename to vendor/gitea.com/macaron/cache/memcache/memcache.goconvey diff --git a/vendor/gitea.com/macaron/cache/memory.go b/vendor/gitea.com/macaron/cache/memory.go new file mode 100644 index 0000000000000..2d5a8fac4daa3 --- /dev/null +++ b/vendor/gitea.com/macaron/cache/memory.go @@ -0,0 +1,179 @@ +// Copyright 2013 Beego Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package cache + +import ( + "errors" + "sync" + "time" +) + +// MemoryItem represents a memory cache item. +type MemoryItem struct { + val interface{} + created int64 + expire int64 +} + +func (item *MemoryItem) hasExpired() bool { + return item.expire > 0 && + (time.Now().Unix()-item.created) >= item.expire +} + +// MemoryCacher represents a memory cache adapter implementation. +type MemoryCacher struct { + lock sync.RWMutex + items map[string]*MemoryItem + interval int // GC interval. +} + +// NewMemoryCacher creates and returns a new memory cacher. +func NewMemoryCacher() *MemoryCacher { + return &MemoryCacher{items: make(map[string]*MemoryItem)} +} + +// Put puts value into cache with key and expire time. +// If expired is 0, it will be deleted by next GC operation. +func (c *MemoryCacher) Put(key string, val interface{}, expire int64) error { + c.lock.Lock() + defer c.lock.Unlock() + + c.items[key] = &MemoryItem{ + val: val, + created: time.Now().Unix(), + expire: expire, + } + return nil +} + +// Get gets cached value by given key. +func (c *MemoryCacher) Get(key string) interface{} { + c.lock.RLock() + defer c.lock.RUnlock() + + item, ok := c.items[key] + if !ok { + return nil + } + if item.hasExpired() { + go c.Delete(key) + return nil + } + return item.val +} + +// Delete deletes cached value by given key. +func (c *MemoryCacher) Delete(key string) error { + c.lock.Lock() + defer c.lock.Unlock() + + delete(c.items, key) + return nil +} + +// Incr increases cached int-type value by given key as a counter. +func (c *MemoryCacher) Incr(key string) (err error) { + c.lock.RLock() + defer c.lock.RUnlock() + + item, ok := c.items[key] + if !ok { + return errors.New("key not exist") + } + item.val, err = Incr(item.val) + return err +} + +// Decr decreases cached int-type value by given key as a counter. +func (c *MemoryCacher) Decr(key string) (err error) { + c.lock.RLock() + defer c.lock.RUnlock() + + item, ok := c.items[key] + if !ok { + return errors.New("key not exist") + } + + item.val, err = Decr(item.val) + return err +} + +// IsExist returns true if cached value exists. +func (c *MemoryCacher) IsExist(key string) bool { + c.lock.RLock() + defer c.lock.RUnlock() + + _, ok := c.items[key] + return ok +} + +// Flush deletes all cached data. +func (c *MemoryCacher) Flush() error { + c.lock.Lock() + defer c.lock.Unlock() + + c.items = make(map[string]*MemoryItem) + return nil +} + +func (c *MemoryCacher) checkRawExpiration(key string) { + item, ok := c.items[key] + if !ok { + return + } + + if item.hasExpired() { + delete(c.items, key) + } +} + +func (c *MemoryCacher) checkExpiration(key string) { + c.lock.Lock() + defer c.lock.Unlock() + + c.checkRawExpiration(key) +} + +func (c *MemoryCacher) startGC() { + c.lock.Lock() + defer c.lock.Unlock() + + if c.interval < 1 { + return + } + + if c.items != nil { + for key, _ := range c.items { + c.checkRawExpiration(key) + } + } + + time.AfterFunc(time.Duration(c.interval)*time.Second, func() { c.startGC() }) +} + +// StartAndGC starts GC routine based on config string settings. +func (c *MemoryCacher) StartAndGC(opt Options) error { + c.lock.Lock() + c.interval = opt.Interval + c.lock.Unlock() + + go c.startGC() + return nil +} + +func init() { + Register("memory", NewMemoryCacher()) +} diff --git a/vendor/github.com/go-macaron/cache/redis/redis.go b/vendor/gitea.com/macaron/cache/redis/redis.go similarity index 93% rename from vendor/github.com/go-macaron/cache/redis/redis.go rename to vendor/gitea.com/macaron/cache/redis/redis.go index 5b59fbd2927b1..66466b165eaa6 100644 --- a/vendor/github.com/go-macaron/cache/redis/redis.go +++ b/vendor/gitea.com/macaron/cache/redis/redis.go @@ -21,10 +21,10 @@ import ( "time" "github.com/Unknwon/com" + "github.com/go-redis/redis" "gopkg.in/ini.v1" - "gopkg.in/redis.v2" - "github.com/go-macaron/cache" + "gitea.com/macaron/cache" ) // RedisCacher represents a redis cache adapter implementation. @@ -40,7 +40,7 @@ type RedisCacher struct { func (c *RedisCacher) Put(key string, val interface{}, expire int64) error { key = c.prefix + key if expire == 0 { - if err := c.c.Set(key, com.ToStr(val)).Err(); err != nil { + if err := c.c.Set(key, com.ToStr(val), 0).Err(); err != nil { return err } } else { @@ -48,7 +48,7 @@ func (c *RedisCacher) Put(key string, val interface{}, expire int64) error { if err != nil { return err } - if err = c.c.SetEx(key, dur, com.ToStr(val)).Err(); err != nil { + if err = c.c.Set(key, com.ToStr(val), dur).Err(); err != nil { return err } } @@ -99,7 +99,7 @@ func (c *RedisCacher) Decr(key string) error { // IsExist returns true if cached value exists. func (c *RedisCacher) IsExist(key string) bool { - if c.c.Exists(c.prefix + key).Val() { + if c.c.Exists(c.prefix + key).Val() == 1 { return true } @@ -148,7 +148,7 @@ func (c *RedisCacher) StartAndGC(opts cache.Options) error { case "password": opt.Password = v case "db": - opt.DB = com.StrTo(v).MustInt64() + opt.DB = com.StrTo(v).MustInt() case "pool_size": opt.PoolSize = com.StrTo(v).MustInt() case "idle_timeout": diff --git a/vendor/github.com/go-macaron/cache/redis/redis.goconvey b/vendor/gitea.com/macaron/cache/redis/redis.goconvey similarity index 100% rename from vendor/github.com/go-macaron/cache/redis/redis.goconvey rename to vendor/gitea.com/macaron/cache/redis/redis.goconvey diff --git a/vendor/gitea.com/macaron/cache/utils.go b/vendor/gitea.com/macaron/cache/utils.go new file mode 100644 index 0000000000000..734fb6f40ed50 --- /dev/null +++ b/vendor/gitea.com/macaron/cache/utils.go @@ -0,0 +1,84 @@ +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package cache + +import ( + "bytes" + "encoding/gob" + "errors" +) + +func EncodeGob(item *Item) ([]byte, error) { + buf := bytes.NewBuffer(nil) + err := gob.NewEncoder(buf).Encode(item) + return buf.Bytes(), err +} + +func DecodeGob(data []byte, out *Item) error { + buf := bytes.NewBuffer(data) + return gob.NewDecoder(buf).Decode(&out) +} + +func Incr(val interface{}) (interface{}, error) { + switch val.(type) { + case int: + val = val.(int) + 1 + case int32: + val = val.(int32) + 1 + case int64: + val = val.(int64) + 1 + case uint: + val = val.(uint) + 1 + case uint32: + val = val.(uint32) + 1 + case uint64: + val = val.(uint64) + 1 + default: + return val, errors.New("item value is not int-type") + } + return val, nil +} + +func Decr(val interface{}) (interface{}, error) { + switch val.(type) { + case int: + val = val.(int) - 1 + case int32: + val = val.(int32) - 1 + case int64: + val = val.(int64) - 1 + case uint: + if val.(uint) > 0 { + val = val.(uint) - 1 + } else { + return val, errors.New("item value is less than 0") + } + case uint32: + if val.(uint32) > 0 { + val = val.(uint32) - 1 + } else { + return val, errors.New("item value is less than 0") + } + case uint64: + if val.(uint64) > 0 { + val = val.(uint64) - 1 + } else { + return val, errors.New("item value is less than 0") + } + default: + return val, errors.New("item value is not int-type") + } + return val, nil +} diff --git a/vendor/gitea.com/macaron/session/.drone.yml b/vendor/gitea.com/macaron/session/.drone.yml new file mode 100644 index 0000000000000..717ada4b8f1b3 --- /dev/null +++ b/vendor/gitea.com/macaron/session/.drone.yml @@ -0,0 +1,11 @@ +kind: pipeline +name: default + +steps: +- name: test + image: golang:1.12 + environment: + GOPROXY: https://goproxy.cn + commands: + - go build -v + - go test -v -race -coverprofile=coverage.txt -covermode=atomic \ No newline at end of file diff --git a/vendor/gitea.com/macaron/session/.gitignore b/vendor/gitea.com/macaron/session/.gitignore new file mode 100644 index 0000000000000..834722925c9ea --- /dev/null +++ b/vendor/gitea.com/macaron/session/.gitignore @@ -0,0 +1,4 @@ +ledis/tmp.db +nodb/tmp.db +/vendor +/.idea diff --git a/vendor/gitea.com/macaron/session/LICENSE b/vendor/gitea.com/macaron/session/LICENSE new file mode 100644 index 0000000000000..8405e89a0b120 --- /dev/null +++ b/vendor/gitea.com/macaron/session/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/vendor/gitea.com/macaron/session/README.md b/vendor/gitea.com/macaron/session/README.md new file mode 100644 index 0000000000000..3f443c7bd874e --- /dev/null +++ b/vendor/gitea.com/macaron/session/README.md @@ -0,0 +1,22 @@ +# session + +Middleware session provides session management for [Macaron](https://github.com/go-macaron/macaron). It can use many session providers, including memory, file, Redis, Memcache, PostgreSQL, MySQL, Couchbase, Ledis and Nodb. + +### Installation + +The minimum requirement of Go is 1.11 . + + go get gitea.com/macaron/session + +## Getting Help + +- [API Reference](https://gowalker.org/gitea.com/macaron/session) +- [Documentation](https://go-macaron.com/docs/middlewares/session) + +## Credits + +This package is a modified version of [go-macaron/session](github.com/go-macaron/session). + +## License + +This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text. \ No newline at end of file diff --git a/vendor/github.com/go-macaron/session/couchbase/couchbase.go b/vendor/gitea.com/macaron/session/couchbase/couchbase.go similarity index 99% rename from vendor/github.com/go-macaron/session/couchbase/couchbase.go rename to vendor/gitea.com/macaron/session/couchbase/couchbase.go index 8001fd15f1e64..b6f671f75ea88 100644 --- a/vendor/github.com/go-macaron/session/couchbase/couchbase.go +++ b/vendor/gitea.com/macaron/session/couchbase/couchbase.go @@ -21,7 +21,7 @@ import ( "github.com/couchbaselabs/go-couchbase" - "github.com/go-macaron/session" + "gitea.com/macaron/session" ) // CouchbaseSessionStore represents a couchbase session store implementation. diff --git a/vendor/gitea.com/macaron/session/file.go b/vendor/gitea.com/macaron/session/file.go new file mode 100644 index 0000000000000..64b47f2b0039a --- /dev/null +++ b/vendor/gitea.com/macaron/session/file.go @@ -0,0 +1,266 @@ +// Copyright 2013 Beego Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package session + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "path" + "path/filepath" + "sync" + "time" + + "github.com/Unknwon/com" +) + +// FileStore represents a file session store implementation. +type FileStore struct { + p *FileProvider + sid string + lock sync.RWMutex + data map[interface{}]interface{} +} + +// NewFileStore creates and returns a file session store. +func NewFileStore(p *FileProvider, sid string, kv map[interface{}]interface{}) *FileStore { + return &FileStore{ + p: p, + sid: sid, + data: kv, + } +} + +// Set sets value to given key in session. +func (s *FileStore) Set(key, val interface{}) error { + s.lock.Lock() + defer s.lock.Unlock() + + s.data[key] = val + return nil +} + +// Get gets value by given key in session. +func (s *FileStore) Get(key interface{}) interface{} { + s.lock.RLock() + defer s.lock.RUnlock() + + return s.data[key] +} + +// Delete delete a key from session. +func (s *FileStore) Delete(key interface{}) error { + s.lock.Lock() + defer s.lock.Unlock() + + delete(s.data, key) + return nil +} + +// ID returns current session ID. +func (s *FileStore) ID() string { + return s.sid +} + +// Release releases resource and save data to provider. +func (s *FileStore) Release() error { + s.p.lock.Lock() + defer s.p.lock.Unlock() + + // Skip encoding if the data is empty + if len(s.data) == 0 { + return nil + } + + data, err := EncodeGob(s.data) + if err != nil { + return err + } + + return ioutil.WriteFile(s.p.filepath(s.sid), data, 0600) +} + +// Flush deletes all session data. +func (s *FileStore) Flush() error { + s.lock.Lock() + defer s.lock.Unlock() + + s.data = make(map[interface{}]interface{}) + return nil +} + +// FileProvider represents a file session provider implementation. +type FileProvider struct { + lock sync.RWMutex + maxlifetime int64 + rootPath string +} + +// Init initializes file session provider with given root path. +func (p *FileProvider) Init(maxlifetime int64, rootPath string) error { + p.lock.Lock() + p.maxlifetime = maxlifetime + p.rootPath = rootPath + p.lock.Unlock() + return nil +} + +func (p *FileProvider) filepath(sid string) string { + return path.Join(p.rootPath, string(sid[0]), string(sid[1]), sid) +} + +// Read returns raw session store by session ID. +func (p *FileProvider) Read(sid string) (_ RawStore, err error) { + filename := p.filepath(sid) + if err = os.MkdirAll(path.Dir(filename), 0700); err != nil { + return nil, err + } + p.lock.RLock() + defer p.lock.RUnlock() + + var f *os.File + if com.IsFile(filename) { + f, err = os.OpenFile(filename, os.O_RDONLY, 0600) + } else { + f, err = os.Create(filename) + } + if err != nil { + return nil, err + } + defer f.Close() + + if err = os.Chtimes(filename, time.Now(), time.Now()); err != nil { + return nil, err + } + + var kv map[interface{}]interface{} + data, err := ioutil.ReadAll(f) + if err != nil { + return nil, err + } + if len(data) == 0 { + kv = make(map[interface{}]interface{}) + } else { + kv, err = DecodeGob(data) + if err != nil { + return nil, err + } + } + return NewFileStore(p, sid, kv), nil +} + +// Exist returns true if session with given ID exists. +func (p *FileProvider) Exist(sid string) bool { + p.lock.RLock() + defer p.lock.RUnlock() + return com.IsFile(p.filepath(sid)) +} + +// Destory deletes a session by session ID. +func (p *FileProvider) Destory(sid string) error { + p.lock.Lock() + defer p.lock.Unlock() + return os.Remove(p.filepath(sid)) +} + +func (p *FileProvider) regenerate(oldsid, sid string) (err error) { + p.lock.Lock() + defer p.lock.Unlock() + + filename := p.filepath(sid) + if com.IsExist(filename) { + return fmt.Errorf("new sid '%s' already exists", sid) + } + + oldname := p.filepath(oldsid) + if !com.IsFile(oldname) { + data, err := EncodeGob(make(map[interface{}]interface{})) + if err != nil { + return err + } + if err = os.MkdirAll(path.Dir(oldname), 0700); err != nil { + return err + } + if err = ioutil.WriteFile(oldname, data, 0600); err != nil { + return err + } + } + + if err = os.MkdirAll(path.Dir(filename), 0700); err != nil { + return err + } + if err = os.Rename(oldname, filename); err != nil { + return err + } + return nil +} + +// Regenerate regenerates a session store from old session ID to new one. +func (p *FileProvider) Regenerate(oldsid, sid string) (_ RawStore, err error) { + if err := p.regenerate(oldsid, sid); err != nil { + return nil, err + } + + return p.Read(sid) +} + +// Count counts and returns number of sessions. +func (p *FileProvider) Count() int { + count := 0 + if err := filepath.Walk(p.rootPath, func(path string, fi os.FileInfo, err error) error { + if err != nil { + return err + } + + if !fi.IsDir() { + count++ + } + return nil + }); err != nil { + log.Printf("error counting session files: %v", err) + return 0 + } + return count +} + +// GC calls GC to clean expired sessions. +func (p *FileProvider) GC() { + p.lock.RLock() + defer p.lock.RUnlock() + + if !com.IsExist(p.rootPath) { + return + } + + if err := filepath.Walk(p.rootPath, func(path string, fi os.FileInfo, err error) error { + if err != nil { + return err + } + + if !fi.IsDir() && + (fi.ModTime().Unix()+p.maxlifetime) < time.Now().Unix() { + return os.Remove(path) + } + return nil + }); err != nil { + log.Printf("error garbage collecting session files: %v", err) + } +} + +func init() { + Register("file", &FileProvider{}) +} diff --git a/vendor/gitea.com/macaron/session/flash.go b/vendor/gitea.com/macaron/session/flash.go new file mode 100644 index 0000000000000..99aae71e224eb --- /dev/null +++ b/vendor/gitea.com/macaron/session/flash.go @@ -0,0 +1,61 @@ +// Copyright 2018 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package session + +import ( + "net/url" + + "gopkg.in/macaron.v1" +) + +type Flash struct { + ctx *macaron.Context + url.Values + ErrorMsg, WarningMsg, InfoMsg, SuccessMsg string +} + +func (f *Flash) set(name, msg string, current ...bool) { + isShow := false + if (len(current) == 0 && macaron.FlashNow) || + (len(current) > 0 && current[0]) { + isShow = true + } + + if isShow { + f.ctx.Data["Flash"] = f + } else { + f.Set(name, msg) + } +} + +func (f *Flash) Error(msg string, current ...bool) { + f.ErrorMsg = msg + f.set("error", msg, current...) +} + +func (f *Flash) Warning(msg string, current ...bool) { + f.WarningMsg = msg + f.set("warning", msg, current...) +} + +func (f *Flash) Info(msg string, current ...bool) { + f.InfoMsg = msg + f.set("info", msg, current...) +} + +func (f *Flash) Success(msg string, current ...bool) { + f.SuccessMsg = msg + f.set("success", msg, current...) +} diff --git a/vendor/gitea.com/macaron/session/go.mod b/vendor/gitea.com/macaron/session/go.mod new file mode 100644 index 0000000000000..cfa4aaf75b3c0 --- /dev/null +++ b/vendor/gitea.com/macaron/session/go.mod @@ -0,0 +1,34 @@ +module gitea.com/macaron/session + +go 1.11 + +require ( + github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 + github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 + github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d // indirect + github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b // indirect + github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7 + github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 // indirect + github.com/edsrzf/mmap-go v1.0.0 // indirect + github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 // indirect + github.com/go-redis/redis v6.15.2+incompatible + github.com/go-sql-driver/mysql v1.4.1 + github.com/lib/pq v1.2.0 + github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de // indirect + github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af + github.com/mattn/go-sqlite3 v1.11.0 // indirect + github.com/pelletier/go-toml v1.4.0 // indirect + github.com/pkg/errors v0.8.1 // indirect + github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect + github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d // indirect + github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 + github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d // indirect + github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 + github.com/stretchr/testify v1.3.0 // indirect + github.com/syndtr/goleveldb v1.0.0 // indirect + golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect + golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect + google.golang.org/appengine v1.6.1 // indirect + gopkg.in/ini.v1 v1.44.0 + gopkg.in/macaron.v1 v1.3.2 +) diff --git a/vendor/gitea.com/macaron/session/go.sum b/vendor/gitea.com/macaron/session/go.sum new file mode 100644 index 0000000000000..b748c9fc01156 --- /dev/null +++ b/vendor/gitea.com/macaron/session/go.sum @@ -0,0 +1,116 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 h1:1B7wb36fHLSwZfHg6ngZhhtIEHQjiC5H4p7qQGBEffg= +github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68= +github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= +github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d h1:XMf4E1U+b9E3ElF0mjvfXZdflBRZz4gLp16nQ/QSHQM= +github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= +github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b h1:bZ9rKU2/V8sY+NulSfxDOnXTWcs1rySqdF1sVepihvo= +github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= +github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7 h1:1XjEY/gnjQ+AfXef2U6dxCquhiRzkEpxZuWqs+QxTL8= +github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7/go.mod h1:mby/05p8HE5yHEAKiIH/555NoblMs7PtW6NrYshDruc= +github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 h1:Lgdd/Qp96Qj8jqLpq2cI1I1X7BJnu06efS+XkhRoLUQ= +github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI= +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw= +github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= +github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de h1:nyxwRdWHAVxpFcDThedEgQ07DbcRc5xgNObtbTp76fk= +github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ= +github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af h1:UaWHNBdukWrSG3DRvHFR/hyfg681fceqQDYVTBncKfQ= +github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0= +github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM= +github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= +github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d h1:qQWKKOvHN7Q9c6GdmUteCef2F9ubxMpxY1IKwpIKz68= +github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= +github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 h1:qvsJwGToa8rxb42cDRhkbKeX2H5N8BH+s2aUikGt8mI= +github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= +github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d h1:NVwnfyR3rENtlz62bcrkXME3INVUa4lcdGt+opvxExs= +github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 h1:N8Bg45zpk/UcpNGnfJt2y/3lRWASHNTUET8owPYCgYI= +github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c h1:+EXw7AwNOKzPFXMZ1yNjO40aWCh3PIquJB2fYlv9wcs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= +gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/macaron.v1 v1.3.2 h1:AvWIaPmwBUA87/OWzePkoxeaw6YJWDfBt1pDFPBnLf8= +gopkg.in/macaron.v1 v1.3.2/go.mod h1:PrsiawTWAGZs6wFbT5hlr7SQ2Ns9h7cUVtcUu4lQOVo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/go-macaron/session/memcache/memcache.go b/vendor/gitea.com/macaron/session/memcache/memcache.go similarity index 99% rename from vendor/github.com/go-macaron/session/memcache/memcache.go rename to vendor/gitea.com/macaron/session/memcache/memcache.go index 496939398b0cd..43d94846365f7 100644 --- a/vendor/github.com/go-macaron/session/memcache/memcache.go +++ b/vendor/gitea.com/macaron/session/memcache/memcache.go @@ -22,7 +22,7 @@ import ( "github.com/bradfitz/gomemcache/memcache" - "github.com/go-macaron/session" + "gitea.com/macaron/session" ) // MemcacheStore represents a memcache session store implementation. diff --git a/vendor/github.com/go-macaron/session/memcache/memcache.goconvey b/vendor/gitea.com/macaron/session/memcache/memcache.goconvey similarity index 100% rename from vendor/github.com/go-macaron/session/memcache/memcache.goconvey rename to vendor/gitea.com/macaron/session/memcache/memcache.goconvey diff --git a/vendor/gitea.com/macaron/session/memory.go b/vendor/gitea.com/macaron/session/memory.go new file mode 100644 index 0000000000000..4ad929352e942 --- /dev/null +++ b/vendor/gitea.com/macaron/session/memory.go @@ -0,0 +1,217 @@ +// Copyright 2013 Beego Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package session + +import ( + "container/list" + "fmt" + "sync" + "time" +) + +// MemStore represents a in-memory session store implementation. +type MemStore struct { + sid string + lock sync.RWMutex + data map[interface{}]interface{} + lastAccess time.Time +} + +// NewMemStore creates and returns a memory session store. +func NewMemStore(sid string) *MemStore { + return &MemStore{ + sid: sid, + data: make(map[interface{}]interface{}), + lastAccess: time.Now(), + } +} + +// Set sets value to given key in session. +func (s *MemStore) Set(key, val interface{}) error { + s.lock.Lock() + defer s.lock.Unlock() + + s.data[key] = val + return nil +} + +// Get gets value by given key in session. +func (s *MemStore) Get(key interface{}) interface{} { + s.lock.RLock() + defer s.lock.RUnlock() + + return s.data[key] +} + +// Delete deletes a key from session. +func (s *MemStore) Delete(key interface{}) error { + s.lock.Lock() + defer s.lock.Unlock() + + delete(s.data, key) + return nil +} + +// ID returns current session ID. +func (s *MemStore) ID() string { + return s.sid +} + +// Release releases resource and save data to provider. +func (_ *MemStore) Release() error { + return nil +} + +// Flush deletes all session data. +func (s *MemStore) Flush() error { + s.lock.Lock() + defer s.lock.Unlock() + + s.data = make(map[interface{}]interface{}) + return nil +} + +// MemProvider represents a in-memory session provider implementation. +type MemProvider struct { + lock sync.RWMutex + maxLifetime int64 + data map[string]*list.Element + // A priority list whose lastAccess newer gets higer priority. + list *list.List +} + +// Init initializes memory session provider. +func (p *MemProvider) Init(maxLifetime int64, _ string) error { + p.lock.Lock() + p.maxLifetime = maxLifetime + p.lock.Unlock() + return nil +} + +// update expands time of session store by given ID. +func (p *MemProvider) update(sid string) error { + p.lock.Lock() + defer p.lock.Unlock() + + if e, ok := p.data[sid]; ok { + e.Value.(*MemStore).lastAccess = time.Now() + p.list.MoveToFront(e) + return nil + } + return nil +} + +// Read returns raw session store by session ID. +func (p *MemProvider) Read(sid string) (_ RawStore, err error) { + p.lock.RLock() + e, ok := p.data[sid] + p.lock.RUnlock() + + if ok { + if err = p.update(sid); err != nil { + return nil, err + } + return e.Value.(*MemStore), nil + } + + // Create a new session. + p.lock.Lock() + defer p.lock.Unlock() + + s := NewMemStore(sid) + p.data[sid] = p.list.PushBack(s) + return s, nil +} + +// Exist returns true if session with given ID exists. +func (p *MemProvider) Exist(sid string) bool { + p.lock.RLock() + defer p.lock.RUnlock() + + _, ok := p.data[sid] + return ok +} + +// Destory deletes a session by session ID. +func (p *MemProvider) Destory(sid string) error { + p.lock.Lock() + defer p.lock.Unlock() + + e, ok := p.data[sid] + if !ok { + return nil + } + + p.list.Remove(e) + delete(p.data, sid) + return nil +} + +// Regenerate regenerates a session store from old session ID to new one. +func (p *MemProvider) Regenerate(oldsid, sid string) (RawStore, error) { + if p.Exist(sid) { + return nil, fmt.Errorf("new sid '%s' already exists", sid) + } + + s, err := p.Read(oldsid) + if err != nil { + return nil, err + } + + if err = p.Destory(oldsid); err != nil { + return nil, err + } + + s.(*MemStore).sid = sid + + p.lock.Lock() + defer p.lock.Unlock() + p.data[sid] = p.list.PushBack(s) + return s, nil +} + +// Count counts and returns number of sessions. +func (p *MemProvider) Count() int { + return p.list.Len() +} + +// GC calls GC to clean expired sessions. +func (p *MemProvider) GC() { + p.lock.RLock() + for { + // No session in the list. + e := p.list.Back() + if e == nil { + break + } + + if (e.Value.(*MemStore).lastAccess.Unix() + p.maxLifetime) < time.Now().Unix() { + p.lock.RUnlock() + p.lock.Lock() + p.list.Remove(e) + delete(p.data, e.Value.(*MemStore).sid) + p.lock.Unlock() + p.lock.RLock() + } else { + break + } + } + p.lock.RUnlock() +} + +func init() { + Register("memory", &MemProvider{list: list.New(), data: make(map[string]*list.Element)}) +} diff --git a/vendor/github.com/go-macaron/session/mysql/mysql.go b/vendor/gitea.com/macaron/session/mysql/mysql.go similarity index 99% rename from vendor/github.com/go-macaron/session/mysql/mysql.go rename to vendor/gitea.com/macaron/session/mysql/mysql.go index 7bde37445e46a..58f1abff94d67 100644 --- a/vendor/github.com/go-macaron/session/mysql/mysql.go +++ b/vendor/gitea.com/macaron/session/mysql/mysql.go @@ -24,7 +24,7 @@ import ( _ "github.com/go-sql-driver/mysql" - "github.com/go-macaron/session" + "gitea.com/macaron/session" ) // MysqlStore represents a mysql session store implementation. diff --git a/vendor/github.com/go-macaron/session/mysql/mysql.goconvey b/vendor/gitea.com/macaron/session/mysql/mysql.goconvey similarity index 100% rename from vendor/github.com/go-macaron/session/mysql/mysql.goconvey rename to vendor/gitea.com/macaron/session/mysql/mysql.goconvey diff --git a/vendor/github.com/go-macaron/session/nodb/nodb.go b/vendor/gitea.com/macaron/session/nodb/nodb.go similarity index 99% rename from vendor/github.com/go-macaron/session/nodb/nodb.go rename to vendor/gitea.com/macaron/session/nodb/nodb.go index 8b5a7116933de..cdd29bcc67e6e 100644 --- a/vendor/github.com/go-macaron/session/nodb/nodb.go +++ b/vendor/gitea.com/macaron/session/nodb/nodb.go @@ -21,7 +21,7 @@ import ( "github.com/lunny/nodb" "github.com/lunny/nodb/config" - "github.com/go-macaron/session" + "gitea.com/macaron/session" ) // NodbStore represents a nodb session store implementation. diff --git a/vendor/github.com/go-macaron/session/nodb/nodb.goconvey b/vendor/gitea.com/macaron/session/nodb/nodb.goconvey similarity index 100% rename from vendor/github.com/go-macaron/session/nodb/nodb.goconvey rename to vendor/gitea.com/macaron/session/nodb/nodb.goconvey diff --git a/vendor/github.com/go-macaron/session/postgres/postgres.go b/vendor/gitea.com/macaron/session/postgres/postgres.go similarity index 99% rename from vendor/github.com/go-macaron/session/postgres/postgres.go rename to vendor/gitea.com/macaron/session/postgres/postgres.go index f1e034b501faa..7c3ba035c5fe1 100644 --- a/vendor/github.com/go-macaron/session/postgres/postgres.go +++ b/vendor/gitea.com/macaron/session/postgres/postgres.go @@ -24,7 +24,7 @@ import ( _ "github.com/lib/pq" - "github.com/go-macaron/session" + "gitea.com/macaron/session" ) // PostgresStore represents a postgres session store implementation. diff --git a/vendor/github.com/go-macaron/session/postgres/postgres.goconvey b/vendor/gitea.com/macaron/session/postgres/postgres.goconvey similarity index 100% rename from vendor/github.com/go-macaron/session/postgres/postgres.goconvey rename to vendor/gitea.com/macaron/session/postgres/postgres.goconvey diff --git a/vendor/github.com/go-macaron/session/redis/redis.go b/vendor/gitea.com/macaron/session/redis/redis.go similarity index 93% rename from vendor/github.com/go-macaron/session/redis/redis.go rename to vendor/gitea.com/macaron/session/redis/redis.go index 2d7fe984055d0..f0a5b0c7130aa 100644 --- a/vendor/github.com/go-macaron/session/redis/redis.go +++ b/vendor/gitea.com/macaron/session/redis/redis.go @@ -22,10 +22,10 @@ import ( "time" "github.com/Unknwon/com" + "github.com/go-redis/redis" "gopkg.in/ini.v1" - "gopkg.in/redis.v2" - "github.com/go-macaron/session" + "gitea.com/macaron/session" ) // RedisStore represents a redis session store implementation. @@ -91,7 +91,7 @@ func (s *RedisStore) Release() error { return err } - return s.c.SetEx(s.prefix+s.sid, s.duration, string(data)).Err() + return s.c.Set(s.prefix+s.sid, string(data), s.duration).Err() } // Flush deletes all session data. @@ -135,7 +135,7 @@ func (p *RedisProvider) Init(maxlifetime int64, configs string) (err error) { case "password": opt.Password = v case "db": - opt.DB = com.StrTo(v).MustInt64() + opt.DB = com.StrTo(v).MustInt() case "pool_size": opt.PoolSize = com.StrTo(v).MustInt() case "idle_timeout": @@ -158,7 +158,7 @@ func (p *RedisProvider) Init(maxlifetime int64, configs string) (err error) { func (p *RedisProvider) Read(sid string) (session.RawStore, error) { psid := p.prefix + sid if !p.Exist(sid) { - if err := p.c.SetEx(psid, p.duration, "").Err(); err != nil { + if err := p.c.Set(psid, "", p.duration).Err(); err != nil { return nil, err } } @@ -182,8 +182,8 @@ func (p *RedisProvider) Read(sid string) (session.RawStore, error) { // Exist returns true if session with given ID exists. func (p *RedisProvider) Exist(sid string) bool { - has, err := p.c.Exists(p.prefix + sid).Result() - return err == nil && has + v, err := p.c.Exists(p.prefix + sid).Result() + return err == nil && v == 1 } // Destory deletes a session by session ID. @@ -200,7 +200,7 @@ func (p *RedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err return nil, fmt.Errorf("new sid '%s' already exists", sid) } else if !p.Exist(oldsid) { // Make a fake old session. - if err = p.c.SetEx(poldsid, p.duration, "").Err(); err != nil { + if err = p.c.Set(poldsid, "", p.duration).Err(); err != nil { return nil, err } } diff --git a/vendor/github.com/go-macaron/session/redis/redis.goconvey b/vendor/gitea.com/macaron/session/redis/redis.goconvey similarity index 100% rename from vendor/github.com/go-macaron/session/redis/redis.goconvey rename to vendor/gitea.com/macaron/session/redis/redis.goconvey diff --git a/vendor/gitea.com/macaron/session/session.go b/vendor/gitea.com/macaron/session/session.go new file mode 100644 index 0000000000000..97fa56ede60fc --- /dev/null +++ b/vendor/gitea.com/macaron/session/session.go @@ -0,0 +1,393 @@ +// Copyright 2013 Beego Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +// Package session a middleware that provides the session management of Macaron. +package session + +import ( + "encoding/hex" + "errors" + "fmt" + "net/http" + "net/url" + "time" + + "gopkg.in/macaron.v1" +) + +const _VERSION = "0.6.0" + +func Version() string { + return _VERSION +} + +// RawStore is the interface that operates the session data. +type RawStore interface { + // Set sets value to given key in session. + Set(interface{}, interface{}) error + // Get gets value by given key in session. + Get(interface{}) interface{} + // Delete deletes a key from session. + Delete(interface{}) error + // ID returns current session ID. + ID() string + // Release releases session resource and save data to provider. + Release() error + // Flush deletes all session data. + Flush() error +} + +// Store is the interface that contains all data for one session process with specific ID. +type Store interface { + RawStore + // Read returns raw session store by session ID. + Read(string) (RawStore, error) + // Destory deletes a session. + Destory(*macaron.Context) error + // RegenerateId regenerates a session store from old session ID to new one. + RegenerateId(*macaron.Context) (RawStore, error) + // Count counts and returns number of sessions. + Count() int + // GC calls GC to clean expired sessions. + GC() +} + +type store struct { + RawStore + *Manager +} + +var _ Store = &store{} + +// Options represents a struct for specifying configuration options for the session middleware. +type Options struct { + // Name of provider. Default is "memory". + Provider string + // Provider configuration, it's corresponding to provider. + ProviderConfig string + // Cookie name to save session ID. Default is "MacaronSession". + CookieName string + // Cookie path to store. Default is "/". + CookiePath string + // GC interval time in seconds. Default is 3600. + Gclifetime int64 + // Max life time in seconds. Default is whatever GC interval time is. + Maxlifetime int64 + // Use HTTPS only. Default is false. + Secure bool + // Cookie life time. Default is 0. + CookieLifeTime int + // Cookie domain name. Default is empty. + Domain string + // Session ID length. Default is 16. + IDLength int + // Configuration section name. Default is "session". + Section string + // Ignore release for websocket. Default is false. + IgnoreReleaseForWebSocket bool +} + +func prepareOptions(options []Options) Options { + var opt Options + if len(options) > 0 { + opt = options[0] + } + if len(opt.Section) == 0 { + opt.Section = "session" + } + sec := macaron.Config().Section(opt.Section) + + if len(opt.Provider) == 0 { + opt.Provider = sec.Key("PROVIDER").MustString("memory") + } + if len(opt.ProviderConfig) == 0 { + opt.ProviderConfig = sec.Key("PROVIDER_CONFIG").MustString("data/sessions") + } + if len(opt.CookieName) == 0 { + opt.CookieName = sec.Key("COOKIE_NAME").MustString("MacaronSession") + } + if len(opt.CookiePath) == 0 { + opt.CookiePath = sec.Key("COOKIE_PATH").MustString("/") + } + if opt.Gclifetime == 0 { + opt.Gclifetime = sec.Key("GC_INTERVAL_TIME").MustInt64(3600) + } + if opt.Maxlifetime == 0 { + opt.Maxlifetime = sec.Key("MAX_LIFE_TIME").MustInt64(opt.Gclifetime) + } + if !opt.Secure { + opt.Secure = sec.Key("SECURE").MustBool() + } + if opt.CookieLifeTime == 0 { + opt.CookieLifeTime = sec.Key("COOKIE_LIFE_TIME").MustInt() + } + if len(opt.Domain) == 0 { + opt.Domain = sec.Key("DOMAIN").String() + } + if opt.IDLength == 0 { + opt.IDLength = sec.Key("ID_LENGTH").MustInt(16) + } + if !opt.IgnoreReleaseForWebSocket { + opt.IgnoreReleaseForWebSocket = sec.Key("IGNORE_RELEASE_FOR_WEBSOCKET").MustBool() + } + + return opt +} + +// Sessioner is a middleware that maps a session.SessionStore service into the Macaron handler chain. +// An single variadic session.Options struct can be optionally provided to configure. +func Sessioner(options ...Options) macaron.Handler { + opt := prepareOptions(options) + manager, err := NewManager(opt.Provider, opt) + if err != nil { + panic(err) + } + go manager.startGC() + + return func(ctx *macaron.Context) { + sess, err := manager.Start(ctx) + if err != nil { + panic("session(start): " + err.Error()) + } + + // Get flash. + vals, _ := url.ParseQuery(ctx.GetCookie("macaron_flash")) + if len(vals) > 0 { + f := &Flash{Values: vals} + f.ErrorMsg = f.Get("error") + f.SuccessMsg = f.Get("success") + f.InfoMsg = f.Get("info") + f.WarningMsg = f.Get("warning") + ctx.Data["Flash"] = f + ctx.SetCookie("macaron_flash", "", -1, opt.CookiePath) + } + + f := &Flash{ctx, url.Values{}, "", "", "", ""} + ctx.Resp.Before(func(macaron.ResponseWriter) { + if flash := f.Encode(); len(flash) > 0 { + ctx.SetCookie("macaron_flash", flash, 0, opt.CookiePath) + } + }) + + ctx.Map(f) + s := store{ + RawStore: sess, + Manager: manager, + } + + ctx.MapTo(s, (*Store)(nil)) + + ctx.Next() + + if manager.opt.IgnoreReleaseForWebSocket && ctx.Req.Header.Get("Upgrade") == "websocket" { + return + } + + if err = sess.Release(); err != nil { + panic("session(release): " + err.Error()) + } + } +} + +// Provider is the interface that provides session manipulations. +type Provider interface { + // Init initializes session provider. + Init(gclifetime int64, config string) error + // Read returns raw session store by session ID. + Read(sid string) (RawStore, error) + // Exist returns true if session with given ID exists. + Exist(sid string) bool + // Destory deletes a session by session ID. + Destory(sid string) error + // Regenerate regenerates a session store from old session ID to new one. + Regenerate(oldsid, sid string) (RawStore, error) + // Count counts and returns number of sessions. + Count() int + // GC calls GC to clean expired sessions. + GC() +} + +var providers = make(map[string]Provider) + +// Register registers a provider. +func Register(name string, provider Provider) { + if provider == nil { + panic("session: cannot register provider with nil value") + } + if _, dup := providers[name]; dup { + panic(fmt.Errorf("session: cannot register provider '%s' twice", name)) + } + providers[name] = provider +} + +// _____ +// / \ _____ ____ _____ ____ ___________ +// / \ / \\__ \ / \\__ \ / ___\_/ __ \_ __ \ +// / Y \/ __ \| | \/ __ \_/ /_/ > ___/| | \/ +// \____|__ (____ /___| (____ /\___ / \___ >__| +// \/ \/ \/ \//_____/ \/ + +// Manager represents a struct that contains session provider and its configuration. +type Manager struct { + provider Provider + opt Options +} + +// NewManager creates and returns a new session manager by given provider name and configuration. +// It panics when given provider isn't registered. +func NewManager(name string, opt Options) (*Manager, error) { + p, ok := providers[name] + if !ok { + return nil, fmt.Errorf("session: unknown provider '%s'(forgotten import?)", name) + } + return &Manager{p, opt}, p.Init(opt.Maxlifetime, opt.ProviderConfig) +} + +// sessionID generates a new session ID with rand string, unix nano time, remote addr by hash function. +func (m *Manager) sessionID() string { + return hex.EncodeToString(generateRandomKey(m.opt.IDLength / 2)) +} + +// validSessionID tests whether a provided session ID is a valid session ID. +func (m *Manager) validSessionID(sid string) (bool, error) { + if len(sid) != m.opt.IDLength { + return false, errors.New("invalid 'sid': " + sid) + } + + for i := range sid { + switch { + case '0' <= sid[i] && sid[i] <= '9': + case 'a' <= sid[i] && sid[i] <= 'f': + default: + return false, errors.New("invalid 'sid': " + sid) + } + } + return true, nil +} + +// Start starts a session by generating new one +// or retrieve existence one by reading session ID from HTTP request if it's valid. +func (m *Manager) Start(ctx *macaron.Context) (RawStore, error) { + sid := ctx.GetCookie(m.opt.CookieName) + valid, _ := m.validSessionID(sid) + if len(sid) > 0 && valid && m.provider.Exist(sid) { + return m.provider.Read(sid) + } + + sid = m.sessionID() + sess, err := m.provider.Read(sid) + if err != nil { + return nil, err + } + + cookie := &http.Cookie{ + Name: m.opt.CookieName, + Value: sid, + Path: m.opt.CookiePath, + HttpOnly: true, + Secure: m.opt.Secure, + Domain: m.opt.Domain, + } + if m.opt.CookieLifeTime >= 0 { + cookie.MaxAge = m.opt.CookieLifeTime + } + http.SetCookie(ctx.Resp, cookie) + ctx.Req.AddCookie(cookie) + return sess, nil +} + +// Read returns raw session store by session ID. +func (m *Manager) Read(sid string) (RawStore, error) { + // Ensure we're trying to read a valid session ID + if _, err := m.validSessionID(sid); err != nil { + return nil, err + } + + return m.provider.Read(sid) +} + +// Destory deletes a session by given ID. +func (m *Manager) Destory(ctx *macaron.Context) error { + sid := ctx.GetCookie(m.opt.CookieName) + if len(sid) == 0 { + return nil + } + + if _, err := m.validSessionID(sid); err != nil { + return err + } + + if err := m.provider.Destory(sid); err != nil { + return err + } + cookie := &http.Cookie{ + Name: m.opt.CookieName, + Path: m.opt.CookiePath, + HttpOnly: true, + Expires: time.Now(), + MaxAge: -1, + } + http.SetCookie(ctx.Resp, cookie) + return nil +} + +// RegenerateId regenerates a session store from old session ID to new one. +func (m *Manager) RegenerateId(ctx *macaron.Context) (sess RawStore, err error) { + sid := m.sessionID() + oldsid := ctx.GetCookie(m.opt.CookieName) + _, err = m.validSessionID(oldsid) + if err != nil { + return nil, err + } + sess, err = m.provider.Regenerate(oldsid, sid) + if err != nil { + return nil, err + } + cookie := &http.Cookie{ + Name: m.opt.CookieName, + Value: sid, + Path: m.opt.CookiePath, + HttpOnly: true, + Secure: m.opt.Secure, + Domain: m.opt.Domain, + } + if m.opt.CookieLifeTime >= 0 { + cookie.MaxAge = m.opt.CookieLifeTime + } + http.SetCookie(ctx.Resp, cookie) + ctx.Req.AddCookie(cookie) + return sess, nil +} + +// Count counts and returns number of sessions. +func (m *Manager) Count() int { + return m.provider.Count() +} + +// GC starts GC job in a certain period. +func (m *Manager) GC() { + m.provider.GC() +} + +// startGC starts GC job in a certain period. +func (m *Manager) startGC() { + m.GC() + time.AfterFunc(time.Duration(m.opt.Gclifetime)*time.Second, func() { m.startGC() }) +} + +// SetSecure indicates whether to set cookie with HTTPS or not. +func (m *Manager) SetSecure(secure bool) { + m.opt.Secure = secure +} diff --git a/vendor/gitea.com/macaron/session/utils.go b/vendor/gitea.com/macaron/session/utils.go new file mode 100644 index 0000000000000..90ca38064bee8 --- /dev/null +++ b/vendor/gitea.com/macaron/session/utils.go @@ -0,0 +1,63 @@ +// Copyright 2013 Beego Authors +// Copyright 2014 The Macaron Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package session + +import ( + "bytes" + "crypto/rand" + "encoding/gob" + "io" + + "github.com/Unknwon/com" +) + +func init() { + gob.Register([]interface{}{}) + gob.Register(map[int]interface{}{}) + gob.Register(map[string]interface{}{}) + gob.Register(map[interface{}]interface{}{}) + gob.Register(map[string]string{}) + gob.Register(map[int]string{}) + gob.Register(map[int]int{}) + gob.Register(map[int]int64{}) +} + +func EncodeGob(obj map[interface{}]interface{}) ([]byte, error) { + for _, v := range obj { + gob.Register(v) + } + buf := bytes.NewBuffer(nil) + err := gob.NewEncoder(buf).Encode(obj) + return buf.Bytes(), err +} + +func DecodeGob(encoded []byte) (out map[interface{}]interface{}, err error) { + buf := bytes.NewBuffer(encoded) + err = gob.NewDecoder(buf).Decode(&out) + return out, err +} + +// NOTE: A local copy in case of underlying package change +var alphanum = []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") + +// generateRandomKey creates a random key with the given strength. +func generateRandomKey(strength int) []byte { + k := make([]byte, strength) + if n, err := io.ReadFull(rand.Reader, k); n != strength || err != nil { + return com.RandomCreateBytes(strength, alphanum...) + } + return k +} diff --git a/vendor/github.com/bradfitz/gomemcache/memcache/memcache.go b/vendor/github.com/bradfitz/gomemcache/memcache/memcache.go index 7b5442d735ef9..25e88ca261267 100644 --- a/vendor/github.com/bradfitz/gomemcache/memcache/memcache.go +++ b/vendor/github.com/bradfitz/gomemcache/memcache/memcache.go @@ -23,7 +23,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "strconv" @@ -33,7 +32,7 @@ import ( ) // Similar to: -// http://code.google.com/appengine/docs/go/memcache/reference.html +// https://godoc.org/google.golang.org/appengine/memcache var ( // ErrCacheMiss means that a Get failed because the item wasn't present. @@ -56,7 +55,7 @@ var ( ErrNoStats = errors.New("memcache: no statistics available") // ErrMalformedKey is returned when an invalid key is used. - // Keys must be at maximum 250 bytes long, ASCII, and not + // Keys must be at maximum 250 bytes long and not // contain whitespace or control characters. ErrMalformedKey = errors.New("malformed: key is too long or contains invalid characters") @@ -64,14 +63,17 @@ var ( ErrNoServers = errors.New("memcache: no servers configured or available") ) -// DefaultTimeout is the default socket read/write timeout. -const DefaultTimeout = 100 * time.Millisecond - const ( - buffered = 8 // arbitrary buffered channel size, for readability - maxIdleConnsPerAddr = 2 // TODO(bradfitz): make this configurable? + // DefaultTimeout is the default socket read/write timeout. + DefaultTimeout = 100 * time.Millisecond + + // DefaultMaxIdleConns is the default maximum number of idle connections + // kept for any single address. + DefaultMaxIdleConns = 2 ) +const buffered = 8 // arbitrary buffered channel size, for readability + // resumableError returns true if err is only a protocol-level cache error. // This is used to determine whether or not a server connection should // be re-used or not. If an error occurs, by default we don't reuse the @@ -89,7 +91,7 @@ func legalKey(key string) bool { return false } for i := 0; i < len(key); i++ { - if key[i] <= ' ' || key[i] > 0x7e { + if key[i] <= ' ' || key[i] == 0x7f { return false } } @@ -133,6 +135,14 @@ type Client struct { // If zero, DefaultTimeout is used. Timeout time.Duration + // MaxIdleConns specifies the maximum number of idle connections that will + // be maintained per address. If less than one, DefaultMaxIdleConns will be + // used. + // + // Consider your expected traffic rates and latency carefully. This should + // be set to a number higher than your peak parallel requests. + MaxIdleConns int + selector ServerSelector lk sync.Mutex @@ -196,7 +206,7 @@ func (c *Client) putFreeConn(addr net.Addr, cn *conn) { c.freeconn = make(map[string][]*conn) } freelist := c.freeconn[addr.String()] - if len(freelist) >= maxIdleConnsPerAddr { + if len(freelist) >= c.maxIdleConns() { cn.nc.Close() return } @@ -225,6 +235,13 @@ func (c *Client) netTimeout() time.Duration { return DefaultTimeout } +func (c *Client) maxIdleConns() int { + if c.MaxIdleConns > 0 { + return c.MaxIdleConns + } + return DefaultMaxIdleConns +} + // ConnectTimeoutError is the error type used when it takes // too long to connect to the desired host. This level of // detail can generally be ignored. @@ -308,8 +325,9 @@ func (c *Client) Get(key string) (item *Item, err error) { // Touch updates the expiry for the given key. The seconds parameter is either // a Unix timestamp or, if seconds is less than 1 month, the number of seconds -// into the future at which time the item will expire. ErrCacheMiss is returned if the -// key is not in the cache. The key must be at most 250 bytes in length. +// into the future at which time the item will expire. Zero means the item has +// no expiration time. ErrCacheMiss is returned if the key is not in the cache. +// The key must be at most 250 bytes in length. func (c *Client) Touch(key string, seconds int32) (err error) { return c.withKeyAddr(key, func(addr net.Addr) error { return c.touchFromAddr(addr, []string{key}, seconds) @@ -463,11 +481,14 @@ func parseGetResponse(r *bufio.Reader, cb func(*Item)) error { if err != nil { return err } - it.Value, err = ioutil.ReadAll(io.LimitReader(r, int64(size)+2)) + it.Value = make([]byte, size+2) + _, err = io.ReadFull(r, it.Value) if err != nil { + it.Value = nil return err } if !bytes.HasSuffix(it.Value, crlf) { + it.Value = nil return fmt.Errorf("memcache: corrupt get result read") } it.Value = it.Value[:size] diff --git a/vendor/github.com/bradfitz/gomemcache/memcache/selector.go b/vendor/github.com/bradfitz/gomemcache/memcache/selector.go index 10b04d349fe95..89ad81e0d8306 100644 --- a/vendor/github.com/bradfitz/gomemcache/memcache/selector.go +++ b/vendor/github.com/bradfitz/gomemcache/memcache/selector.go @@ -41,6 +41,21 @@ type ServerList struct { addrs []net.Addr } +// staticAddr caches the Network() and String() values from any net.Addr. +type staticAddr struct { + ntw, str string +} + +func newStaticAddr(a net.Addr) net.Addr { + return &staticAddr{ + ntw: a.Network(), + str: a.String(), + } +} + +func (s *staticAddr) Network() string { return s.ntw } +func (s *staticAddr) String() string { return s.str } + // SetServers changes a ServerList's set of servers at runtime and is // safe for concurrent use by multiple goroutines. // @@ -58,13 +73,13 @@ func (ss *ServerList) SetServers(servers ...string) error { if err != nil { return err } - naddr[i] = addr + naddr[i] = newStaticAddr(addr) } else { tcpaddr, err := net.ResolveTCPAddr("tcp", server) if err != nil { return err } - naddr[i] = tcpaddr + naddr[i] = newStaticAddr(tcpaddr) } } diff --git a/vendor/github.com/couchbase/gomemcached/client/mc.go b/vendor/github.com/couchbase/gomemcached/client/mc.go index bd1433ba28fb5..0f1d61e5129c1 100644 --- a/vendor/github.com/couchbase/gomemcached/client/mc.go +++ b/vendor/github.com/couchbase/gomemcached/client/mc.go @@ -2,6 +2,7 @@ package memcached import ( + "crypto/tls" "encoding/binary" "fmt" "github.com/couchbase/gomemcached" @@ -26,11 +27,14 @@ type ClientIface interface { AuthScramSha(user, pass string) (*gomemcached.MCResponse, error) CASNext(vb uint16, k string, exp int, state *CASState) bool CAS(vb uint16, k string, f CasFunc, initexp int) (*gomemcached.MCResponse, error) + CollectionsGetCID(scope string, collection string) (*gomemcached.MCResponse, error) Close() error Decr(vb uint16, key string, amt, def uint64, exp int) (uint64, error) Del(vb uint16, key string) (*gomemcached.MCResponse, error) EnableMutationToken() (*gomemcached.MCResponse, error) Get(vb uint16, key string) (*gomemcached.MCResponse, error) + GetCollectionsManifest() (*gomemcached.MCResponse, error) + GetFromCollection(vb uint16, cid uint32, key string) (*gomemcached.MCResponse, error) GetSubdoc(vb uint16, key string, subPaths []string) (*gomemcached.MCResponse, error) GetAndTouch(vb uint16, key string, exp int) (*gomemcached.MCResponse, error) GetBulk(vb uint16, keys []string, rv map[string]*gomemcached.MCResponse, subPaths []string) error @@ -74,11 +78,19 @@ type Feature uint16 const FeatureMutationToken = Feature(0x04) const FeatureXattr = Feature(0x06) +const FeatureCollections = Feature(0x12) const FeatureDataType = Feature(0x0b) +type memcachedConnection interface { + io.ReadWriteCloser + + SetReadDeadline(time.Time) error + SetDeadline(time.Time) error +} + // The Client itself. type Client struct { - conn io.ReadWriteCloser + conn memcachedConnection // use uint32 type so that it can be accessed through atomic APIs healthy uint32 opaque uint32 @@ -105,6 +117,15 @@ func Connect(prot, dest string) (rv *Client, err error) { return Wrap(conn) } +// Connect to a memcached server using TLS. +func ConnectTLS(prot, dest string, config *tls.Config) (rv *Client, err error) { + conn, err := tls.Dial(prot, dest, config) + if err != nil { + return nil, err + } + return Wrap(conn) +} + func SetDefaultTimeouts(dial, read, write time.Duration) { DefaultDialTimeout = dial DefaultWriteTimeout = write @@ -115,22 +136,25 @@ func SetDefaultDialTimeout(dial time.Duration) { } func (c *Client) SetKeepAliveOptions(interval time.Duration) { - c.conn.(*net.TCPConn).SetKeepAlive(true) - c.conn.(*net.TCPConn).SetKeepAlivePeriod(interval) + tcpConn, ok := c.conn.(*net.TCPConn) + if ok { + tcpConn.SetKeepAlive(true) + tcpConn.SetKeepAlivePeriod(interval) + } } func (c *Client) SetReadDeadline(t time.Time) { - c.conn.(*net.TCPConn).SetReadDeadline(t) + c.conn.SetReadDeadline(t) } func (c *Client) SetDeadline(t time.Time) { - c.conn.(*net.TCPConn).SetDeadline(t) + c.conn.SetDeadline(t) } // Wrap an existing transport. -func Wrap(rwc io.ReadWriteCloser) (rv *Client, err error) { +func Wrap(conn memcachedConnection) (rv *Client, err error) { client := &Client{ - conn: rwc, + conn: conn, hdrBuf: make([]byte, gomemcached.HDR_LEN), opaque: uint32(1), } @@ -278,6 +302,22 @@ func (c *Client) Get(vb uint16, key string) (*gomemcached.MCResponse, error) { }) } +// Get the value for a key from a collection, identified by collection id. +func (c *Client) GetFromCollection(vb uint16, cid uint32, key string) (*gomemcached.MCResponse, error) { + keyBytes := []byte(key) + encodedCid := make([]byte, binary.MaxVarintLen32) + lenEncodedCid := binary.PutUvarint(encodedCid, uint64(cid)) + encodedKey := make([]byte, 0, lenEncodedCid+len(keyBytes)) + encodedKey = append(encodedKey, encodedCid[0:lenEncodedCid]...) + encodedKey = append(encodedKey, keyBytes...) + + return c.Send(&gomemcached.MCRequest{ + Opcode: gomemcached.GET, + VBucket: vb, + Key: encodedKey, + }) +} + // Get the xattrs, doc value for the input key func (c *Client) GetSubdoc(vb uint16, key string, subPaths []string) (*gomemcached.MCResponse, error) { @@ -296,6 +336,33 @@ func (c *Client) GetSubdoc(vb uint16, key string, subPaths []string) (*gomemcach return res, nil } +// Retrieve the collections manifest. +func (c *Client) GetCollectionsManifest() (*gomemcached.MCResponse, error) { + + res, err := c.Send(&gomemcached.MCRequest{ + Opcode: gomemcached.GET_COLLECTIONS_MANIFEST, + }) + + if err != nil && IfResStatusError(res) { + return res, err + } + return res, nil +} + +// Retrieve the collections manifest. +func (c *Client) CollectionsGetCID(scope string, collection string) (*gomemcached.MCResponse, error) { + + res, err := c.Send(&gomemcached.MCRequest{ + Opcode: gomemcached.COLLECTIONS_GET_CID, + Key: []byte(scope + "." + collection), + }) + + if err != nil && IfResStatusError(res) { + return res, err + } + return res, nil +} + // Get the value for a key, and update expiry func (c *Client) GetAndTouch(vb uint16, key string, exp int) (*gomemcached.MCResponse, error) { extraBuf := make([]byte, 4) @@ -425,10 +492,9 @@ func (c *Client) AuthPlain(user, pass string) (*gomemcached.MCResponse, error) { // select bucket func (c *Client) SelectBucket(bucket string) (*gomemcached.MCResponse, error) { - return c.Send(&gomemcached.MCRequest{ Opcode: gomemcached.SELECT_BUCKET, - Key: []byte(fmt.Sprintf("%s", bucket))}) + Key: []byte(bucket)}) } func (c *Client) store(opcode gomemcached.CommandCode, vb uint16, diff --git a/vendor/github.com/couchbase/gomemcached/client/upr_feed.go b/vendor/github.com/couchbase/gomemcached/client/upr_feed.go index dc737e6cc0fd9..95fa12577f315 100644 --- a/vendor/github.com/couchbase/gomemcached/client/upr_feed.go +++ b/vendor/github.com/couchbase/gomemcached/client/upr_feed.go @@ -53,6 +53,16 @@ type UprEvent struct { AckSize uint32 // The number of bytes that can be Acked to DCP } +type PriorityType string + +// high > medium > disabled > low +const ( + PriorityDisabled PriorityType = "" + PriorityLow PriorityType = "low" + PriorityMed PriorityType = "medium" + PriorityHigh PriorityType = "high" +) + // UprStream is per stream data structure over an UPR Connection. type UprStream struct { Vbucket uint16 // Vbucket id @@ -62,6 +72,27 @@ type UprStream struct { connected bool } +type FeedState int + +const ( + FeedStateInitial = iota + FeedStateOpened = iota + FeedStateClosed = iota +) + +func (fs FeedState) String() string { + switch fs { + case FeedStateInitial: + return "Initial" + case FeedStateOpened: + return "Opened" + case FeedStateClosed: + return "Closed" + default: + return "Unknown" + } +} + const ( CompressionTypeStartMarker = iota // also means invalid CompressionTypeNone = iota @@ -80,6 +111,8 @@ type UprFeatures struct { Xattribute bool CompressionType int IncludeDeletionTime bool + DcpPriority PriorityType + EnableExpiry bool } /** @@ -179,7 +212,7 @@ func (negotiator *vbStreamNegotiator) handleStreamRequest(feed *UprFeed, stream, err := negotiator.getStreamFromMap(vbno, opaque) if err != nil { - err = fmt.Errorf("Stream not found for vb %d appOpaque %v: %#v", vbno, appOpaque, *pktPtr) + err = fmt.Errorf("Stream not found for vb %d: %#v", vbno, *pktPtr) logging.Errorf(err.Error()) return nil, err } @@ -226,8 +259,6 @@ func (negotiator *vbStreamNegotiator) cleanUpVbStreams(vbno uint16) { type UprFeed struct { // lock for feed.vbstreams muVbstreams sync.RWMutex - // lock for feed.closed - muClosed sync.RWMutex C <-chan *UprEvent // Exported channel for receiving UPR events negotiator vbStreamNegotiator // Used for pre-vbstreams, concurrent vb stream negotiation vbstreams map[uint16]*UprStream // official live vb->stream mapping @@ -240,12 +271,12 @@ type UprFeed struct { stats UprStats // Stats for upr client transmitCh chan *gomemcached.MCRequest // transmit command channel transmitCl chan bool // closer channel for transmit go-routine - closed bool // flag indicating whether the feed has been closed - // flag indicating whether client of upr feed will send ack to upr feed // if flag is true, upr feed will use ack from client to determine whether/when to send ack to DCP // if flag is false, upr feed will track how many bytes it has sent to client // and use that to determine whether/when to send ack to DCP ackByClient bool + feedState FeedState + muFeedState sync.RWMutex } // Exported interface - to allow for mocking @@ -263,6 +294,8 @@ type UprFeedIface interface { UprOpenWithXATTR(name string, sequence uint32, bufSize uint32) error UprOpenWithFeatures(name string, sequence uint32, bufSize uint32, features UprFeatures) (error, UprFeatures) UprRequestStream(vbno, opaqueMSB uint16, flags uint32, vuuid, startSequence, endSequence, snapStart, snapEnd uint64) error + // Set DCP priority on an existing DCP connection. The command is sent asynchronously without waiting for a response + SetPriorityAsync(p PriorityType) error } type UprStats struct { @@ -494,6 +527,31 @@ func (feed *UprFeed) UprOpenWithFeatures(name string, sequence uint32, bufSize u return feed.uprOpen(name, sequence, bufSize, features) } +func (feed *UprFeed) SetPriorityAsync(p PriorityType) error { + if !feed.isOpen() { + // do not send this command if upr feed is not yet open, otherwise it may interfere with + // feed start up process, which relies on synchronous message exchange with DCP. + return fmt.Errorf("Upr feed is not open. State=%v", feed.getState()) + } + + return feed.setPriority(p, false /*sync*/) +} + +func (feed *UprFeed) setPriority(p PriorityType, sync bool) error { + rq := &gomemcached.MCRequest{ + Opcode: gomemcached.UPR_CONTROL, + Key: []byte("set_priority"), + Body: []byte(p), + Opaque: getUprOpenCtrlOpaque(), + } + if sync { + return sendMcRequestSync(feed.conn, rq) + } else { + return feed.writeToTransmitCh(rq) + + } +} + func (feed *UprFeed) uprOpen(name string, sequence uint32, bufSize uint32, features UprFeatures) (err error, activatedFeatures UprFeatures) { mc := feed.conn @@ -561,6 +619,31 @@ func (feed *UprFeed) uprOpen(name string, sequence uint32, bufSize uint32, featu } activatedFeatures.CompressionType = features.CompressionType + if features.DcpPriority != PriorityDisabled { + err = feed.setPriority(features.DcpPriority, true /*sync*/) + if err == nil { + activatedFeatures.DcpPriority = features.DcpPriority + } else { + return + } + } + + if features.EnableExpiry { + rq := &gomemcached.MCRequest{ + Opcode: gomemcached.UPR_CONTROL, + Key: []byte("enable_expiry_opcode"), + Body: []byte("true"), + Opaque: getUprOpenCtrlOpaque(), + } + err = sendMcRequestSync(feed.conn, rq) + if err != nil { + return + } + activatedFeatures.EnableExpiry = true + } + + // everything is ok so far, set upr feed to open state + feed.setOpen() return } @@ -988,18 +1071,37 @@ func vbOpaque(opq32 uint32) uint16 { // Close this UprFeed. func (feed *UprFeed) Close() { - feed.muClosed.Lock() - defer feed.muClosed.Unlock() - if !feed.closed { + feed.muFeedState.Lock() + defer feed.muFeedState.Unlock() + if feed.feedState != FeedStateClosed { close(feed.closer) - feed.closed = true + feed.feedState = FeedStateClosed feed.negotiator.initialize() } } // check if the UprFeed has been closed func (feed *UprFeed) Closed() bool { - feed.muClosed.RLock() - defer feed.muClosed.RUnlock() - return feed.closed + feed.muFeedState.RLock() + defer feed.muFeedState.RUnlock() + return feed.feedState == FeedStateClosed +} + +// set upr feed to opened state after initialization is done +func (feed *UprFeed) setOpen() { + feed.muFeedState.Lock() + defer feed.muFeedState.Unlock() + feed.feedState = FeedStateOpened +} + +func (feed *UprFeed) isOpen() bool { + feed.muFeedState.RLock() + defer feed.muFeedState.RUnlock() + return feed.feedState == FeedStateOpened +} + +func (feed *UprFeed) getState() FeedState { + feed.muFeedState.RLock() + defer feed.muFeedState.RUnlock() + return feed.feedState } diff --git a/vendor/github.com/couchbase/gomemcached/mc_constants.go b/vendor/github.com/couchbase/gomemcached/mc_constants.go index 1d5027d16c0e7..32f4f51852fd1 100644 --- a/vendor/github.com/couchbase/gomemcached/mc_constants.go +++ b/vendor/github.com/couchbase/gomemcached/mc_constants.go @@ -93,9 +93,12 @@ const ( OBSERVE_SEQNO = CommandCode(0x91) // Sequence Number based Observe OBSERVE = CommandCode(0x92) - GET_META = CommandCode(0xA0) // Get meta. returns with expiry, flags, cas etc - SUBDOC_GET = CommandCode(0xc5) // Get subdoc. Returns with xattrs - SUBDOC_MULTI_LOOKUP = CommandCode(0xd0) // Multi lookup. Doc xattrs and meta. + GET_META = CommandCode(0xA0) // Get meta. returns with expiry, flags, cas etc + GET_COLLECTIONS_MANIFEST = CommandCode(0xba) // Get entire collections manifest. + COLLECTIONS_GET_CID = CommandCode(0xbb) // Get collection id. + SUBDOC_GET = CommandCode(0xc5) // Get subdoc. Returns with xattrs + SUBDOC_MULTI_LOOKUP = CommandCode(0xd0) // Multi lookup. Doc xattrs and meta. + ) // command codes that are counted toward DCP control buffer @@ -113,29 +116,33 @@ type Status uint16 // Matches with protocol_binary.h as source of truth const ( - SUCCESS = Status(0x00) - KEY_ENOENT = Status(0x01) - KEY_EEXISTS = Status(0x02) - E2BIG = Status(0x03) - EINVAL = Status(0x04) - NOT_STORED = Status(0x05) - DELTA_BADVAL = Status(0x06) - NOT_MY_VBUCKET = Status(0x07) - NO_BUCKET = Status(0x08) - LOCKED = Status(0x09) - AUTH_STALE = Status(0x1f) - AUTH_ERROR = Status(0x20) - AUTH_CONTINUE = Status(0x21) - ERANGE = Status(0x22) - ROLLBACK = Status(0x23) - EACCESS = Status(0x24) - NOT_INITIALIZED = Status(0x25) - UNKNOWN_COMMAND = Status(0x81) - ENOMEM = Status(0x82) - NOT_SUPPORTED = Status(0x83) - EINTERNAL = Status(0x84) - EBUSY = Status(0x85) - TMPFAIL = Status(0x86) + SUCCESS = Status(0x00) + KEY_ENOENT = Status(0x01) + KEY_EEXISTS = Status(0x02) + E2BIG = Status(0x03) + EINVAL = Status(0x04) + NOT_STORED = Status(0x05) + DELTA_BADVAL = Status(0x06) + NOT_MY_VBUCKET = Status(0x07) + NO_BUCKET = Status(0x08) + LOCKED = Status(0x09) + AUTH_STALE = Status(0x1f) + AUTH_ERROR = Status(0x20) + AUTH_CONTINUE = Status(0x21) + ERANGE = Status(0x22) + ROLLBACK = Status(0x23) + EACCESS = Status(0x24) + NOT_INITIALIZED = Status(0x25) + UNKNOWN_COMMAND = Status(0x81) + ENOMEM = Status(0x82) + NOT_SUPPORTED = Status(0x83) + EINTERNAL = Status(0x84) + EBUSY = Status(0x85) + TMPFAIL = Status(0x86) + UNKNOWN_COLLECTION = Status(0x88) + + SYNC_WRITE_IN_PROGRESS = Status(0xa2) + SYNC_WRITE_AMBIGUOUS = Status(0xa3) // SUBDOC SUBDOC_PATH_NOT_FOUND = Status(0xc0) @@ -261,6 +268,8 @@ func init() { CommandNames[UPR_CONTROL] = "UPR_CONTROL" CommandNames[SUBDOC_GET] = "SUBDOC_GET" CommandNames[SUBDOC_MULTI_LOOKUP] = "SUBDOC_MULTI_LOOKUP" + CommandNames[GET_COLLECTIONS_MANIFEST] = "GET_COLLECTIONS_MANIFEST" + CommandNames[COLLECTIONS_GET_CID] = "COLLECTIONS_GET_CID" StatusNames = make(map[Status]string) StatusNames[SUCCESS] = "SUCCESS" @@ -285,6 +294,7 @@ func init() { StatusNames[EINTERNAL] = "EINTERNAL" StatusNames[EBUSY] = "EBUSY" StatusNames[TMPFAIL] = "TMPFAIL" + StatusNames[UNKNOWN_COLLECTION] = "UNKNOWN_COLLECTION" StatusNames[SUBDOC_PATH_NOT_FOUND] = "SUBDOC_PATH_NOT_FOUND" StatusNames[SUBDOC_BAD_MULTI] = "SUBDOC_BAD_MULTI" diff --git a/vendor/github.com/couchbase/goutils/logging/logger.go b/vendor/github.com/couchbase/goutils/logging/logger.go index b9948f9b2ef81..ab854635bf7fd 100644 --- a/vendor/github.com/couchbase/goutils/logging/logger.go +++ b/vendor/github.com/couchbase/goutils/logging/logger.go @@ -36,6 +36,7 @@ const ( TEXTFORMATTER = LogEntryFormatter(iota) JSONFORMATTER KVFORMATTER + UNIFORMFORMATTER ) func (level Level) String() string { @@ -476,6 +477,6 @@ func Stackf(level Level, fmt string, args ...interface{}) { } func init() { - logger = NewLogger(os.Stderr, INFO, TEXTFORMATTER) + logger := NewLogger(os.Stderr, INFO, TEXTFORMATTER) SetLogger(logger) } diff --git a/vendor/github.com/couchbase/goutils/logging/logger_golog.go b/vendor/github.com/couchbase/goutils/logging/logger_golog.go index eec432a51369d..14fd3c391db07 100644 --- a/vendor/github.com/couchbase/goutils/logging/logger_golog.go +++ b/vendor/github.com/couchbase/goutils/logging/logger_golog.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Couchbase, Inc. +// Copyright (c) 2016-2019 Couchbase, Inc. // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file // except in compliance with the License. You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 @@ -31,7 +31,7 @@ const ( _RLEVEL = "_rlevel" ) -func NewLogger(out io.Writer, lvl Level, fmtLogging LogEntryFormatter) *goLogger { +func NewLogger(out io.Writer, lvl Level, fmtLogging LogEntryFormatter, fmtArgs ...interface{}) *goLogger { logger := &goLogger{ logger: log.New(out, "", 0), level: lvl, @@ -40,6 +40,10 @@ func NewLogger(out io.Writer, lvl Level, fmtLogging LogEntryFormatter) *goLogger logger.entryFormatter = &jsonFormatter{} } else if fmtLogging == KVFORMATTER { logger.entryFormatter = &keyvalueFormatter{} + } else if fmtLogging == UNIFORMFORMATTER { + logger.entryFormatter = &uniformFormatter{ + callback: fmtArgs[0].(ComponentCallback), + } } else { logger.entryFormatter = &textFormatter{} } @@ -316,3 +320,46 @@ func (*jsonFormatter) format(newEntry *logEntry) string { s := bytes.NewBuffer(append(serialized, '\n')) return s.String() } + +type ComponentCallback func() string + +type uniformFormatter struct { + callback ComponentCallback +} + +// ex. 2019-03-15T11:28:07.652-04:00 DEBU COMPONENT.subcomponent This is a message from test in uniform format + +var _LEVEL_UNIFORM = []string{ + DEBUG: "DEBU", + TRACE: "TRAC", + REQUEST: "REQU", + INFO: "INFO", + WARN: "WARN", + ERROR: "ERRO", + SEVERE: "SEVE", + FATAL: "FATA", + NONE: "NONE", +} + +func (level Level) UniformString() string { + return _LEVEL_UNIFORM[level] +} + +func (uf *uniformFormatter) format(newEntry *logEntry) string { + b := &bytes.Buffer{} + appendValue(b, newEntry.Time) + component := uf.callback() + if newEntry.Rlevel != NONE { + // not really any accommodation for a composite level in the uniform standard; just output as abbr,abbr + fmt.Fprintf(b, "%s,%s %s ", newEntry.Level.UniformString(), newEntry.Rlevel.UniformString(), component) + } else { + fmt.Fprintf(b, "%s %s ", newEntry.Level.UniformString(), component) + } + appendValue(b, newEntry.Message) + for key, value := range newEntry.Data { + appendKeyValue(b, key, value) + } + b.WriteByte('\n') + s := bytes.NewBuffer(b.Bytes()) + return s.String() +} diff --git a/vendor/github.com/couchbaselabs/go-couchbase/client.go b/vendor/github.com/couchbaselabs/go-couchbase/client.go index 43c3382960187..433b08ff02ea7 100644 --- a/vendor/github.com/couchbaselabs/go-couchbase/client.go +++ b/vendor/github.com/couchbaselabs/go-couchbase/client.go @@ -255,6 +255,26 @@ func (b *Bucket) GetCount(refresh bool) (count int64, err error) { return count, nil } +// Get bucket document size through the bucket stats +func (b *Bucket) GetSize(refresh bool) (size int64, err error) { + if refresh { + b.Refresh() + } + + var sz int64 + for _, gs := range b.GatherStats("") { + if len(gs.Stats) > 0 { + sz, err = strconv.ParseInt(gs.Stats["ep_value_size"], 10, 64) + if err != nil { + return 0, err + } + size += sz + } + } + + return size, nil +} + func isAuthError(err error) bool { estr := err.Error() return strings.Contains(estr, "Auth failure") @@ -980,6 +1000,78 @@ func (b *Bucket) Append(k string, data []byte) error { return b.Write(k, 0, 0, data, Append|Raw) } +func (b *Bucket) GetsMCFromCollection(collUid uint32, key string, reqDeadline time.Time) (*gomemcached.MCResponse, error) { + var err error + var response *gomemcached.MCResponse + + if key == "" { + return nil, nil + } + + if ClientOpCallback != nil { + defer func(t time.Time) { ClientOpCallback("GetsMCFromCollection", key, t, err) }(time.Now()) + } + + err = b.Do2(key, func(mc *memcached.Client, vb uint16) error { + var err1 error + + mc.SetDeadline(getDeadline(reqDeadline, DefaultTimeout)) + _, err1 = mc.SelectBucket(b.Name) + if err1 != nil { + mc.SetDeadline(noDeadline) + return err1 + } + + mc.SetDeadline(getDeadline(reqDeadline, DefaultTimeout)) + response, err1 = mc.GetFromCollection(vb, collUid, key) + if err1 != nil { + mc.SetDeadline(noDeadline) + return err1 + } + + return nil + }, false) + + return response, err +} + +// Returns collectionUid, manifestUid, error. +func (b *Bucket) GetCollectionCID(scope string, collection string, reqDeadline time.Time) (uint32, uint32, error) { + var err error + var response *gomemcached.MCResponse + + if ClientOpCallback != nil { + defer func(t time.Time) { ClientOpCallback("GetCollectionCID", scope+"."+collection, t, err) }(time.Now()) + } + + var key = "DUMMY" // Contact any server. + var manifestUid uint32 + var collUid uint32 + err = b.Do2(key, func(mc *memcached.Client, vb uint16) error { + var err1 error + + mc.SetDeadline(getDeadline(reqDeadline, DefaultTimeout)) + _, err1 = mc.SelectBucket(b.Name) + if err1 != nil { + mc.SetDeadline(noDeadline) + return err1 + } + + response, err1 = mc.CollectionsGetCID(scope, collection) + if err1 != nil { + mc.SetDeadline(noDeadline) + return err1 + } + + manifestUid = binary.BigEndian.Uint32(response.Extras[4:8]) + collUid = binary.BigEndian.Uint32(response.Extras[8:12]) + + return nil + }, false) + + return collUid, manifestUid, err +} + // Get a value straight from Memcached func (b *Bucket) GetsMC(key string, reqDeadline time.Time) (*gomemcached.MCResponse, error) { var err error diff --git a/vendor/github.com/couchbaselabs/go-couchbase/conn_pool.go b/vendor/github.com/couchbaselabs/go-couchbase/conn_pool.go index babd3adb6a6ce..23102abd84ac2 100644 --- a/vendor/github.com/couchbaselabs/go-couchbase/conn_pool.go +++ b/vendor/github.com/couchbaselabs/go-couchbase/conn_pool.go @@ -1,6 +1,7 @@ package couchbase import ( + "crypto/tls" "errors" "sync/atomic" "time" @@ -36,7 +37,7 @@ var ConnPoolAvailWaitTime = time.Millisecond type connectionPool struct { host string - mkConn func(host string, ah AuthHandler) (*memcached.Client, error) + mkConn func(host string, ah AuthHandler, tlsConfig *tls.Config, bucketName string) (*memcached.Client, error) auth AuthHandler connections chan *memcached.Client createsem chan bool @@ -44,9 +45,11 @@ type connectionPool struct { poolSize int connCount uint64 inUse bool + tlsConfig *tls.Config + bucket string } -func newConnectionPool(host string, ah AuthHandler, closer bool, poolSize, poolOverflow int) *connectionPool { +func newConnectionPool(host string, ah AuthHandler, closer bool, poolSize, poolOverflow int, tlsConfig *tls.Config, bucket string) *connectionPool { connSize := poolSize if closer { connSize += poolOverflow @@ -58,6 +61,8 @@ func newConnectionPool(host string, ah AuthHandler, closer bool, poolSize, poolO mkConn: defaultMkConn, auth: ah, poolSize: poolSize, + tlsConfig: tlsConfig, + bucket: bucket, } if closer { rv.bailOut = make(chan bool, 1) @@ -69,10 +74,19 @@ func newConnectionPool(host string, ah AuthHandler, closer bool, poolSize, poolO // ConnPoolTimeout is notified whenever connections are acquired from a pool. var ConnPoolCallback func(host string, source string, start time.Time, err error) -func defaultMkConn(host string, ah AuthHandler) (*memcached.Client, error) { +// Use regular in-the-clear connection if tlsConfig is nil. +// Use secure connection (TLS) if tlsConfig is set. +func defaultMkConn(host string, ah AuthHandler, tlsConfig *tls.Config, bucketName string) (*memcached.Client, error) { var features memcached.Features - conn, err := memcached.Connect("tcp", host) + var conn *memcached.Client + var err error + if tlsConfig == nil { + conn, err = memcached.Connect("tcp", host) + } else { + conn, err = memcached.ConnectTLS("tcp", host, tlsConfig) + } + if err != nil { return nil, err } @@ -92,6 +106,10 @@ func defaultMkConn(host string, ah AuthHandler) (*memcached.Client, error) { features = append(features, memcached.FeatureXattr) } + if EnableCollections { + features = append(features, memcached.FeatureCollections) + } + if len(features) > 0 { if DefaultTimeout > 0 { conn.SetDeadline(getDeadline(noDeadline, DefaultTimeout)) @@ -122,6 +140,11 @@ func defaultMkConn(host string, ah AuthHandler) (*memcached.Client, error) { return conn, nil } name, pass, bucket := ah.GetCredentials() + if bucket == "" { + // Authenticator does not know specific bucket. + bucket = bucketName + } + if name != "default" { _, err = conn.Auth(name, pass) if err != nil { @@ -221,7 +244,7 @@ func (cp *connectionPool) GetWithTimeout(d time.Duration) (rv *memcached.Client, // Build a connection if we can't get a real one. // This can potentially be an overflow connection, or // a pooled connection. - rv, err := cp.mkConn(cp.host, cp.auth) + rv, err := cp.mkConn(cp.host, cp.auth, cp.tlsConfig, cp.bucket) if err != nil { // On error, release our create hold <-cp.createsem diff --git a/vendor/github.com/couchbaselabs/go-couchbase/pools.go b/vendor/github.com/couchbaselabs/go-couchbase/pools.go index 5f3ff8c49523c..0e2379398ab09 100644 --- a/vendor/github.com/couchbaselabs/go-couchbase/pools.go +++ b/vendor/github.com/couchbaselabs/go-couchbase/pools.go @@ -16,8 +16,10 @@ import ( "net/url" "runtime" "sort" + "strconv" "strings" "sync" + "time" "unsafe" "github.com/couchbase/goutils/logging" @@ -28,8 +30,9 @@ import ( // HTTPClient to use for REST and view operations. var MaxIdleConnsPerHost = 256 +var ClientTimeOut = 10 * time.Second var HTTPTransport = &http.Transport{MaxIdleConnsPerHost: MaxIdleConnsPerHost} -var HTTPClient = &http.Client{Transport: HTTPTransport} +var HTTPClient = &http.Client{Transport: HTTPTransport, Timeout: ClientTimeOut} // PoolSize is the size of each connection pool (per host). var PoolSize = 64 @@ -53,6 +56,9 @@ var EnableDataType = false // Enable Xattr var EnableXattr = false +// Enable Collections +var EnableCollections = false + // TCP keepalive interval in seconds. Default 30 minutes var TCPKeepaliveInterval = 30 * 60 @@ -178,12 +184,12 @@ type Node struct { // A Pool of nodes and buckets. type Pool struct { - BucketMap map[string]Bucket + BucketMap map[string]*Bucket Nodes []Node BucketURL map[string]string `json:"buckets"` - client Client + client *Client } // VBucketServerMap is the a mapping of vbuckets to nodes. @@ -240,13 +246,14 @@ type Bucket struct { commonSufix string ah AuthHandler // auth handler ds *DurablitySettings // Durablity Settings for this bucket - Scopes Scopes + closed bool } // PoolServices is all the bucket-independent services in a pool type PoolServices struct { - Rev int `json:"rev"` - NodesExt []NodeServices `json:"nodesExt"` + Rev int `json:"rev"` + NodesExt []NodeServices `json:"nodesExt"` + Capabilities json.RawMessage `json:"clusterCapabilities"` } // NodeServices is all the bucket-independent services running on @@ -337,7 +344,7 @@ func (b *Bucket) GetName() string { return ret } -// Nodes returns teh current list of nodes servicing this bucket. +// Nodes returns the current list of nodes servicing this bucket. func (b *Bucket) Nodes() []Node { b.RLock() defer b.RUnlock() @@ -475,6 +482,14 @@ func (b *Bucket) GetRandomDoc() (*gomemcached.MCResponse, error) { return nil, err } + // We may need to select the bucket before GetRandomDoc() + // will work. This is sometimes done at startup (see defaultMkConn()) + // but not always, depending on the auth type. + _, err = conn.SelectBucket(b.Name) + if err != nil { + return nil, err + } + // get a randomm document from the connection doc, err := conn.GetRandomDoc() // need to return the connection to the pool @@ -533,9 +548,10 @@ func (b *Bucket) CommonAddressSuffix() string { // A Client is the starting point for all services across all buckets // in a Couchbase cluster. type Client struct { - BaseURL *url.URL - ah AuthHandler - Info Pools + BaseURL *url.URL + ah AuthHandler + Info Pools + tlsConfig *tls.Config } func maybeAddAuth(req *http.Request, ah AuthHandler) error { @@ -601,11 +617,11 @@ func doHTTPRequest(req *http.Request) (*http.Response, error) { var err error var res *http.Response - tr := &http.Transport{} - // we need a client that ignores certificate errors, since we self-sign // our certs if client == nil && req.URL.Scheme == "https" { + var tr *http.Transport + if skipVerify { tr = &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, @@ -931,6 +947,25 @@ func ConnectWithAuth(baseU string, ah AuthHandler) (c Client, err error) { return c, c.parseURLResponse("/pools", &c.Info) } +// Call this method with a TLS certificate file name to make communication +// with the KV engine encrypted. +// +// This method should be called immediately after a Connect*() method. +func (c *Client) InitTLS(certFile string) error { + serverCert, err := ioutil.ReadFile(certFile) + if err != nil { + return err + } + CA_Pool := x509.NewCertPool() + CA_Pool.AppendCertsFromPEM(serverCert) + c.tlsConfig = &tls.Config{RootCAs: CA_Pool} + return nil +} + +func (c *Client) ClearTLS() { + c.tlsConfig = nil +} + // ConnectWithAuthCreds connects to a couchbase cluster with the give // authorization creds returned by cb_auth func ConnectWithAuthCreds(baseU, username, password string) (c Client, err error) { @@ -941,7 +976,6 @@ func ConnectWithAuthCreds(baseU, username, password string) (c Client, err error c.ah = newBucketAuth(username, password, "") return c, c.parseURLResponse("/pools", &c.Info) - } // Connect to a couchbase cluster. An authentication handler will be @@ -1038,44 +1072,153 @@ func (b *Bucket) NodeListChanged() bool { // /pooles/default/$BUCKET_NAME/collections API. // {"myScope2":{"myCollectionC":{}},"myScope1":{"myCollectionB":{},"myCollectionA":{}},"_default":{"_default":{}}} -// A Scopes holds the set of scopes in a bucket. +// Structures for parsing collections manifest. // The map key is the name of the scope. -type Scopes map[string]Collections - -// A Collections holds the set of collections in a scope. -// The map key is the name of the collection. -type Collections map[string]Collection - -// A Collection holds the information for a collection. -// It is currently returned empty. -type Collection struct{} - -func getScopesAndCollections(pool *Pool, bucketName string) (Scopes, error) { - scopes := make(Scopes) - // This URL is a bit of a hack. The "default" is the name of the pool, and should - // be a parameter. But the name does not appear to be available anywhere, - // and in any case we never use a pool other than "default". - err := pool.client.parseURLResponse(fmt.Sprintf("/pools/default/buckets/%s/collections", bucketName), &scopes) +// Example data: +// {"uid":"b","scopes":[ +// {"name":"_default","uid":"0","collections":[ +// {"name":"_default","uid":"0"}]}, +// {"name":"myScope1","uid":"8","collections":[ +// {"name":"myCollectionB","uid":"c"}, +// {"name":"myCollectionA","uid":"b"}]}, +// {"name":"myScope2","uid":"9","collections":[ +// {"name":"myCollectionC","uid":"d"}]}]} +type InputManifest struct { + Uid string + Scopes []InputScope +} +type InputScope struct { + Name string + Uid string + Collections []InputCollection +} +type InputCollection struct { + Name string + Uid string +} + +// Structures for storing collections information. +type Manifest struct { + Uid uint64 + Scopes map[string]*Scope // map by name +} +type Scope struct { + Name string + Uid uint64 + Collections map[string]*Collection // map by name +} +type Collection struct { + Name string + Uid uint64 +} + +var _EMPTY_MANIFEST *Manifest = &Manifest{Uid: 0, Scopes: map[string]*Scope{}} + +func parseCollectionsManifest(res *gomemcached.MCResponse) (*Manifest, error) { + if !EnableCollections { + return _EMPTY_MANIFEST, nil + } + + var im InputManifest + err := json.Unmarshal(res.Body, &im) + if err != nil { + return nil, err + } + + uid, err := strconv.ParseUint(im.Uid, 16, 64) if err != nil { return nil, err } - return scopes, nil + mani := &Manifest{Uid: uid, Scopes: make(map[string]*Scope, len(im.Scopes))} + for _, iscope := range im.Scopes { + scope_uid, err := strconv.ParseUint(iscope.Uid, 16, 64) + if err != nil { + return nil, err + } + scope := &Scope{Uid: scope_uid, Name: iscope.Name, Collections: make(map[string]*Collection, len(iscope.Collections))} + mani.Scopes[iscope.Name] = scope + for _, icoll := range iscope.Collections { + coll_uid, err := strconv.ParseUint(icoll.Uid, 16, 64) + if err != nil { + return nil, err + } + coll := &Collection{Uid: coll_uid, Name: icoll.Name} + scope.Collections[icoll.Name] = coll + } + } + + return mani, nil +} + +// This function assumes the bucket is locked. +func (b *Bucket) GetCollectionsManifest() (*Manifest, error) { + // Collections not used? + if !EnableCollections { + return nil, fmt.Errorf("Collections not enabled.") + } + + b.RLock() + pools := b.getConnPools(true /* already locked */) + pool := pools[0] // Any pool will do, so use the first one. + b.RUnlock() + client, err := pool.Get() + if err != nil { + return nil, fmt.Errorf("Unable to get connection to retrieve collections manifest: %v. No collections access to bucket %s.", err, b.Name) + } + + // We need to select the bucket before GetCollectionsManifest() + // will work. This is sometimes done at startup (see defaultMkConn()) + // but not always, depending on the auth type. + // Doing this is safe because we collect the the connections + // by bucket, so the bucket being selected will never change. + _, err = client.SelectBucket(b.Name) + if err != nil { + pool.Return(client) + return nil, fmt.Errorf("Unable to select bucket %s: %v. No collections access to bucket %s.", err, b.Name, b.Name) + } + + res, err := client.GetCollectionsManifest() + if err != nil { + pool.Return(client) + return nil, fmt.Errorf("Unable to retrieve collections manifest: %v. No collections access to bucket %s.", err, b.Name) + } + mani, err := parseCollectionsManifest(res) + if err != nil { + pool.Return(client) + return nil, fmt.Errorf("Unable to parse collections manifest: %v. No collections access to bucket %s.", err, b.Name) + } + + pool.Return(client) + return mani, nil +} + +func (b *Bucket) RefreshFully() error { + return b.refresh(false) } func (b *Bucket) Refresh() error { + return b.refresh(true) +} + +func (b *Bucket) refresh(preserveConnections bool) error { b.RLock() pool := b.pool uri := b.URI - name := b.Name + client := pool.client b.RUnlock() + tlsConfig := client.tlsConfig - tmpb := &Bucket{} - err := pool.client.parseURLResponse(uri, tmpb) - if err != nil { - return err + var poolServices PoolServices + var err error + if tlsConfig != nil { + poolServices, err = client.GetPoolServices("default") + if err != nil { + return err + } } - scopes, err := getScopesAndCollections(pool, name) + tmpb := &Bucket{} + err = pool.client.parseURLResponse(uri, tmpb) if err != nil { return err } @@ -1096,50 +1239,67 @@ func (b *Bucket) Refresh() error { newcps := make([]*connectionPool, len(tmpb.VBSMJson.ServerList)) for i := range newcps { - pool := b.getConnPoolByHost(tmpb.VBSMJson.ServerList[i], true /* bucket already locked */) - if pool != nil && pool.inUse == false { - // if the hostname and index is unchanged then reuse this pool - newcps[i] = pool - pool.inUse = true - continue + if preserveConnections { + pool := b.getConnPoolByHost(tmpb.VBSMJson.ServerList[i], true /* bucket already locked */) + if pool != nil && pool.inUse == false { + // if the hostname and index is unchanged then reuse this pool + newcps[i] = pool + pool.inUse = true + continue + } + } + + hostport := tmpb.VBSMJson.ServerList[i] + if tlsConfig != nil { + hostport, err = MapKVtoSSL(hostport, &poolServices) + if err != nil { + b.Unlock() + return err + } } if b.ah != nil { - newcps[i] = newConnectionPool( - tmpb.VBSMJson.ServerList[i], - b.ah, AsynchronousCloser, PoolSize, PoolOverflow) + newcps[i] = newConnectionPool(hostport, + b.ah, AsynchronousCloser, PoolSize, PoolOverflow, tlsConfig, b.Name) } else { - newcps[i] = newConnectionPool( - tmpb.VBSMJson.ServerList[i], + newcps[i] = newConnectionPool(hostport, b.authHandler(true /* bucket already locked */), - AsynchronousCloser, PoolSize, PoolOverflow) + AsynchronousCloser, PoolSize, PoolOverflow, tlsConfig, b.Name) } } b.replaceConnPools2(newcps, true /* bucket already locked */) tmpb.ah = b.ah b.vBucketServerMap = unsafe.Pointer(&tmpb.VBSMJson) b.nodeList = unsafe.Pointer(&tmpb.NodesJSON) - b.Scopes = scopes b.Unlock() return nil } func (p *Pool) refresh() (err error) { - p.BucketMap = make(map[string]Bucket) + p.BucketMap = make(map[string]*Bucket) buckets := []Bucket{} err = p.client.parseURLResponse(p.BucketURL["uri"], &buckets) if err != nil { return err } - for _, b := range buckets { + for i, _ := range buckets { + b := new(Bucket) + *b = buckets[i] b.pool = p b.nodeList = unsafe.Pointer(&b.NodesJSON) - b.replaceConnPools(make([]*connectionPool, len(b.VBSMJson.ServerList))) + // MB-33185 this is merely defensive, just in case + // refresh() gets called on a perfectly node pool + ob, ok := p.BucketMap[b.Name] + if ok && ob.connPools != nil { + ob.Close() + } + b.replaceConnPools(make([]*connectionPool, len(b.VBSMJson.ServerList))) p.BucketMap[b.Name] = b + runtime.SetFinalizer(b, bucketFinalizer) } return nil } @@ -1148,9 +1308,11 @@ func (p *Pool) refresh() (err error) { // "default"). func (c *Client) GetPool(name string) (p Pool, err error) { var poolURI string + for _, p := range c.Info.Pools { if p.Name == name { poolURI = p.URI + break } } if poolURI == "" { @@ -1159,7 +1321,7 @@ func (c *Client) GetPool(name string) (p Pool, err error) { err = c.parseURLResponse(poolURI, &p) - p.client = *c + p.client = c err = p.refresh() return @@ -1184,6 +1346,19 @@ func (c *Client) GetPoolServices(name string) (ps PoolServices, err error) { return } +func (b *Bucket) GetPoolServices(name string) (*PoolServices, error) { + b.RLock() + pool := b.pool + b.RUnlock() + + ps, err := pool.client.GetPoolServices(name) + if err != nil { + return nil, err + } + + return &ps, nil +} + // Close marks this bucket as no longer needed, closing connections it // may have open. func (b *Bucket) Close() { @@ -1201,7 +1376,12 @@ func (b *Bucket) Close() { func bucketFinalizer(b *Bucket) { if b.connPools != nil { - logging.Warnf("Finalizing a bucket with active connections.") + if !b.closed { + logging.Warnf("Finalizing a bucket with active connections.") + } + + // MB-33185 do not leak connection pools + b.Close() } } @@ -1211,12 +1391,11 @@ func (p *Pool) GetBucket(name string) (*Bucket, error) { if !ok { return nil, &BucketNotFoundError{bucket: name} } - runtime.SetFinalizer(&rv, bucketFinalizer) err := rv.Refresh() if err != nil { return nil, err } - return &rv, nil + return rv, nil } // GetBucket gets a bucket from within this pool. @@ -1225,13 +1404,12 @@ func (p *Pool) GetBucketWithAuth(bucket, username, password string) (*Bucket, er if !ok { return nil, &BucketNotFoundError{bucket: bucket} } - runtime.SetFinalizer(&rv, bucketFinalizer) rv.ah = newBucketAuth(username, password, bucket) err := rv.Refresh() if err != nil { return nil, err } - return &rv, nil + return rv, nil } // GetPool gets the pool to which this bucket belongs. @@ -1244,7 +1422,21 @@ func (b *Bucket) GetPool() *Pool { // GetClient gets the client from which we got this pool. func (p *Pool) GetClient() *Client { - return &p.client + return p.client +} + +// Release bucket connections when the pool is no longer in use +func (p *Pool) Close() { + // fine to loop through the buckets unlocked + // locking happens at the bucket level + for b, _ := range p.BucketMap { + + // MB-33208 defer closing connection pools until the bucket is no longer used + bucket := p.BucketMap[b] + bucket.Lock() + bucket.closed = true + bucket.Unlock() + } } // GetBucket is a convenience function for getting a named bucket from diff --git a/vendor/github.com/couchbaselabs/go-couchbase/port_map.go b/vendor/github.com/couchbaselabs/go-couchbase/port_map.go new file mode 100644 index 0000000000000..24c9f105db820 --- /dev/null +++ b/vendor/github.com/couchbaselabs/go-couchbase/port_map.go @@ -0,0 +1,84 @@ +package couchbase + +/* + +The goal here is to map a hostname:port combination to another hostname:port +combination. The original hostname:port gives the name and regular KV port +of a couchbase server. We want to determine the corresponding SSL KV port. + +To do this, we have a pool services structure, as obtained from +the /pools/default/nodeServices API. + +For a fully configured two-node system, the structure may look like this: +{"rev":32,"nodesExt":[ + {"services":{"mgmt":8091,"mgmtSSL":18091,"fts":8094,"ftsSSL":18094,"indexAdmin":9100,"indexScan":9101,"indexHttp":9102,"indexStreamInit":9103,"indexStreamCatchup":9104,"indexStreamMaint":9105,"indexHttps":19102,"capiSSL":18092,"capi":8092,"kvSSL":11207,"projector":9999,"kv":11210,"moxi":11211},"hostname":"172.23.123.101"}, + {"services":{"mgmt":8091,"mgmtSSL":18091,"indexAdmin":9100,"indexScan":9101,"indexHttp":9102,"indexStreamInit":9103,"indexStreamCatchup":9104,"indexStreamMaint":9105,"indexHttps":19102,"capiSSL":18092,"capi":8092,"kvSSL":11207,"projector":9999,"kv":11210,"moxi":11211,"n1ql":8093,"n1qlSSL":18093},"thisNode":true,"hostname":"172.23.123.102"}]} + +In this case, note the "hostname" fields, and the "kv" and "kvSSL" fields. + +For a single-node system, perhaps brought up for testing, the structure may look like this: +{"rev":66,"nodesExt":[ + {"services":{"mgmt":8091,"mgmtSSL":18091,"indexAdmin":9100,"indexScan":9101,"indexHttp":9102,"indexStreamInit":9103,"indexStreamCatchup":9104,"indexStreamMaint":9105,"indexHttps":19102,"kv":11210,"kvSSL":11207,"capi":8092,"capiSSL":18092,"projector":9999,"n1ql":8093,"n1qlSSL":18093},"thisNode":true}],"clusterCapabilitiesVer":[1,0],"clusterCapabilities":{"n1ql":["enhancedPreparedStatements"]}} + +Here, note that there is only a single entry in the "nodeExt" array and that it does not have a "hostname" field. +We will assume that either hostname fields are present, or there is only a single node. +*/ + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" +) + +func ParsePoolServices(jsonInput string) (*PoolServices, error) { + ps := &PoolServices{} + err := json.Unmarshal([]byte(jsonInput), ps) + return ps, err +} + +func MapKVtoSSL(hostport string, ps *PoolServices) (string, error) { + colonIndex := strings.LastIndex(hostport, ":") + if colonIndex < 0 { + return "", fmt.Errorf("Unable to find host/port separator in %s", hostport) + } + host := hostport[0:colonIndex] + port := hostport[colonIndex+1:] + portInt, err := strconv.Atoi(port) + if err != nil { + return "", fmt.Errorf("Unable to parse host/port combination %s: %v", hostport, err) + } + + var ns *NodeServices + if len(ps.NodesExt) == 1 { + ns = &(ps.NodesExt[0]) + } else { + for i := range ps.NodesExt { + hostname := ps.NodesExt[i].Hostname + if len(hostname) == 0 { + // in case of missing hostname, check for 127.0.0.1 + hostname = "127.0.0.1" + } + if hostname == host { + ns = &(ps.NodesExt[i]) + break + } + } + } + + if ns == nil { + return "", fmt.Errorf("Unable to parse host/port combination %s: no matching node found among %d", hostport, len(ps.NodesExt)) + } + kv, found := ns.Services["kv"] + if !found { + return "", fmt.Errorf("Unable to map host/port combination %s: target host has no kv port listed", hostport) + } + kvSSL, found := ns.Services["kvSSL"] + if !found { + return "", fmt.Errorf("Unable to map host/port combination %s: target host has no kvSSL port listed", hostport) + } + if portInt != kv { + return "", fmt.Errorf("Unable to map hostport combination %s: expected port %d but found %d", hostport, portInt, kv) + } + return fmt.Sprintf("%s:%d", host, kvSSL), nil +} diff --git a/vendor/github.com/couchbaselabs/go-couchbase/streaming.go b/vendor/github.com/couchbaselabs/go-couchbase/streaming.go index 6467635371603..6d8f7dfd53847 100644 --- a/vendor/github.com/couchbaselabs/go-couchbase/streaming.go +++ b/vendor/github.com/couchbaselabs/go-couchbase/streaming.go @@ -88,6 +88,16 @@ func (b *Bucket) UpdateBucket() error { var failures int var returnErr error + var poolServices PoolServices + var err error + tlsConfig := b.pool.client.tlsConfig + if tlsConfig != nil { + poolServices, err = b.pool.client.GetPoolServices("default") + if err != nil { + return err + } + } + for { if failures == MAX_RETRY_COUNT { @@ -110,15 +120,6 @@ func (b *Bucket) UpdateBucket() error { return err } - b.RLock() - pool := b.pool - bucketName := b.Name - b.RUnlock() - scopes, err := getScopesAndCollections(pool, bucketName) - if err != nil { - return err - } - // Lock here to avoid having pool closed under us. b.RLock() err = maybeAddAuth(req, b.pool.client.ah) @@ -176,16 +177,22 @@ func (b *Bucket) UpdateBucket() error { continue } // else create a new pool + hostport := tmpb.VBSMJson.ServerList[i] + if tlsConfig != nil { + hostport, err = MapKVtoSSL(hostport, &poolServices) + if err != nil { + b.Unlock() + return err + } + } if b.ah != nil { - newcps[i] = newConnectionPool( - tmpb.VBSMJson.ServerList[i], - b.ah, false, PoolSize, PoolOverflow) + newcps[i] = newConnectionPool(hostport, + b.ah, false, PoolSize, PoolOverflow, b.pool.client.tlsConfig, b.Name) } else { - newcps[i] = newConnectionPool( - tmpb.VBSMJson.ServerList[i], + newcps[i] = newConnectionPool(hostport, b.authHandler(true /* bucket already locked */), - false, PoolSize, PoolOverflow) + false, PoolSize, PoolOverflow, b.pool.client.tlsConfig, b.Name) } } @@ -194,7 +201,6 @@ func (b *Bucket) UpdateBucket() error { tmpb.ah = b.ah b.vBucketServerMap = unsafe.Pointer(&tmpb.VBSMJson) b.nodeList = unsafe.Pointer(&tmpb.NodesJSON) - b.Scopes = scopes b.Unlock() logging.Infof("Got new configuration for bucket %s", b.GetName()) diff --git a/vendor/github.com/edsrzf/mmap-go/mmap.go b/vendor/github.com/edsrzf/mmap-go/mmap.go index 14fb22580a82f..29655bd222ca6 100644 --- a/vendor/github.com/edsrzf/mmap-go/mmap.go +++ b/vendor/github.com/edsrzf/mmap-go/mmap.go @@ -81,25 +81,27 @@ func (m *MMap) header() *reflect.SliceHeader { return (*reflect.SliceHeader)(unsafe.Pointer(m)) } +func (m *MMap) addrLen() (uintptr, uintptr) { + header := m.header() + return header.Data, uintptr(header.Len) +} + // Lock keeps the mapped region in physical memory, ensuring that it will not be // swapped out. func (m MMap) Lock() error { - dh := m.header() - return lock(dh.Data, uintptr(dh.Len)) + return m.lock() } // Unlock reverses the effect of Lock, allowing the mapped region to potentially // be swapped out. // If m is already unlocked, aan error will result. func (m MMap) Unlock() error { - dh := m.header() - return unlock(dh.Data, uintptr(dh.Len)) + return m.unlock() } // Flush synchronizes the mapping's contents to the file's contents on disk. func (m MMap) Flush() error { - dh := m.header() - return flush(dh.Data, uintptr(dh.Len)) + return m.flush() } // Unmap deletes the memory mapped region, flushes any remaining changes, and sets @@ -109,8 +111,7 @@ func (m MMap) Flush() error { // Unmap should only be called on the slice value that was originally returned from // a call to Map. Calling Unmap on a derived slice may cause errors. func (m *MMap) Unmap() error { - dh := m.header() - err := unmap(dh.Data, uintptr(dh.Len)) + err := m.unmap() *m = nil return err } diff --git a/vendor/github.com/edsrzf/mmap-go/mmap_unix.go b/vendor/github.com/edsrzf/mmap-go/mmap_unix.go index 4af98420d56c0..25b13e51fdffd 100644 --- a/vendor/github.com/edsrzf/mmap-go/mmap_unix.go +++ b/vendor/github.com/edsrzf/mmap-go/mmap_unix.go @@ -7,61 +7,45 @@ package mmap import ( - "syscall" + "golang.org/x/sys/unix" ) func mmap(len int, inprot, inflags, fd uintptr, off int64) ([]byte, error) { - flags := syscall.MAP_SHARED - prot := syscall.PROT_READ + flags := unix.MAP_SHARED + prot := unix.PROT_READ switch { case inprot© != 0: - prot |= syscall.PROT_WRITE - flags = syscall.MAP_PRIVATE + prot |= unix.PROT_WRITE + flags = unix.MAP_PRIVATE case inprot&RDWR != 0: - prot |= syscall.PROT_WRITE + prot |= unix.PROT_WRITE } if inprot&EXEC != 0 { - prot |= syscall.PROT_EXEC + prot |= unix.PROT_EXEC } if inflags&ANON != 0 { - flags |= syscall.MAP_ANON + flags |= unix.MAP_ANON } - b, err := syscall.Mmap(int(fd), off, len, prot, flags) + b, err := unix.Mmap(int(fd), off, len, prot, flags) if err != nil { return nil, err } return b, nil } -func flush(addr, len uintptr) error { - _, _, errno := syscall.Syscall(_SYS_MSYNC, addr, len, _MS_SYNC) - if errno != 0 { - return syscall.Errno(errno) - } - return nil +func (m MMap) flush() error { + return unix.Msync([]byte(m), unix.MS_SYNC) } -func lock(addr, len uintptr) error { - _, _, errno := syscall.Syscall(syscall.SYS_MLOCK, addr, len, 0) - if errno != 0 { - return syscall.Errno(errno) - } - return nil +func (m MMap) lock() error { + return unix.Mlock([]byte(m)) } -func unlock(addr, len uintptr) error { - _, _, errno := syscall.Syscall(syscall.SYS_MUNLOCK, addr, len, 0) - if errno != 0 { - return syscall.Errno(errno) - } - return nil +func (m MMap) unlock() error { + return unix.Munlock([]byte(m)) } -func unmap(addr, len uintptr) error { - _, _, errno := syscall.Syscall(syscall.SYS_MUNMAP, addr, len, 0) - if errno != 0 { - return syscall.Errno(errno) - } - return nil +func (m MMap) unmap() error { + return unix.Munmap([]byte(m)) } diff --git a/vendor/github.com/edsrzf/mmap-go/mmap_windows.go b/vendor/github.com/edsrzf/mmap-go/mmap_windows.go index c3d2d02d3f1b9..7910da257703a 100644 --- a/vendor/github.com/edsrzf/mmap-go/mmap_windows.go +++ b/vendor/github.com/edsrzf/mmap-go/mmap_windows.go @@ -8,7 +8,8 @@ import ( "errors" "os" "sync" - "syscall" + + "golang.org/x/sys/windows" ) // mmap on Windows is a two-step process. @@ -19,23 +20,29 @@ import ( // not a struct, so it's convenient to manipulate. // We keep this map so that we can get back the original handle from the memory address. + +type addrinfo struct { + file windows.Handle + mapview windows.Handle +} + var handleLock sync.Mutex -var handleMap = map[uintptr]syscall.Handle{} +var handleMap = map[uintptr]*addrinfo{} func mmap(len int, prot, flags, hfile uintptr, off int64) ([]byte, error) { - flProtect := uint32(syscall.PAGE_READONLY) - dwDesiredAccess := uint32(syscall.FILE_MAP_READ) + flProtect := uint32(windows.PAGE_READONLY) + dwDesiredAccess := uint32(windows.FILE_MAP_READ) switch { case prot© != 0: - flProtect = syscall.PAGE_WRITECOPY - dwDesiredAccess = syscall.FILE_MAP_COPY + flProtect = windows.PAGE_WRITECOPY + dwDesiredAccess = windows.FILE_MAP_COPY case prot&RDWR != 0: - flProtect = syscall.PAGE_READWRITE - dwDesiredAccess = syscall.FILE_MAP_WRITE + flProtect = windows.PAGE_READWRITE + dwDesiredAccess = windows.FILE_MAP_WRITE } if prot&EXEC != 0 { flProtect <<= 4 - dwDesiredAccess |= syscall.FILE_MAP_EXECUTE + dwDesiredAccess |= windows.FILE_MAP_EXECUTE } // The maximum size is the area of the file, starting from 0, @@ -45,7 +52,7 @@ func mmap(len int, prot, flags, hfile uintptr, off int64) ([]byte, error) { maxSizeHigh := uint32((off + int64(len)) >> 32) maxSizeLow := uint32((off + int64(len)) & 0xFFFFFFFF) // TODO: Do we need to set some security attributes? It might help portability. - h, errno := syscall.CreateFileMapping(syscall.Handle(hfile), nil, flProtect, maxSizeHigh, maxSizeLow, nil) + h, errno := windows.CreateFileMapping(windows.Handle(hfile), nil, flProtect, maxSizeHigh, maxSizeLow, nil) if h == 0 { return nil, os.NewSyscallError("CreateFileMapping", errno) } @@ -54,12 +61,15 @@ func mmap(len int, prot, flags, hfile uintptr, off int64) ([]byte, error) { // is the length the user requested. fileOffsetHigh := uint32(off >> 32) fileOffsetLow := uint32(off & 0xFFFFFFFF) - addr, errno := syscall.MapViewOfFile(h, dwDesiredAccess, fileOffsetHigh, fileOffsetLow, uintptr(len)) + addr, errno := windows.MapViewOfFile(h, dwDesiredAccess, fileOffsetHigh, fileOffsetLow, uintptr(len)) if addr == 0 { return nil, os.NewSyscallError("MapViewOfFile", errno) } handleLock.Lock() - handleMap[addr] = h + handleMap[addr] = &addrinfo{ + file: windows.Handle(hfile), + mapview: h, + } handleLock.Unlock() m := MMap{} @@ -71,8 +81,9 @@ func mmap(len int, prot, flags, hfile uintptr, off int64) ([]byte, error) { return m, nil } -func flush(addr, len uintptr) error { - errno := syscall.FlushViewOfFile(addr, len) +func (m MMap) flush() error { + addr, len := m.addrLen() + errno := windows.FlushViewOfFile(addr, len) if errno != nil { return os.NewSyscallError("FlushViewOfFile", errno) } @@ -85,22 +96,29 @@ func flush(addr, len uintptr) error { return errors.New("unknown base address") } - errno = syscall.FlushFileBuffers(handle) + errno = windows.FlushFileBuffers(handle.file) return os.NewSyscallError("FlushFileBuffers", errno) } -func lock(addr, len uintptr) error { - errno := syscall.VirtualLock(addr, len) +func (m MMap) lock() error { + addr, len := m.addrLen() + errno := windows.VirtualLock(addr, len) return os.NewSyscallError("VirtualLock", errno) } -func unlock(addr, len uintptr) error { - errno := syscall.VirtualUnlock(addr, len) +func (m MMap) unlock() error { + addr, len := m.addrLen() + errno := windows.VirtualUnlock(addr, len) return os.NewSyscallError("VirtualUnlock", errno) } -func unmap(addr, len uintptr) error { - flush(addr, len) +func (m MMap) unmap() error { + err := m.flush() + if err != nil { + return err + } + + addr := m.header().Data // Lock the UnmapViewOfFile along with the handleMap deletion. // As soon as we unmap the view, the OS is free to give the // same addr to another new map. We don't want another goroutine @@ -108,7 +126,7 @@ func unmap(addr, len uintptr) error { // we're trying to remove our old addr/handle pair. handleLock.Lock() defer handleLock.Unlock() - err := syscall.UnmapViewOfFile(addr) + err = windows.UnmapViewOfFile(addr) if err != nil { return err } @@ -120,6 +138,6 @@ func unmap(addr, len uintptr) error { } delete(handleMap, addr) - e := syscall.CloseHandle(syscall.Handle(handle)) + e := windows.CloseHandle(windows.Handle(handle.mapview)) return os.NewSyscallError("CloseHandle", e) } diff --git a/vendor/github.com/edsrzf/mmap-go/msync_netbsd.go b/vendor/github.com/edsrzf/mmap-go/msync_netbsd.go deleted file mode 100644 index a64b003e2db42..0000000000000 --- a/vendor/github.com/edsrzf/mmap-go/msync_netbsd.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2011 Evan Shaw. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package mmap - -const _SYS_MSYNC = 277 -const _MS_SYNC = 0x04 diff --git a/vendor/github.com/edsrzf/mmap-go/msync_unix.go b/vendor/github.com/edsrzf/mmap-go/msync_unix.go deleted file mode 100644 index 91ee5f40f1071..0000000000000 --- a/vendor/github.com/edsrzf/mmap-go/msync_unix.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2011 Evan Shaw. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd linux openbsd solaris - -package mmap - -import ( - "syscall" -) - -const _SYS_MSYNC = syscall.SYS_MSYNC -const _MS_SYNC = syscall.MS_SYNC diff --git a/vendor/github.com/lib/pq/.travis.sh b/vendor/github.com/lib/pq/.travis.sh index 21a526443dd3a..ebf447030be0b 100644 --- a/vendor/github.com/lib/pq/.travis.sh +++ b/vendor/github.com/lib/pq/.travis.sh @@ -70,17 +70,4 @@ postgresql_uninstall() { sudo rm -rf /var/lib/postgresql } -megacheck_install() { - # Lock megacheck version at $MEGACHECK_VERSION to prevent spontaneous - # new error messages in old code. - go get -d honnef.co/go/tools/... - git -C $GOPATH/src/honnef.co/go/tools/ checkout $MEGACHECK_VERSION - go install honnef.co/go/tools/cmd/megacheck - megacheck --version -} - -golint_install() { - go get golang.org/x/lint/golint -} - $1 diff --git a/vendor/github.com/lib/pq/.travis.yml b/vendor/github.com/lib/pq/.travis.yml index f0305809f46a8..8396f5d9d4759 100644 --- a/vendor/github.com/lib/pq/.travis.yml +++ b/vendor/github.com/lib/pq/.travis.yml @@ -1,9 +1,8 @@ language: go go: - - 1.9.x - - 1.10.x - 1.11.x + - 1.12.x - master sudo: true @@ -14,16 +13,11 @@ env: - PQGOSSLTESTS=1 - PQSSLCERTTEST_PATH=$PWD/certs - PGHOST=127.0.0.1 - - MEGACHECK_VERSION=2017.2.2 matrix: - PGVERSION=10 - PGVERSION=9.6 - PGVERSION=9.5 - PGVERSION=9.4 - - PGVERSION=9.3 - - PGVERSION=9.2 - - PGVERSION=9.1 - - PGVERSION=9.0 before_install: - ./.travis.sh postgresql_uninstall @@ -31,9 +25,9 @@ before_install: - ./.travis.sh postgresql_install - ./.travis.sh postgresql_configure - ./.travis.sh client_configure - - ./.travis.sh megacheck_install - - ./.travis.sh golint_install - go get golang.org/x/tools/cmd/goimports + - go get golang.org/x/lint/golint + - GO111MODULE=on go get honnef.co/go/tools/cmd/staticcheck@2019.2.1 before_script: - createdb pqgotest @@ -44,7 +38,7 @@ script: - > goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }' - go vet ./... - - megacheck -go 1.9 ./... + - staticcheck -go 1.11 ./... - golint ./... - PQTEST_BINARY_PARAMETERS=no go test -race -v ./... - PQTEST_BINARY_PARAMETERS=yes go test -race -v ./... diff --git a/vendor/github.com/lib/pq/buf.go b/vendor/github.com/lib/pq/buf.go index 666b0012a79ba..4b0a0a8f7e9da 100644 --- a/vendor/github.com/lib/pq/buf.go +++ b/vendor/github.com/lib/pq/buf.go @@ -66,7 +66,7 @@ func (b *writeBuf) int16(n int) { } func (b *writeBuf) string(s string) { - b.buf = append(b.buf, (s + "\000")...) + b.buf = append(append(b.buf, s...), '\000') } func (b *writeBuf) byte(c byte) { diff --git a/vendor/github.com/lib/pq/conn.go b/vendor/github.com/lib/pq/conn.go index 62551a142097d..55152b1242ce3 100644 --- a/vendor/github.com/lib/pq/conn.go +++ b/vendor/github.com/lib/pq/conn.go @@ -92,6 +92,7 @@ type Dialer interface { DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) } +// DialerContext is the context-aware dialer interface. type DialerContext interface { DialContext(ctx context.Context, network, address string) (net.Conn, error) } @@ -301,6 +302,9 @@ func (c *Connector) open(ctx context.Context) (cn *conn, err error) { err = cn.ssl(o) if err != nil { + if cn.c != nil { + cn.c.Close() + } return nil, err } @@ -546,7 +550,7 @@ func (cn *conn) Commit() (err error) { // would get the same behaviour if you issued a COMMIT in a failed // transaction, so it's also the least surprising thing to do here. if cn.txnStatus == txnStatusInFailedTransaction { - if err := cn.Rollback(); err != nil { + if err := cn.rollback(); err != nil { return err } return ErrInFailedTransaction @@ -573,7 +577,10 @@ func (cn *conn) Rollback() (err error) { return driver.ErrBadConn } defer cn.errRecover(&err) + return cn.rollback() +} +func (cn *conn) rollback() (err error) { cn.checkIsInTransaction(true) _, commandTag, err := cn.simpleExec("ROLLBACK") if err != nil { @@ -1500,6 +1507,39 @@ func QuoteIdentifier(name string) string { return `"` + strings.Replace(name, `"`, `""`, -1) + `"` } +// QuoteLiteral quotes a 'literal' (e.g. a parameter, often used to pass literal +// to DDL and other statements that do not accept parameters) to be used as part +// of an SQL statement. For example: +// +// exp_date := pq.QuoteLiteral("2023-01-05 15:00:00Z") +// err := db.Exec(fmt.Sprintf("CREATE ROLE my_user VALID UNTIL %s", exp_date)) +// +// Any single quotes in name will be escaped. Any backslashes (i.e. "\") will be +// replaced by two backslashes (i.e. "\\") and the C-style escape identifier +// that PostgreSQL provides ('E') will be prepended to the string. +func QuoteLiteral(literal string) string { + // This follows the PostgreSQL internal algorithm for handling quoted literals + // from libpq, which can be found in the "PQEscapeStringInternal" function, + // which is found in the libpq/fe-exec.c source file: + // https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/interfaces/libpq/fe-exec.c + // + // substitute any single-quotes (') with two single-quotes ('') + literal = strings.Replace(literal, `'`, `''`, -1) + // determine if the string has any backslashes (\) in it. + // if it does, replace any backslashes (\) with two backslashes (\\) + // then, we need to wrap the entire string with a PostgreSQL + // C-style escape. Per how "PQEscapeStringInternal" handles this case, we + // also add a space before the "E" + if strings.Contains(literal, `\`) { + literal = strings.Replace(literal, `\`, `\\`, -1) + literal = ` E'` + literal + `'` + } else { + // otherwise, we can just wrap the literal with a pair of single quotes + literal = `'` + literal + `'` + } + return literal +} + func md5s(s string) string { h := md5.New() h.Write([]byte(s)) diff --git a/vendor/github.com/lib/pq/encode.go b/vendor/github.com/lib/pq/encode.go index 3b0d365f2964b..a6902fae615cc 100644 --- a/vendor/github.com/lib/pq/encode.go +++ b/vendor/github.com/lib/pq/encode.go @@ -117,11 +117,10 @@ func textDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interfa } return i case oid.T_float4, oid.T_float8: - bits := 64 - if typ == oid.T_float4 { - bits = 32 - } - f, err := strconv.ParseFloat(string(s), bits) + // We always use 64 bit parsing, regardless of whether the input text is for + // a float4 or float8, because clients expect float64s for all float datatypes + // and returning a 32-bit parsed float64 produces lossy results. + f, err := strconv.ParseFloat(string(s), 64) if err != nil { errorf("%s", err) } diff --git a/vendor/github.com/lib/pq/error.go b/vendor/github.com/lib/pq/error.go index 96aae29c6579d..3d66ba7c52e50 100644 --- a/vendor/github.com/lib/pq/error.go +++ b/vendor/github.com/lib/pq/error.go @@ -478,13 +478,13 @@ func errRecoverNoErrBadConn(err *error) { } } -func (c *conn) errRecover(err *error) { +func (cn *conn) errRecover(err *error) { e := recover() switch v := e.(type) { case nil: // Do nothing case runtime.Error: - c.bad = true + cn.bad = true panic(v) case *Error: if v.Fatal() { @@ -493,7 +493,7 @@ func (c *conn) errRecover(err *error) { *err = v } case *net.OpError: - c.bad = true + cn.bad = true *err = v case error: if v == io.EOF || v.(error).Error() == "remote error: handshake failure" { @@ -503,13 +503,13 @@ func (c *conn) errRecover(err *error) { } default: - c.bad = true + cn.bad = true panic(fmt.Sprintf("unknown error: %#v", e)) } // Any time we return ErrBadConn, we need to remember it since *Tx doesn't // mark the connection bad in database/sql. if *err == driver.ErrBadConn { - c.bad = true + cn.bad = true } } diff --git a/vendor/github.com/lib/pq/scram/scram.go b/vendor/github.com/lib/pq/scram/scram.go index 5d0358f8ffb5d..484f378a7604a 100644 --- a/vendor/github.com/lib/pq/scram/scram.go +++ b/vendor/github.com/lib/pq/scram/scram.go @@ -22,7 +22,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Pacakage scram implements a SCRAM-{SHA-1,etc} client per RFC5802. +// Package scram implements a SCRAM-{SHA-1,etc} client per RFC5802. // // http://tools.ietf.org/html/rfc5802 // diff --git a/vendor/github.com/mattn/go-sqlite3/.travis.yml b/vendor/github.com/mattn/go-sqlite3/.travis.yml index 2ae08beb4dacb..eb0abbbbea935 100644 --- a/vendor/github.com/mattn/go-sqlite3/.travis.yml +++ b/vendor/github.com/mattn/go-sqlite3/.travis.yml @@ -8,34 +8,24 @@ addons: apt: update: true -env: - matrix: - - GOTAGS= - - GOTAGS=libsqlite3 - - GOTAGS="sqlite_allow_uri_authority sqlite_app_armor sqlite_foreign_keys sqlite_fts5 sqlite_icu sqlite_introspect sqlite_json sqlite_secure_delete sqlite_see sqlite_stat4 sqlite_trace sqlite_userauth sqlite_vacuum_incr sqlite_vtable sqlite_unlock_notify" - - GOTAGS=sqlite_vacuum_full - go: - 1.9.x - 1.10.x - 1.11.x + - master before_install: - | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update fi - - | - go get github.com/smartystreets/goconvey - if [[ "${GOOS}" != "windows" ]]; then - go get github.com/mattn/goveralls - go get golang.org/x/tools/cmd/cover - fi + - go get github.com/smartystreets/goconvey + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover script: - - GOOS=$(go env GOOS) GOARCH=$(go env GOARCH) go build -v -tags "${GOTAGS}" . - - | - if [[ "${GOOS}" != "windows" ]]; then - $HOME/gopath/bin/goveralls -repotoken 3qJVUE0iQwqnCbmNcDsjYu1nh4J4KIFXx - go test -race -v . -tags "${GOTAGS}" - fi + - $HOME/gopath/bin/goveralls -repotoken 3qJVUE0iQwqnCbmNcDsjYu1nh4J4KIFXx + - go test -race -v . -tags "" + - go test -race -v . -tags "libsqlite3" + - go test -race -v . -tags "sqlite_allow_uri_authority sqlite_app_armor sqlite_foreign_keys sqlite_fts5 sqlite_icu sqlite_introspect sqlite_json sqlite_secure_delete sqlite_see sqlite_stat4 sqlite_trace sqlite_userauth sqlite_vacuum_incr sqlite_vtable sqlite_unlock_notify" + - go test -race -v . -tags "sqlite_vacuum_full" \ No newline at end of file diff --git a/vendor/github.com/mattn/go-sqlite3/README.md b/vendor/github.com/mattn/go-sqlite3/README.md index 207f1cd1eb9ee..8a87941e4052f 100644 --- a/vendor/github.com/mattn/go-sqlite3/README.md +++ b/vendor/github.com/mattn/go-sqlite3/README.md @@ -10,9 +10,7 @@ go-sqlite3 sqlite3 driver conforming to the built-in database/sql interface -Supported Golang version: -- 1.9.x -- 1.10.x +Supported Golang version: See .travis.yml [This package follows the official Golang Release Policy.](https://golang.org/doc/devel/release.html#policy) @@ -249,7 +247,7 @@ Required dependency brew install sqlite3 ``` -For OSX there is an additional package install which is required if you whish to build the `icu` extension. +For OSX there is an additional package install which is required if you wish to build the `icu` extension. This additional package can be installed with `homebrew`. @@ -282,7 +280,7 @@ To compile this package on Windows OS you must have the `gcc` compiler installed 3) Open a terminal for the TDM-GCC toolchain, can be found in the Windows Start menu. 4) Navigate to your project folder and run the `go build ...` command for this package. -For example the TDM-GCC Toolchain can be found [here](ttps://sourceforge.net/projects/tdm-gcc/). +For example the TDM-GCC Toolchain can be found [here](https://sourceforge.net/projects/tdm-gcc/). ## Errors @@ -458,15 +456,19 @@ For an example see [shaxbee/go-spatialite](https://github.com/shaxbee/go-spatial Why is it racy if I use a `sql.Open("sqlite3", ":memory:")` database? - Each connection to :memory: opens a brand new in-memory sql database, so if + Each connection to `":memory:"` opens a brand new in-memory sql database, so if the stdlib's sql engine happens to open another connection and you've only - specified ":memory:", that connection will see a brand new database. A - workaround is to use "file::memory:?mode=memory&cache=shared". Every - connection to this string will point to the same in-memory database. + specified `":memory:"`, that connection will see a brand new database. A + workaround is to use `"file::memory:?cache=shared"` (or `"file:foobar?mode=memory&cache=shared"`). Every + connection to this string will point to the same in-memory database. + + Note that if the last database connection in the pool closes, the in-memory database is deleted. Make sure the [max idle connection limit](https://golang.org/pkg/database/sql/#DB.SetMaxIdleConns) is > 0, and the [connection lifetime](https://golang.org/pkg/database/sql/#DB.SetConnMaxLifetime) is infinite. For more information see * [#204](https://github.com/mattn/go-sqlite3/issues/204) * [#511](https://github.com/mattn/go-sqlite3/issues/511) + * https://www.sqlite.org/sharedcache.html#shared_cache_and_in_memory_databases + * https://www.sqlite.org/inmemorydb.html#sharedmemdb - Reading from database with large amount of goroutines fails on OSX. @@ -481,11 +483,11 @@ For an example see [shaxbee/go-spatialite](https://github.com/shaxbee/go-spatial You need to implement the feature or call the sqlite3 cli. - More infomation see [#305](https://github.com/mattn/go-sqlite3/issues/305) + More information see [#305](https://github.com/mattn/go-sqlite3/issues/305) - Error: `database is locked` - When you get an database is locked. Please use the following options. + When you get a database is locked. Please use the following options. Add to DSN: `cache=shared` @@ -497,7 +499,7 @@ For an example see [shaxbee/go-spatialite](https://github.com/shaxbee/go-spatial Second please set the database connections of the SQL package to 1. ```go - db.SetMaxOpenConn(1) + db.SetMaxOpenConns(1) ``` More information see [#209](https://github.com/mattn/go-sqlite3/issues/209) diff --git a/vendor/github.com/mattn/go-sqlite3/callback.go b/vendor/github.com/mattn/go-sqlite3/callback.go index 2c68973b8555c..e8c492b361d7a 100644 --- a/vendor/github.com/mattn/go-sqlite3/callback.go +++ b/vendor/github.com/mattn/go-sqlite3/callback.go @@ -368,7 +368,7 @@ func callbackRet(typ reflect.Type) (callbackRetConverter, error) { func callbackError(ctx *C.sqlite3_context, err error) { cstr := C.CString(err.Error()) defer C.free(unsafe.Pointer(cstr)) - C.sqlite3_result_error(ctx, cstr, -1) + C.sqlite3_result_error(ctx, cstr, C.int(-1)) } // Test support code. Tests are not allowed to import "C", so we can't diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c index 7763197505219..140d096a88047 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c @@ -1,7 +1,7 @@ #ifndef USE_LIBSQLITE3 /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.25.2. By combining all the individual C code files into this +** version 3.29.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -40,7 +40,7 @@ ** SQLite was built with. */ -#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */ /* ** Include the configuration header output by 'configure' if we're using the @@ -261,6 +261,9 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_ENABLE_FTS5 "ENABLE_FTS5", #endif +#if SQLITE_ENABLE_GEOPOLY + "ENABLE_GEOPOLY", +#endif #if SQLITE_ENABLE_HIDDEN_COLUMNS "ENABLE_HIDDEN_COLUMNS", #endif @@ -291,6 +294,9 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_ENABLE_MULTIPLEX "ENABLE_MULTIPLEX", #endif +#if SQLITE_ENABLE_NORMALIZE + "ENABLE_NORMALIZE", +#endif #if SQLITE_ENABLE_NULL_TRIM "ENABLE_NULL_TRIM", #endif @@ -883,6 +889,11 @@ SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){ #pragma warning(disable : 4706) #endif /* defined(_MSC_VER) */ +#if defined(_MSC_VER) && !defined(_WIN64) +#undef SQLITE_4_BYTE_ALIGNED_MALLOC +#define SQLITE_4_BYTE_ALIGNED_MALLOC +#endif /* defined(_MSC_VER) && !defined(_WIN64) */ + #endif /* SQLITE_MSVC_H */ /************** End of msvc.h ************************************************/ @@ -1157,9 +1168,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.25.2" -#define SQLITE_VERSION_NUMBER 3025002 -#define SQLITE_SOURCE_ID "2018-09-25 19:08:10 fb90e7189ae6d62e77ba3a308ca5d683f90bbe633cf681865365b8e92792d1c7" +#define SQLITE_VERSION "3.29.0" +#define SQLITE_VERSION_NUMBER 3029000 +#define SQLITE_SOURCE_ID "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88bfa6" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -1223,6 +1234,9 @@ SQLITE_API int sqlite3_libversion_number(void); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_API int sqlite3_compileoption_used(const char *zOptName); SQLITE_API const char *sqlite3_compileoption_get(int N); +#else +# define sqlite3_compileoption_used(X) 0 +# define sqlite3_compileoption_get(X) ((void*)0) #endif /* @@ -1857,6 +1871,15 @@ struct sqlite3_io_methods { ** file space based on this hint in order to help writes to the database ** file run faster. ** +**
  • [[SQLITE_FCNTL_SIZE_LIMIT]] +** The [SQLITE_FCNTL_SIZE_LIMIT] opcode is used by in-memory VFS that +** implements [sqlite3_deserialize()] to set an upper bound on the size +** of the in-memory database. The argument is a pointer to a [sqlite3_int64]. +** If the integer pointed to is negative, then it is filled in with the +** current limit. Otherwise the limit is set to the larger of the value +** of the integer pointed to and the current database size. The integer +** pointed to is set to the new limit. +** **
  • [[SQLITE_FCNTL_CHUNK_SIZE]] ** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS ** extends and truncates the database file in chunks of a size specified @@ -2165,6 +2188,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 #define SQLITE_FCNTL_LOCK_TIMEOUT 34 #define SQLITE_FCNTL_DATA_VERSION 35 +#define SQLITE_FCNTL_SIZE_LIMIT 36 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -2317,8 +2341,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] -** to test whether a file is at least readable. The file can be a -** directory. +** to test whether a file is at least readable. The SQLITE_ACCESS_READ +** flag is never actually used and is not implemented in the built-in +** VFSes of SQLite. The file is named by the second argument and can be a +** directory. The xAccess method returns [SQLITE_OK] on success or some +** non-zero error code if there is an I/O error or if the name of +** the file given in the second argument is illegal. If SQLITE_OK +** is returned, then non-zero or zero is written into *pResOut to indicate +** whether or not the file is accessible. ** ** ^SQLite will always allocate at least mxPathname+1 bytes for the ** output buffer xFullPathname. The exact size of the output buffer @@ -3006,6 +3036,17 @@ struct sqlite3_mem_methods { ** negative value for this option restores the default behaviour. ** This option is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. +** +** [[SQLITE_CONFIG_MEMDB_MAXSIZE]] +**
    SQLITE_CONFIG_MEMDB_MAXSIZE +**
    The SQLITE_CONFIG_MEMDB_MAXSIZE option accepts a single parameter +** [sqlite3_int64] parameter which is the default maximum size for an in-memory +** database created using [sqlite3_deserialize()]. This default maximum +** size can be adjusted up or down for individual databases using the +** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this +** configuration setting is never used, then the default maximum is determined +** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that +** compile-time option is not set, then the default maximum is 1073741824. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -3036,6 +3077,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ +#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ /* ** CAPI3REF: Database Connection Configuration Options @@ -3051,6 +3093,7 @@ struct sqlite3_mem_methods { ** is invoked. ** **
    +** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    **
    ^This option takes three additional arguments that determine the ** [lookaside memory allocator] configuration for the [database connection]. @@ -3073,6 +3116,7 @@ struct sqlite3_mem_methods { ** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^
    ** +** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **
    SQLITE_DBCONFIG_ENABLE_FKEY
    **
    ^This option is used to enable or disable the enforcement of ** [foreign key constraints]. There should be two additional arguments. @@ -3083,6 +3127,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the FK enforcement setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_TRIGGER]] **
    SQLITE_DBCONFIG_ENABLE_TRIGGER
    **
    ^This option is used to enable or disable [CREATE TRIGGER | triggers]. ** There should be two additional arguments. @@ -3093,9 +3138,10 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the trigger setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] **
    SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
    -**
    ^This option is used to enable or disable the two-argument -** version of the [fts3_tokenizer()] function which is part of the +**
    ^This option is used to enable or disable the +** [fts3_tokenizer()] function which is part of the ** [FTS3] full-text search engine extension. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable fts3_tokenizer() or @@ -3106,6 +3152,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the new setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]] **
    SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
    **
    ^This option is used to enable or disable the [sqlite3_load_extension()] ** interface independently of the [load_extension()] SQL function. @@ -3123,7 +3170,7 @@ struct sqlite3_mem_methods { ** be a NULL pointer, in which case the new setting is not reported back. **
    ** -**
    SQLITE_DBCONFIG_MAINDBNAME
    +** [[SQLITE_DBCONFIG_MAINDBNAME]]
    SQLITE_DBCONFIG_MAINDBNAME
    **
    ^This option is used to change the name of the "main" database ** schema. ^The sole argument is a pointer to a constant UTF8 string ** which will become the new schema name in place of "main". ^SQLite @@ -3132,6 +3179,7 @@ struct sqlite3_mem_methods { ** until after the database connection closes. **
    ** +** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] **
    SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
    **
    Usually, when a database in wal mode is closed or detached from a ** database handle, SQLite checks if this will mean that there are now no @@ -3145,7 +3193,7 @@ struct sqlite3_mem_methods { ** have been disabled - 0 if they are not disabled, 1 if they are. **
    ** -**
    SQLITE_DBCONFIG_ENABLE_QPSG
    +** [[SQLITE_DBCONFIG_ENABLE_QPSG]]
    SQLITE_DBCONFIG_ENABLE_QPSG
    **
    ^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates ** the [query planner stability guarantee] (QPSG). When the QPSG is active, ** a single SQL query statement will always use the same algorithm regardless @@ -3161,7 +3209,7 @@ struct sqlite3_mem_methods { ** following this call. **
    ** -**
    SQLITE_DBCONFIG_TRIGGER_EQP
    +** [[SQLITE_DBCONFIG_TRIGGER_EQP]]
    SQLITE_DBCONFIG_TRIGGER_EQP
    **
    By default, the output of EXPLAIN QUERY PLAN commands does not ** include output for any operations performed by trigger programs. This ** option is used to set or clear (the default) a flag that governs this @@ -3173,7 +3221,7 @@ struct sqlite3_mem_methods { ** it is not disabled, 1 if it is. **
    ** -**
    SQLITE_DBCONFIG_RESET_DATABASE
    +** [[SQLITE_DBCONFIG_RESET_DATABASE]]
    SQLITE_DBCONFIG_RESET_DATABASE
    **
    Set the SQLITE_DBCONFIG_RESET_DATABASE flag and then run ** [VACUUM] in order to reset a database back to an empty database ** with no schema and no content. The following process works even for @@ -3192,6 +3240,58 @@ struct sqlite3_mem_methods { ** Because resetting a database is destructive and irreversible, the ** process requires the use of this obscure API and multiple steps to help ** ensure that it does not happen by accident. +** +** [[SQLITE_DBCONFIG_DEFENSIVE]]
    SQLITE_DBCONFIG_DEFENSIVE
    +**
    The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the +** "defensive" flag for a database connection. When the defensive +** flag is enabled, language features that allow ordinary SQL to +** deliberately corrupt the database file are disabled. The disabled +** features include but are not limited to the following: +**
      +**
    • The [PRAGMA writable_schema=ON] statement. +**
    • The [PRAGMA journal_mode=OFF] statement. +**
    • Writes to the [sqlite_dbpage] virtual table. +**
    • Direct writes to [shadow tables]. +**
    +**
    +** +** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]]
    SQLITE_DBCONFIG_WRITABLE_SCHEMA
    +**
    The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the +** "writable_schema" flag. This has the same effect and is logically equivalent +** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF]. +** The first argument to this setting is an integer which is 0 to disable +** the writable_schema, positive to enable writable_schema, or negative to +** leave the setting unchanged. The second parameter is a pointer to an +** integer into which is written 0 or 1 to indicate whether the writable_schema +** is enabled or disabled following this call. +**
    +** +** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]] +**
    SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
    +**
    The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates +** the legacy behavior of the [ALTER TABLE RENAME] command such it +** behaves as it did prior to [version 3.24.0] (2018-06-04). See the +** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for +** additional information. This feature can also be turned on and off +** using the [PRAGMA legacy_alter_table] statement. +**
    +** +** [[SQLITE_DBCONFIG_DQS_DML]] +**
    SQLITE_DBCONFIG_DQS_DML +**
    The SQLITE_DBCONFIG_DQS_DML option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DML statement +** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. +**
    +** +** [[SQLITE_DBCONFIG_DQS_DDL]] +**
    SQLITE_DBCONFIG_DQS_DDL +**
    The SQLITE_DBCONFIG_DQS option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DDL statements, +** such as CREATE TABLE and CREATE INDEX. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. **
    **
    */ @@ -3205,7 +3305,12 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ #define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ #define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1009 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ +#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ +#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1014 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -3362,7 +3467,7 @@ SQLITE_API int sqlite3_changes(sqlite3*); ** not. ^Changes to a view that are intercepted by INSTEAD OF triggers ** are not counted. ** -** This the [sqlite3_total_changes(D)] interface only reports the number +** The [sqlite3_total_changes(D)] interface only reports the number ** of rows that changed due to SQL statement run against database ** connection D. Any changes by other database connections are ignored. ** To detect changes against a database file from other database @@ -4006,9 +4111,9 @@ SQLITE_API int sqlite3_set_authorizer( ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite -** might provide greater resolution on the profiler callback. The -** sqlite3_profile() function is considered experimental and is -** subject to change in future versions of SQLite. +** might provide greater resolution on the profiler callback. Invoking +** either [sqlite3_trace()] or [sqlite3_trace_v2()] will cancel the +** profile callback. */ SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); @@ -4422,6 +4527,8 @@ SQLITE_API int sqlite3_open_v2( ** is not a database file pathname pointer that SQLite passed into the xOpen ** VFS method, then the behavior of this routine is undefined and probably ** undesirable. +** +** See the [URI filename] documentation for additional information. */ SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); @@ -4643,9 +4750,24 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** on this hint by avoiding the use of [lookaside memory] so as not to ** deplete the limited store of lookaside memory. Future versions of ** SQLite may act on this hint differently. +** +** [[SQLITE_PREPARE_NORMALIZE]]
    SQLITE_PREPARE_NORMALIZE
    +**
    The SQLITE_PREPARE_NORMALIZE flag is a no-op. This flag used +** to be required for any prepared statement that wanted to use the +** [sqlite3_normalized_sql()] interface. However, the +** [sqlite3_normalized_sql()] interface is now available to all +** prepared statements, regardless of whether or not they use this +** flag. +** +** [[SQLITE_PREPARE_NO_VTAB]]
    SQLITE_PREPARE_NO_VTAB
    +**
    The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler +** to return an error (error code SQLITE_ERROR) if the statement uses +** any virtual tables. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 +#define SQLITE_PREPARE_NORMALIZE 0x02 +#define SQLITE_PREPARE_NO_VTAB 0x04 /* ** CAPI3REF: Compiling An SQL Statement @@ -4803,6 +4925,11 @@ SQLITE_API int sqlite3_prepare16_v3( ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 ** string containing the SQL text of prepared statement P with ** [bound parameters] expanded. +** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8 +** string containing the normalized SQL text of prepared statement P. The +** semantics used to normalize a SQL statement are unspecified and subject +** to change. At a minimum, literal values will be replaced with suitable +** placeholders. ** ** ^(For example, if a prepared statement is created using the SQL ** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 @@ -4818,14 +4945,16 @@ SQLITE_API int sqlite3_prepare16_v3( ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time ** option causes sqlite3_expanded_sql() to always return NULL. ** -** ^The string returned by sqlite3_sql(P) is managed by SQLite and is -** automatically freed when the prepared statement is finalized. +** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) +** are managed by SQLite and are automatically freed when the prepared +** statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, ** is obtained from [sqlite3_malloc()] and must be free by the application ** by passing it to [sqlite3_free()]. */ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); +SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database @@ -4863,6 +4992,18 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); */ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); +/* +** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement +** METHOD: sqlite3_stmt +** +** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the +** prepared statement S is an EXPLAIN statement, or 2 if the +** statement S is an EXPLAIN QUERY PLAN. +** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is +** an ordinary statement or a NULL pointer. +*/ +SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); + /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt @@ -5002,7 +5143,9 @@ typedef struct sqlite3_context sqlite3_context; ** ^The fifth argument to the BLOB and string binding interfaces ** is a destructor used to dispose of the BLOB or ** string after SQLite has finished with it. ^The destructor is called -** to dispose of the BLOB or string even if the call to bind API fails. +** to dispose of the BLOB or string even if the call to the bind API fails, +** except the destructor is not called if the third parameter is a NULL +** pointer or the fourth parameter is negative. ** ^If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. @@ -5919,6 +6062,8 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** sqlite3_value_nochange   ** →  True if the column is unchanged in an UPDATE ** against a virtual table. +** sqlite3_value_frombind   +** →  True if value originated from a [bound parameter] ** ** ** Details: @@ -5980,6 +6125,11 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** than within an [xUpdate] method call for an UPDATE statement, then ** the return value is arbitrary and meaningless. ** +** ^The sqlite3_value_frombind(X) interface returns non-zero if the +** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] +** interfaces. ^If X comes from an SQL literal value, or a table column, +** and expression, then sqlite3_value_frombind(X) returns zero. +** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to @@ -6025,6 +6175,7 @@ SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); +SQLITE_API int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values @@ -6760,7 +6911,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); ** associated with database N of connection D. ^The main database file ** has the name "main". If there is no attached database N on the database ** connection D, or if database N is a temporary or in-memory database, then -** a NULL pointer is returned. +** this function will return either a NULL pointer or an empty string. ** ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename @@ -7315,6 +7466,9 @@ struct sqlite3_module { int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); + /* The methods above are in versions 1 and 2 of the sqlite_module object. + ** Those below are for version 3 and greater. */ + int (*xShadowName)(const char*); }; /* @@ -8237,6 +8391,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ +#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 @@ -8247,7 +8402,8 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_SORTER_MMAP 24 #define SQLITE_TESTCTRL_IMPOSTER 25 #define SQLITE_TESTCTRL_PARSER_COVERAGE 26 -#define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_RESULT_INTREAL 27 +#define SQLITE_TESTCTRL_LAST 27 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -9649,6 +9805,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** can use to customize and optimize their behavior. ** **
    +** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]] **
    SQLITE_VTAB_CONSTRAINT_SUPPORT **
    Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, @@ -10418,7 +10575,7 @@ struct sqlite3_rtree_query_info { sqlite3_int64 iRowid; /* Rowid for current entry */ sqlite3_rtree_dbl rParentScore; /* Score of parent node */ int eParentWithin; /* Visibility of parent node */ - int eWithin; /* OUT: Visiblity */ + int eWithin; /* OUT: Visibility */ sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ /* The following fields are only available in 3.8.11 and later */ sqlite3_value **apSqlParam; /* Original SQL values of parameters */ @@ -10914,12 +11071,38 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); ** consecutively. There is no chance that the iterator will visit a change ** the applies to table X, then one for table Y, and then later on visit ** another change for table X. +** +** The behavior of sqlite3changeset_start_v2() and its streaming equivalent +** may be modified by passing a combination of +** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter. +** +** Note that the sqlite3changeset_start_v2() API is still experimental +** and therefore subject to change. */ SQLITE_API int sqlite3changeset_start( sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset /* Pointer to blob containing changeset */ ); +SQLITE_API int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset, /* Pointer to blob containing changeset */ + int flags /* SESSION_CHANGESETSTART_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3changeset_start_v2 +** +** The following flags may passed via the 4th parameter to +** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: +** +**
    SQLITE_CHANGESETAPPLY_INVERT
    +** Invert the changeset while iterating through it. This is equivalent to +** inverting a changeset using sqlite3changeset_invert() before applying it. +** It is an error to specify this flag with a patchset. +*/ +#define SQLITE_CHANGESETSTART_INVERT 0x0002 /* @@ -10963,7 +11146,7 @@ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); ** sqlite3changeset_next() is called on the iterator or until the ** conflict-handler function returns. If pnCol is not NULL, then *pnCol is ** set to the number of columns in the table affected by the change. If -** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change +** pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change ** is an indirect change, or false (0) otherwise. See the documentation for ** [sqlite3session_indirect()] for a description of direct and indirect ** changes. Finally, if pOp is not NULL, then *pOp is set to one of @@ -11574,7 +11757,7 @@ SQLITE_API int sqlite3changeset_apply_v2( ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, /* OUT: Rebase data */ - int flags /* Combination of SESSION_APPLY_* flags */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ ); /* @@ -11592,8 +11775,14 @@ SQLITE_API int sqlite3changeset_apply_v2( ** causes the sessions module to omit this savepoint. In this case, if the ** caller has an open transaction or savepoint when apply_v2() is called, ** it may revert the partially applied changeset by rolling it back. +** +**
    SQLITE_CHANGESETAPPLY_INVERT
    +** Invert the changeset before applying it. This is equivalent to inverting +** a changeset using sqlite3changeset_invert() before applying it. It is +** an error to specify this flag with a patchset. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 +#define SQLITE_CHANGESETAPPLY_INVERT 0x0002 /* ** CAPI3REF: Constants Passed To The Conflict Handler @@ -11824,7 +12013,7 @@ SQLITE_API int sqlite3rebaser_configure( ** in size. This function allocates and populates a buffer with a copy ** of the changeset rebased rebased according to the configuration of the ** rebaser object passed as the first argument. If successful, (*ppOut) -** is set to point to the new buffer containing the rebased changset and +** is set to point to the new buffer containing the rebased changeset and ** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the ** responsibility of the caller to eventually free the new buffer using ** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut) @@ -11987,6 +12176,12 @@ SQLITE_API int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); +SQLITE_API int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +); SQLITE_API int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), @@ -12013,6 +12208,45 @@ SQLITE_API int sqlite3rebaser_rebase_strm( void *pOut ); +/* +** CAPI3REF: Configure global parameters +** +** The sqlite3session_config() interface is used to make global configuration +** changes to the sessions module in order to tune it to the specific needs +** of the application. +** +** The sqlite3session_config() interface is not threadsafe. If it is invoked +** while any other thread is inside any other sessions method then the +** results are undefined. Furthermore, if it is invoked after any sessions +** related objects have been created, the results are also undefined. +** +** The first argument to the sqlite3session_config() function must be one +** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The +** interpretation of the (void*) value passed as the second parameter and +** the effect of calling this function depends on the value of the first +** parameter. +** +**
    +**
    SQLITE_SESSION_CONFIG_STRMSIZE
    +** By default, the sessions module streaming interfaces attempt to input +** and output data in approximately 1 KiB chunks. This operand may be used +** to set and query the value of this configuration setting. The pointer +** passed as the second argument must point to a value of type (int). +** If this value is greater than 0, it is used as the new streaming data +** chunk size for both input and output. Before returning, the (int) value +** pointed to by pArg is set to the final value of the streaming interface +** chunk size. +**
    +** +** This function returns SQLITE_OK if successful, or an SQLite error code +** otherwise. +*/ +SQLITE_API int sqlite3session_config(int op, void *pArg); + +/* +** CAPI3REF: Values for sqlite3session_config(). +*/ +#define SQLITE_SESSION_CONFIG_STRMSIZE 1 /* ** Make sure we can call this stuff from C++. @@ -12146,12 +12380,8 @@ struct Fts5PhraseIter { ** ** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. The exception is if the table was created -** with the offsets=0 option specified. In this case *piOff is always -** set to -1. -** -** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) -** if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. @@ -12192,7 +12422,7 @@ struct Fts5PhraseIter { ** Save the pointer passed as the second argument as the extension functions ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of -** of the same MATCH query using the xGetAuxdata() API. +** the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for ** each FTS query (MATCH expression). If the extension function is invoked @@ -12207,7 +12437,7 @@ struct Fts5PhraseIter { ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** -** If an error (e.g. an OOM condition) occurs within this function, an +** If an error (e.g. an OOM condition) occurs within this function, ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. @@ -12440,11 +12670,11 @@ struct Fts5ExtensionApi { ** the tokenizer substitutes "first" for "1st" and the query works ** as expected. ** -**
  • By adding multiple synonyms for a single term to the FTS index. -** In this case, when tokenizing query text, the tokenizer may -** provide multiple synonyms for a single term within the document. -** FTS5 then queries the index for each synonym individually. For -** example, faced with the query: +**
  • By querying the index for all synonyms of each query term +** separately. In this case, when tokenizing query text, the +** tokenizer may provide multiple synonyms for a single term +** within the document. FTS5 then queries the index for each +** synonym individually. For example, faced with the query: ** ** ** ... MATCH 'first place' @@ -12468,7 +12698,7 @@ struct Fts5ExtensionApi { ** "place". ** ** This way, even if the tokenizer does not provide synonyms -** when tokenizing query text (it should not - to do would be +** when tokenizing query text (it should not - to do so would be ** inefficient), it doesn't matter if the user queries for ** 'first + place' or '1st + place', as there are entries in the ** FTS index corresponding to both forms of the first token. @@ -13233,7 +13463,7 @@ struct Hash { unsigned int count; /* Number of entries in this table */ HashElem *first; /* The first element of the array */ struct _ht { /* the hash table */ - int count; /* Number of entries with this hash */ + unsigned int count; /* Number of entries with this hash */ HashElem *chain; /* Pointer to first entry with this hash */ } *ht; }; @@ -13374,99 +13604,94 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_PRECEDING 85 #define TK_RANGE 86 #define TK_UNBOUNDED 87 -#define TK_REINDEX 88 -#define TK_RENAME 89 -#define TK_CTIME_KW 90 -#define TK_ANY 91 -#define TK_BITAND 92 -#define TK_BITOR 93 -#define TK_LSHIFT 94 -#define TK_RSHIFT 95 -#define TK_PLUS 96 -#define TK_MINUS 97 -#define TK_STAR 98 -#define TK_SLASH 99 -#define TK_REM 100 -#define TK_CONCAT 101 -#define TK_COLLATE 102 -#define TK_BITNOT 103 -#define TK_ON 104 -#define TK_INDEXED 105 -#define TK_STRING 106 -#define TK_JOIN_KW 107 -#define TK_CONSTRAINT 108 -#define TK_DEFAULT 109 -#define TK_NULL 110 -#define TK_PRIMARY 111 -#define TK_UNIQUE 112 -#define TK_CHECK 113 -#define TK_REFERENCES 114 -#define TK_AUTOINCR 115 -#define TK_INSERT 116 -#define TK_DELETE 117 -#define TK_UPDATE 118 -#define TK_SET 119 -#define TK_DEFERRABLE 120 -#define TK_FOREIGN 121 -#define TK_DROP 122 -#define TK_UNION 123 -#define TK_ALL 124 -#define TK_EXCEPT 125 -#define TK_INTERSECT 126 -#define TK_SELECT 127 -#define TK_VALUES 128 -#define TK_DISTINCT 129 -#define TK_DOT 130 -#define TK_FROM 131 -#define TK_JOIN 132 -#define TK_USING 133 -#define TK_ORDER 134 -#define TK_GROUP 135 -#define TK_HAVING 136 -#define TK_LIMIT 137 -#define TK_WHERE 138 -#define TK_INTO 139 -#define TK_NOTHING 140 -#define TK_FLOAT 141 -#define TK_BLOB 142 -#define TK_INTEGER 143 -#define TK_VARIABLE 144 -#define TK_CASE 145 -#define TK_WHEN 146 -#define TK_THEN 147 -#define TK_ELSE 148 -#define TK_INDEX 149 -#define TK_ALTER 150 -#define TK_ADD 151 -#define TK_WINDOW 152 -#define TK_OVER 153 -#define TK_FILTER 154 -#define TK_TRUEFALSE 155 -#define TK_ISNOT 156 -#define TK_FUNCTION 157 -#define TK_COLUMN 158 -#define TK_AGG_FUNCTION 159 -#define TK_AGG_COLUMN 160 -#define TK_UMINUS 161 -#define TK_UPLUS 162 -#define TK_TRUTH 163 -#define TK_REGISTER 164 -#define TK_VECTOR 165 -#define TK_SELECT_COLUMN 166 -#define TK_IF_NULL_ROW 167 -#define TK_ASTERISK 168 -#define TK_SPAN 169 -#define TK_END_OF_FILE 170 -#define TK_UNCLOSED_STRING 171 -#define TK_SPACE 172 -#define TK_ILLEGAL 173 - -/* The token codes above must all fit in 8 bits */ -#define TKFLG_MASK 0xff - -/* Flags that can be added to a token code when it is not -** being stored in a u8: */ -#define TKFLG_DONTFOLD 0x100 /* Omit constant folding optimizations */ +#define TK_EXCLUDE 88 +#define TK_GROUPS 89 +#define TK_OTHERS 90 +#define TK_TIES 91 +#define TK_REINDEX 92 +#define TK_RENAME 93 +#define TK_CTIME_KW 94 +#define TK_ANY 95 +#define TK_BITAND 96 +#define TK_BITOR 97 +#define TK_LSHIFT 98 +#define TK_RSHIFT 99 +#define TK_PLUS 100 +#define TK_MINUS 101 +#define TK_STAR 102 +#define TK_SLASH 103 +#define TK_REM 104 +#define TK_CONCAT 105 +#define TK_COLLATE 106 +#define TK_BITNOT 107 +#define TK_ON 108 +#define TK_INDEXED 109 +#define TK_STRING 110 +#define TK_JOIN_KW 111 +#define TK_CONSTRAINT 112 +#define TK_DEFAULT 113 +#define TK_NULL 114 +#define TK_PRIMARY 115 +#define TK_UNIQUE 116 +#define TK_CHECK 117 +#define TK_REFERENCES 118 +#define TK_AUTOINCR 119 +#define TK_INSERT 120 +#define TK_DELETE 121 +#define TK_UPDATE 122 +#define TK_SET 123 +#define TK_DEFERRABLE 124 +#define TK_FOREIGN 125 +#define TK_DROP 126 +#define TK_UNION 127 +#define TK_ALL 128 +#define TK_EXCEPT 129 +#define TK_INTERSECT 130 +#define TK_SELECT 131 +#define TK_VALUES 132 +#define TK_DISTINCT 133 +#define TK_DOT 134 +#define TK_FROM 135 +#define TK_JOIN 136 +#define TK_USING 137 +#define TK_ORDER 138 +#define TK_GROUP 139 +#define TK_HAVING 140 +#define TK_LIMIT 141 +#define TK_WHERE 142 +#define TK_INTO 143 +#define TK_NOTHING 144 +#define TK_FLOAT 145 +#define TK_BLOB 146 +#define TK_INTEGER 147 +#define TK_VARIABLE 148 +#define TK_CASE 149 +#define TK_WHEN 150 +#define TK_THEN 151 +#define TK_ELSE 152 +#define TK_INDEX 153 +#define TK_ALTER 154 +#define TK_ADD 155 +#define TK_WINDOW 156 +#define TK_OVER 157 +#define TK_FILTER 158 +#define TK_TRUEFALSE 159 +#define TK_ISNOT 160 +#define TK_FUNCTION 161 +#define TK_COLUMN 162 +#define TK_AGG_FUNCTION 163 +#define TK_AGG_COLUMN 164 +#define TK_UMINUS 165 +#define TK_UPLUS 166 +#define TK_TRUTH 167 +#define TK_REGISTER 168 +#define TK_VECTOR 169 +#define TK_SELECT_COLUMN 170 +#define TK_IF_NULL_ROW 171 +#define TK_ASTERISK 172 +#define TK_SPAN 173 +#define TK_SPACE 174 +#define TK_ILLEGAL 175 /************** End of parse.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -13772,12 +13997,13 @@ typedef INT16_TYPE LogEst; ** at run-time. */ #ifndef SQLITE_BYTEORDER -# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ - defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ - defined(__arm__) || defined(_M_ARM64) +# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ + defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64) # define SQLITE_BYTEORDER 1234 -# elif defined(sparc) || defined(__ppc__) +# elif defined(sparc) || defined(__ppc__) || \ + defined(__ARMEB__) || defined(__AARCH64EB__) # define SQLITE_BYTEORDER 4321 # else # define SQLITE_BYTEORDER 0 @@ -14398,9 +14624,6 @@ struct BtreePayload { SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int flags, int seekResult); SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); -#ifndef SQLITE_OMIT_WINDOWFUNC -SQLITE_PRIVATE void sqlite3BtreeSkipNext(BtCursor*); -#endif SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags); SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); @@ -14412,6 +14635,7 @@ SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor*); SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt); SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*); +SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*); SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); @@ -14651,12 +14875,11 @@ typedef struct VdbeOpList VdbeOpList; #endif /* -** The following macro converts a relative address in the p2 field -** of a VdbeOp structure into a negative number so that -** sqlite3VdbeAddOpList() knows that the address is relative. Calling -** the macro again restores the address. +** The following macro converts a label returned by sqlite3VdbeMakeLabel() +** into an index into the Parse.aLabel[] array that contains the resolved +** address of that label. */ -#define ADDR(X) (-1-(X)) +#define ADDR(X) (~(X)) /* ** The makefile scans the vdbe.c source file and creates the "opcodes.h" @@ -14758,25 +14981,25 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Offset 89 /* synopsis: r[P3] = sqlite_offset(P1) */ #define OP_Column 90 /* synopsis: r[P3]=PX */ #define OP_Affinity 91 /* synopsis: affinity(r[P1@P2]) */ -#define OP_BitAnd 92 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ -#define OP_BitOr 93 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ -#define OP_ShiftLeft 94 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ -#define OP_Add 96 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ -#define OP_Subtract 97 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ -#define OP_Multiply 98 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ -#define OP_Divide 99 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ -#define OP_Remainder 100 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ -#define OP_Concat 101 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ -#define OP_MakeRecord 102 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_BitNot 103 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ -#define OP_Count 104 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 105 -#define OP_String8 106 /* same as TK_STRING, synopsis: r[P2]='P4' */ -#define OP_SetCookie 107 -#define OP_ReopenIdx 108 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenRead 109 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 110 /* synopsis: root=P2 iDb=P3 */ +#define OP_MakeRecord 92 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 93 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 94 +#define OP_SetCookie 95 +#define OP_BitAnd 96 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ +#define OP_BitOr 97 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ +#define OP_ShiftLeft 98 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ +#define OP_Add 100 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ +#define OP_Subtract 101 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ +#define OP_Multiply 102 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ +#define OP_Divide 103 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ +#define OP_Remainder 104 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ +#define OP_Concat 105 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ +#define OP_ReopenIdx 106 /* synopsis: root=P2 iDb=P3 */ +#define OP_BitNot 107 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ +#define OP_OpenRead 108 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 109 /* synopsis: root=P2 iDb=P3 */ +#define OP_String8 110 /* same as TK_STRING, synopsis: r[P2]='P4' */ #define OP_OpenDup 111 #define OP_OpenAutoindex 112 /* synopsis: nColumn=P2 */ #define OP_OpenEphemeral 113 /* synopsis: nColumn=P2 */ @@ -14789,57 +15012,56 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Sequence 120 /* synopsis: r[P2]=cursor[P1].ctr++ */ #define OP_NewRowid 121 /* synopsis: r[P2]=rowid */ #define OP_Insert 122 /* synopsis: intkey=r[P3] data=r[P2] */ -#define OP_InsertInt 123 /* synopsis: intkey=P3 data=r[P2] */ -#define OP_Delete 124 -#define OP_ResetCount 125 -#define OP_SorterCompare 126 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ -#define OP_SorterData 127 /* synopsis: r[P2]=data */ -#define OP_RowData 128 /* synopsis: r[P2]=data */ -#define OP_Rowid 129 /* synopsis: r[P2]=rowid */ -#define OP_NullRow 130 -#define OP_SeekEnd 131 -#define OP_SorterInsert 132 /* synopsis: key=r[P2] */ -#define OP_IdxInsert 133 /* synopsis: key=r[P2] */ -#define OP_IdxDelete 134 /* synopsis: key=r[P2@P3] */ -#define OP_DeferredSeek 135 /* synopsis: Move P3 to P1.rowid if needed */ -#define OP_IdxRowid 136 /* synopsis: r[P2]=rowid */ -#define OP_Destroy 137 -#define OP_Clear 138 -#define OP_ResetSorter 139 -#define OP_CreateBtree 140 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ -#define OP_Real 141 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_SqlExec 142 -#define OP_ParseSchema 143 -#define OP_LoadAnalysis 144 -#define OP_DropTable 145 -#define OP_DropIndex 146 -#define OP_DropTrigger 147 -#define OP_IntegrityCk 148 -#define OP_RowSetAdd 149 /* synopsis: rowset(P1)=r[P2] */ -#define OP_Param 150 -#define OP_FkCounter 151 /* synopsis: fkctr[P1]+=P2 */ -#define OP_MemMax 152 /* synopsis: r[P1]=max(r[P1],r[P2]) */ -#define OP_OffsetLimit 153 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggInverse 154 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ -#define OP_AggStep 155 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep1 156 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggValue 157 /* synopsis: r[P3]=value N=P2 */ -#define OP_AggFinal 158 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 159 -#define OP_TableLock 160 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 161 -#define OP_VCreate 162 -#define OP_VDestroy 163 -#define OP_VOpen 164 -#define OP_VColumn 165 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 166 -#define OP_Pagecount 167 -#define OP_MaxPgcnt 168 -#define OP_Trace 169 -#define OP_CursorHint 170 -#define OP_Noop 171 -#define OP_Explain 172 -#define OP_Abortable 173 +#define OP_Delete 123 +#define OP_ResetCount 124 +#define OP_SorterCompare 125 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 126 /* synopsis: r[P2]=data */ +#define OP_RowData 127 /* synopsis: r[P2]=data */ +#define OP_Rowid 128 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 129 +#define OP_SeekEnd 130 +#define OP_SorterInsert 131 /* synopsis: key=r[P2] */ +#define OP_IdxInsert 132 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 133 /* synopsis: key=r[P2@P3] */ +#define OP_DeferredSeek 134 /* synopsis: Move P3 to P1.rowid if needed */ +#define OP_IdxRowid 135 /* synopsis: r[P2]=rowid */ +#define OP_Destroy 136 +#define OP_Clear 137 +#define OP_ResetSorter 138 +#define OP_CreateBtree 139 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ +#define OP_SqlExec 140 +#define OP_ParseSchema 141 +#define OP_LoadAnalysis 142 +#define OP_DropTable 143 +#define OP_DropIndex 144 +#define OP_Real 145 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ +#define OP_DropTrigger 146 +#define OP_IntegrityCk 147 +#define OP_RowSetAdd 148 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 149 +#define OP_FkCounter 150 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 151 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 152 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggInverse 153 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ +#define OP_AggStep 154 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep1 155 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggValue 156 /* synopsis: r[P3]=value N=P2 */ +#define OP_AggFinal 157 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 158 +#define OP_TableLock 159 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 160 +#define OP_VCreate 161 +#define OP_VDestroy 162 +#define OP_VOpen 163 +#define OP_VColumn 164 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 165 +#define OP_Pagecount 166 +#define OP_MaxPgcnt 167 +#define OP_Trace 168 +#define OP_CursorHint 169 +#define OP_Noop 170 +#define OP_Explain 171 +#define OP_Abortable 172 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -14863,17 +15085,17 @@ typedef struct VdbeOpList VdbeOpList; /* 64 */ 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10,\ /* 72 */ 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,\ /* 80 */ 0x10, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\ -/* 88 */ 0x12, 0x20, 0x00, 0x00, 0x26, 0x26, 0x26, 0x26,\ -/* 96 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00, 0x12,\ -/* 104 */ 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 88 */ 0x12, 0x20, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,\ +/* 96 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\ +/* 104 */ 0x26, 0x26, 0x00, 0x12, 0x00, 0x00, 0x10, 0x00,\ /* 112 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 120 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 128 */ 0x00, 0x10, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00,\ -/* 136 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ -/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00,\ -/* 152 */ 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ -/* 168 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,} +/* 128 */ 0x10, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10,\ +/* 136 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ +/* 144 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\ +/* 152 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\ +/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00,} /* The sqlite3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum @@ -14932,6 +15154,12 @@ SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse*); # define ExplainQueryPlan(P) # define ExplainQueryPlanPop(P) # define ExplainQueryPlanParent(P) 0 +# define sqlite3ExplainBreakpoint(A,B) /*no-op*/ +#endif +#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) +SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char*,const char*); +#else +# define sqlite3ExplainBreakpoint(A,B) /*no-op*/ #endif SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8); @@ -14947,7 +15175,7 @@ SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type); SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); -SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*); +SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*); SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); @@ -14968,6 +15196,10 @@ SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe*); SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*); SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, u8); +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_PRIVATE void sqlite3VdbeAddDblquoteStr(sqlite3*,Vdbe*,const char*); +SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString(Vdbe*,const char*); +#endif SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*); SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); @@ -15278,9 +15510,6 @@ SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*); -# ifdef SQLITE_DIRECT_OVERFLOW_READ -SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno); -# endif # ifdef SQLITE_ENABLE_SNAPSHOT SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot); SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot); @@ -15288,8 +15517,10 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot); SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager); # endif -#else -# define sqlite3PagerUseWal(x,y) 0 +#endif + +#ifdef SQLITE_DIRECT_OVERFLOW_READ +SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno); #endif #ifdef SQLITE_ENABLE_ZIPVFS @@ -15534,6 +15765,10 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void); /* Number of dirty pages as a percentage of the configured cache size */ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); +#ifdef SQLITE_DIRECT_OVERFLOW_READ +SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache); +#endif + #endif /* _PCACHE_H_ */ /************** End of pcache.h **********************************************/ @@ -16039,12 +16274,14 @@ struct LookasideSlot { ** functions use a regular table table from hash.h.) ** ** Hash each FuncDef structure into one of the FuncDefHash.a[] slots. -** Collisions are on the FuncDef.u.pHash chain. +** Collisions are on the FuncDef.u.pHash chain. Use the SQLITE_FUNC_HASH() +** macro to compute a hash on the function name. */ #define SQLITE_FUNC_HASH_SZ 23 struct FuncDefHash { FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */ }; +#define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ) #ifdef SQLITE_USER_AUTHENTICATION /* @@ -16088,10 +16325,13 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); /* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing ** in the style of sqlite3_trace() */ -#define SQLITE_TRACE_LEGACY 0x80 +#define SQLITE_TRACE_LEGACY 0x40 /* Use the legacy xTrace */ +#define SQLITE_TRACE_XPROFILE 0x80 /* Use the legacy xProfile */ #else -#define SQLITE_TRACE_LEGACY 0 +#define SQLITE_TRACE_LEGACY 0 +#define SQLITE_TRACE_XPROFILE 0 #endif /* SQLITE_OMIT_DEPRECATED */ +#define SQLITE_TRACE_NONLEGACY_MASK 0x0f /* Normal flags */ /* @@ -16105,7 +16345,7 @@ struct sqlite3 { Db *aDb; /* All backends */ int nDb; /* Number of backends currently in use */ u32 mDbFlags; /* flags recording internal state */ - u32 flags; /* flags settable by pragmas. See below */ + u64 flags; /* flags settable by pragmas. See below */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 szMmap; /* Default mmap_size setting */ u32 nSchemaLock; /* Do not reset the schema when non-zero */ @@ -16150,14 +16390,17 @@ struct sqlite3 { void **aExtension; /* Array of shared library handles */ int (*xTrace)(u32,void*,void*,void*); /* Trace function */ void *pTraceArg; /* Argument to the trace function */ +#ifndef SQLITE_OMIT_DEPRECATED void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ +#endif void *pCommitArg; /* Argument to xCommitCallback() */ int (*xCommitCallback)(void*); /* Invoked at every commit. */ void *pRollbackArg; /* Argument to xRollbackCallback() */ void (*xRollbackCallback)(void*); /* Invoked at every commit. */ void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); + Parse *pParse; /* Current parse */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK void *pPreUpdateArg; /* First argument to xPreUpdateCallback */ void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */ @@ -16271,14 +16514,20 @@ struct sqlite3 { #define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */ #define SQLITE_ResetDatabase 0x02000000 /* Reset the database */ #define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */ +#define SQLITE_NoSchemaError 0x08000000 /* Do not report schema parse errors*/ +#define SQLITE_Defensive 0x10000000 /* Input SQL is likely hostile */ +#define SQLITE_DqsDDL 0x20000000 /* dbl-quoted strings allowed in DDL*/ +#define SQLITE_DqsDML 0x40000000 /* dbl-quoted strings allowed in DML*/ /* Flags used only if debugging */ +#define HI(X) ((u64)(X)<<32) #ifdef SQLITE_DEBUG -#define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */ -#define SQLITE_VdbeListing 0x10000000 /* Debug listings of VDBE programs */ -#define SQLITE_VdbeTrace 0x20000000 /* True to trace VDBE execution */ -#define SQLITE_VdbeAddopTrace 0x40000000 /* Trace sqlite3VdbeAddOp() calls */ -#define SQLITE_VdbeEQP 0x80000000 /* Debug EXPLAIN QUERY PLAN */ +#define SQLITE_SqlTrace HI(0x0001) /* Debug print SQL as it executes */ +#define SQLITE_VdbeListing HI(0x0002) /* Debug listings of VDBE progs */ +#define SQLITE_VdbeTrace HI(0x0004) /* True to trace VDBE execution */ +#define SQLITE_VdbeAddopTrace HI(0x0008) /* Trace sqlite3VdbeAddOp() calls */ +#define SQLITE_VdbeEQP HI(0x0010) /* Debug EXPLAIN QUERY PLAN */ +#define SQLITE_ParserTrace HI(0x0020) /* PRAGMA parser_trace=ON */ #endif /* @@ -16287,7 +16536,8 @@ struct sqlite3 { #define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */ #define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */ #define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */ -#define DBFLAG_SchemaKnownOk 0x0008 /* Schema is known to be valid */ +#define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */ +#define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the @@ -16295,7 +16545,7 @@ struct sqlite3 { ** selectively disable various optimizations. */ #define SQLITE_QueryFlattener 0x0001 /* Query flattening */ - /* 0x0002 available for reuse */ +#define SQLITE_WindowFunc 0x0002 /* Use xInverse for window functions */ #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ #define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */ @@ -16412,8 +16662,8 @@ struct FuncDestructor { ** single query - might change over time */ #define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */ #define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */ -#define SQLITE_FUNC_WINDOW 0x10000 /* Built-in window-only function */ -#define SQLITE_FUNC_WINDOW_SIZE 0x20000 /* Requires partition size as arg. */ +#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ +#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are @@ -16489,10 +16739,13 @@ struct FuncDestructor { #define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}} - #define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}} +#define INTERNAL_FUNCTION(zName, nArg, xFunc) \ + {nArg, SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ + 0, 0, xFunc, 0, 0, 0, #zName, {0} } + /* ** All current savepoints are stored in a linked list starting at @@ -16727,6 +16980,7 @@ struct Table { #define TF_StatsUsed 0x0100 /* Query planner decisions affected by ** Index.aiRowLogEst[] values */ #define TF_HasNotNull 0x0200 /* Contains NOT NULL constraints */ +#define TF_Shadow 0x0400 /* True for a shadow table */ /* ** Test to see whether or not a table is a virtual table. This is @@ -16962,7 +17216,7 @@ struct Index { u16 nKeyCol; /* Number of columns forming the key */ u16 nColumn; /* Number of columns stored in the index */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ - unsigned idxType:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ + unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ unsigned isResized:1; /* True if resizeIndexObject() has been called */ @@ -16970,6 +17224,7 @@ struct Index { unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ unsigned bNoQuery:1; /* Do not use this index to optimize queries */ + unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ @@ -16987,6 +17242,7 @@ struct Index { #define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */ #define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */ #define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */ +#define SQLITE_IDXTYPE_IPK 3 /* INTEGER PRIMARY KEY index */ /* Return true if index X is a PRIMARY KEY index */ #define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) @@ -17013,6 +17269,12 @@ struct IndexSample { tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */ }; +/* +** Possible values to use within the flags argument to sqlite3GetToken(). +*/ +#define SQLITE_TOKEN_QUOTED 0x1 /* Token is a quoted identifier. */ +#define SQLITE_TOKEN_KEYWORD 0x2 /* Token is a keyword. */ + /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. @@ -17190,25 +17452,33 @@ struct Expr { ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ - u8 op2; /* TK_REGISTER: original value of Expr.op + u8 op2; /* TK_REGISTER/TK_TRUTH: original value of Expr.op ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth */ AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ - Table *pTab; /* Table for TK_COLUMN expressions. Can be NULL - ** for a column of an index on an expression */ -#ifndef SQLITE_OMIT_WINDOWFUNC - Window *pWin; /* Window definition for window functions */ -#endif + union { + Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL + ** for a column of an index on an expression */ + Window *pWin; /* TK_FUNCTION: Window definition for the func */ + struct { /* TK_IN, TK_SELECT, and TK_EXISTS */ + int iAddr; /* Subroutine entry address */ + int regReturn; /* Register used to hold return address */ + } sub; + } y; }; /* ** The following are the meanings of bits in the Expr.flags field. +** Value restrictions: +** +** EP_Agg == NC_HasAgg == SF_HasAgg +** EP_Win == NC_HasWin */ #define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ -#define EP_Agg 0x000002 /* Contains one or more aggregate functions */ +#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */ #define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */ #define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */ -#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ +#define EP_Agg 0x000010 /* Contains one or more aggregate functions */ #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ @@ -17216,10 +17486,10 @@ struct Expr { #define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */ #define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ -#define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */ +#define EP_Skip 0x001000 /* Operator does not contribute to affinity */ #define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ -#define EP_Static 0x008000 /* Held in memory not obtained from malloc() */ +#define EP_Win 0x008000 /* Contains window functions */ #define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ #define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ @@ -17228,6 +17498,12 @@ struct Expr { #define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ #define EP_Alias 0x400000 /* Is an alias for a result set column */ #define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */ +#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */ +#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */ +#define EP_Quoted 0x4000000 /* TK_ID was originally quoted */ +#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */ +#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */ +#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */ /* ** The EP_Propagate mask is a set of properties that automatically propagate @@ -17243,6 +17519,8 @@ struct Expr { #define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) #define ExprSetProperty(E,P) (E)->flags|=(P) #define ExprClearProperty(E,P) (E)->flags&=~(P) +#define ExprAlwaysTrue(E) (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue) +#define ExprAlwaysFalse(E) (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse) /* The ExprSetVVAProperty() macro is used for Verification, Validation, ** and Accreditation only. It works like ExprSetProperty() during VVA @@ -17459,7 +17737,7 @@ struct NameContext { NameContext *pNext; /* Next outer name context. NULL for outermost */ int nRef; /* Number of names resolved by this context */ int nErr; /* Number of errors encountered while resolving names */ - u16 ncFlags; /* Zero or more NC_* flags defined below */ + int ncFlags; /* Zero or more NC_* flags defined below */ Select *pWinSelect; /* SELECT statement for any window functions */ }; @@ -17467,8 +17745,9 @@ struct NameContext { ** Allowed values for the NameContext, ncFlags field. ** ** Value constraints (all checked via assert()): -** NC_HasAgg == SF_HasAgg +** NC_HasAgg == SF_HasAgg == EP_Agg ** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX +** NC_HasWin == EP_Win ** */ #define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ @@ -17484,6 +17763,8 @@ struct NameContext { #define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ #define NC_Complex 0x2000 /* True if a function or subquery seen */ #define NC_AllowWin 0x4000 /* Window functions are allowed here */ +#define NC_HasWin 0x8000 /* One or more window functions seen */ +#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */ /* ** An instance of the following object describes a single ON CONFLICT @@ -17771,16 +18052,17 @@ struct Parse { u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ + u8 disableVtab; /* Disable all virtual tables for this parse */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ - int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ int iSelfTab; /* Table associated with an index on expr, or negative ** of the base register during check-constraint eval */ - int nLabel; /* Number of labels used */ + int nLabel; /* The *negative* of the number of labels used */ + int nLabelAlloc; /* Number of slots in aLabel */ int *aLabel; /* Space to hold the labels */ ExprList *pConstExpr;/* Constant expressions */ Token constraintName;/* Name of the constraint currently being parsed */ @@ -17797,6 +18079,7 @@ struct Parse { AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ + Parse *pParentParse; /* Parent parser if this parser is nested */ int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */ u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u32 oldmask; /* Mask of old.* columns referenced */ @@ -17840,7 +18123,9 @@ struct Parse { Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ - Index *pNewIndex; /* An index being constructed by CREATE INDEX */ + Index *pNewIndex; /* An index being constructed by CREATE INDEX. + ** Also used to hold redundant UNIQUE constraints + ** during a RENAME COLUMN */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -17913,6 +18198,7 @@ struct AuthContext { */ #define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */ /* Also used in P2 (not P5) of OP_Delete */ +#define OPFLAG_NOCHNG 0x01 /* OP_VColumn nochange for UPDATE */ #define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ #define OPFLAG_LASTROWID 0x20 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ @@ -18067,6 +18353,7 @@ typedef struct { int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ int rc; /* Result code stored here */ u32 mInitFlags; /* Flags controlling error messages */ + u32 nInitRow; /* Number of rows processed */ } InitData; /* @@ -18127,10 +18414,14 @@ struct Sqlite3Config { void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */ void *pVdbeBranchArg; /* 1st argument */ #endif +#ifdef SQLITE_ENABLE_DESERIALIZE + sqlite3_int64 mxMemdbSize; /* Default max memdb size */ +#endif #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif int bLocaltimeFault; /* True to fail localtime() calls */ + int bInternalFunctions; /* Internal SQL functions are visible */ int iOnceResetThreshold; /* When to reset OP_Once counters */ u32 szSorterRef; /* Min size in bytes to use sorter-refs */ }; @@ -18229,7 +18520,7 @@ struct TreeView { #endif /* SQLITE_DEBUG */ /* -** This object is used in varioius ways, all related to window functions +** This object is used in various ways, all related to window functions ** ** (1) A single instance of this structure is attached to the ** the Expr.pWin field for each window function in an expression tree. @@ -18244,15 +18535,18 @@ struct TreeView { ** object on a linked list attached to Select.pWinDefn. ** ** The uses (1) and (2) are really the same Window object that just happens -** to be accessible in two different ways. Use (3) is are separate objects. +** to be accessible in two different ways. Use case (3) are separate objects. */ struct Window { char *zName; /* Name of window (may be NULL) */ + char *zBase; /* Name of base window for chaining (may be NULL) */ ExprList *pPartition; /* PARTITION BY clause */ ExprList *pOrderBy; /* ORDER BY clause */ - u8 eType; /* TK_RANGE or TK_ROWS */ + u8 eFrmType; /* TK_RANGE, TK_GROUPS, TK_ROWS, or 0 */ u8 eStart; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ u8 eEnd; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ + u8 bImplicitFrame; /* True if frame was implicitly specified */ + u8 eExclude; /* TK_NO, TK_CURRENT, TK_TIES, TK_GROUP, or 0 */ Expr *pStart; /* Expression for " PRECEDING" */ Expr *pEnd; /* Expression for " FOLLOWING" */ Window *pNextWin; /* Next window function belonging to this SELECT */ @@ -18263,17 +18557,19 @@ struct Window { int regResult; int csrApp; /* Function cursor (used by min/max) */ int regApp; /* Function register (also used by min/max) */ - int regPart; /* First in a set of registers holding PARTITION BY - ** and ORDER BY values for the window */ + int regPart; /* Array of registers for PARTITION BY values */ Expr *pOwner; /* Expression object this window is attached to */ int nBufferCol; /* Number of columns in buffer table */ int iArgCol; /* Offset of first argument for this function */ + int regOne; /* Register containing constant value 1 */ + int regStartRowid; + int regEndRowid; }; #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*); SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p); -SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*); +SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*); SQLITE_PRIVATE int sqlite3WindowCompare(Parse*, Window*, Window*); SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Window*); @@ -18284,6 +18580,8 @@ SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*); SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p); SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p); SQLITE_PRIVATE void sqlite3WindowFunctions(void); +SQLITE_PRIVATE void sqlite3WindowChain(Parse*, Window*, Window*); +SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprList*, Token*); #else # define sqlite3WindowDelete(a,b) # define sqlite3WindowFunctions() @@ -18384,6 +18682,7 @@ SQLITE_PRIVATE int sqlite3IsIdChar(u8); */ SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*); SQLITE_PRIVATE int sqlite3Strlen30(const char*); +#define sqlite3Strlen30NN(C) (strlen(C)&0x3fffffff) SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*); #define sqlite3StrNICmp sqlite3_strnicmp @@ -18472,8 +18771,12 @@ SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex*); #endif #ifndef SQLITE_OMIT_FLOATING_POINT +# define EXP754 (((u64)0x7ff)<<52) +# define MAN754 ((((u64)1)<<52)-1) +# define IsNaN(X) (((X)&EXP754)==EXP754 && ((X)&MAN754)!=0) SQLITE_PRIVATE int sqlite3IsNaN(double); #else +# define IsNaN(X) 0 # define sqlite3IsNaN(X) 0 #endif @@ -18500,6 +18803,7 @@ SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*); SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8); SQLITE_PRIVATE void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*); SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); +SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView*, const SrcList*); SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8); SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8); #ifndef SQLITE_OMIT_WINDOWFUNC @@ -18511,7 +18815,9 @@ SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8); SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*); SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...); +SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3*,int); SQLITE_PRIVATE void sqlite3Dequote(char*); +SQLITE_PRIVATE void sqlite3DequoteExpr(Expr*); SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*); SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int); SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **); @@ -18529,10 +18835,12 @@ SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*); SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*); -SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); +SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*); +SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*); SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); +SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int); @@ -18540,6 +18848,7 @@ SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*); SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*); +SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index*); SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**); SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**); SQLITE_PRIVATE int sqlite3InitOne(sqlite3*, int, char**, u32); @@ -18573,6 +18882,11 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*); SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*); SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); +#ifdef SQLITE_HAS_CODEC +SQLITE_PRIVATE int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*); +#else +# define sqlite3CodecQueryParameters(A,B,C) 0 +#endif SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); #ifdef SQLITE_UNTESTABLE @@ -18625,8 +18939,8 @@ SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upser SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*); -SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int); -SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); +SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int); +SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*); SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, Select*, Expr*, IdList*); SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); @@ -18693,8 +19007,8 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_ite SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); -SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*); -SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int); +SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*,Expr*); +SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*); SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*); SQLITE_PRIVATE int sqlite3ExprCompare(Parse*,Expr*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*, Expr*, int); @@ -18737,6 +19051,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete( SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int); +SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn(Expr*,int*,int); SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, u8,u8,int,int*,int*,Upsert*); #ifdef SQLITE_ENABLE_NULL_TRIM @@ -18757,6 +19072,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*); SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int); +SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*); SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); @@ -18833,6 +19149,7 @@ SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*); SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); +SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64); SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3Atoi(const char*); @@ -18914,6 +19231,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Toke SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); +SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*); SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *); SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64); @@ -18933,6 +19251,9 @@ SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*); SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*); +#ifndef SQLITE_UNTESTABLE +SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context*); +#endif SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *); #ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); @@ -18962,14 +19283,15 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *); SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int); -SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr *, int, int); +SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int); +SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr*); SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*); SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*); SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*); SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*); SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); -SQLITE_PRIVATE void sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); +SQLITE_PRIVATE int sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int); SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *); @@ -19117,6 +19439,9 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); SQLITE_PRIVATE void sqlite3ParserReset(Parse*); +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_PRIVATE char *sqlite3Normalize(Vdbe*, const char*); +#endif SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*); SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); @@ -19211,7 +19536,7 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void); #define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ #define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ #define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ -SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*); +SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*); SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *); @@ -19491,8 +19816,15 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { ** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if ** that compile-time option is omitted. */ -#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN +#if !defined(SQLITE_ALLOW_COVERING_INDEX_SCAN) # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 +#else +# if !SQLITE_ALLOW_COVERING_INDEX_SCAN +# error "Compile-time disabling of covering index scan using the\ + -DSQLITE_ALLOW_COVERING_INDEX_SCAN=0 option is deprecated.\ + Contact SQLite developers if this is a problem for you, and\ + delete this #error macro to continue with your build." +# endif #endif /* The minimum PMA size is set to this value multiplied by the database @@ -19527,6 +19859,13 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { #endif +/* The default maximum size of an in-memory database created using +** sqlite3_deserialize() +*/ +#ifndef SQLITE_MEMDB_DEFAULT_MAXSIZE +# define SQLITE_MEMDB_DEFAULT_MAXSIZE 1073741824 +#endif + /* ** The following singleton contains the global configuration for ** the SQLite library. @@ -19574,12 +19913,16 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0, /* xVdbeBranch */ 0, /* pVbeBranchArg */ #endif +#ifdef SQLITE_ENABLE_DESERIALIZE + SQLITE_MEMDB_DEFAULT_MAXSIZE, /* mxMemdbSize */ +#endif #ifndef SQLITE_UNTESTABLE 0, /* xTestCallback */ #endif 0, /* bLocaltimeFault */ + 0, /* bInternalFunctions */ 0x7ffffffe, /* iOnceResetThreshold */ - SQLITE_DEFAULT_SORTERREF_SIZE /* szSorterRef */ + SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ }; /* @@ -19908,12 +20251,12 @@ struct sqlite3_value { #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ -#define MEM_AffMask 0x001f /* Mask of affinity bits */ -/* Available 0x0020 */ -/* Available 0x0040 */ +#define MEM_IntReal 0x0020 /* MEM_Int that stringifies like MEM_Real */ +#define MEM_AffMask 0x003f /* Mask of affinity bits */ +#define MEM_FromBind 0x0040 /* Value originates from sqlite3_bind() */ #define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ -#define MEM_TypeMask 0xc1ff /* Mask of type bits */ +#define MEM_TypeMask 0xc1bf /* Mask of type bits */ /* Whenever Mem contains a valid string or blob representation, one of @@ -19945,6 +20288,12 @@ struct sqlite3_value { #define MemSetTypeFlag(p, f) \ ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f) +/* +** True if Mem X is a NULL-nochng type. +*/ +#define MemNullNochng(X) \ + ((X)->flags==(MEM_Null|MEM_Zero) && (X)->n==0 && (X)->u.nZero==0) + /* ** Return true if a memory cell is not marked as invalid. This macro ** is for use inside assert() statements only. @@ -19998,6 +20347,9 @@ struct sqlite3_context { */ typedef unsigned bft; /* Bit Field Type */ +/* The ScanStatus object holds a single value for the +** sqlite3_stmt_scanstatus() interface. +*/ typedef struct ScanStatus ScanStatus; struct ScanStatus { int addrExplain; /* OP_Explain for loop */ @@ -20008,6 +20360,19 @@ struct ScanStatus { char *zName; /* Name of table or index */ }; +/* The DblquoteStr object holds the text of a double-quoted +** string for a prepared statement. A linked list of these objects +** is constructed during statement parsing and is held on Vdbe.pDblStr. +** When computing a normalized SQL statement for an SQL statement, that +** list is consulted for each double-quoted identifier to see if the +** identifier should really be a string literal. +*/ +typedef struct DblquoteStr DblquoteStr; +struct DblquoteStr { + DblquoteStr *pNextStr; /* Next string literal in the list */ + char z[8]; /* Dequoted value for the string */ +}; + /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. @@ -20027,28 +20392,29 @@ struct Vdbe { int pc; /* The program counter */ int rc; /* Value to return */ int nChange; /* Number of db changes made since last reset */ - int iStatement; /* Statement number (or 0 if has not opened stmt) */ + int iStatement; /* Statement number (or 0 if has no opened stmt) */ i64 iCurrentTime; /* Value of julianday('now') for this statement */ i64 nFkConstraint; /* Number of imm. FK constraints this VM */ i64 nStmtDefCons; /* Number of def. constraints when stmt started */ i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ + Mem *aMem; /* The memory locations */ + Mem **apArg; /* Arguments to currently executing user function */ + VdbeCursor **apCsr; /* One element of this array for each open cursor */ + Mem *aVar; /* Values for the OP_Variable opcode. */ /* When allocating a new Vdbe object, all of the fields below should be ** initialized to zero or NULL */ Op *aOp; /* Space to hold the virtual machine's program */ - Mem *aMem; /* The memory locations */ - Mem **apArg; /* Arguments to currently executing user function */ + int nOp; /* Number of instructions in the program */ + int nOpAlloc; /* Slots allocated for aOp[] */ Mem *aColName; /* Column names to return */ Mem *pResultSet; /* Pointer to an array of results */ char *zErrMsg; /* Error message written here */ - VdbeCursor **apCsr; /* One element of this array for each open cursor */ - Mem *aVar; /* Values for the OP_Variable opcode. */ VList *pVList; /* Name of variables */ #ifndef SQLITE_OMIT_TRACE i64 startTime; /* Time when query started - used for profiling */ #endif - int nOp; /* Number of instructions in the program */ #ifdef SQLITE_DEBUG int rcApp; /* errcode set by sqlite3_result_error_code() */ u32 nWrite; /* Number of write operations that have occurred */ @@ -20069,6 +20435,10 @@ struct Vdbe { yDbMask lockMask; /* Subset of btreeMask that requires a lock */ u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */ char *zSql; /* Text of the SQL statement that generated this */ +#ifdef SQLITE_ENABLE_NORMALIZE + char *zNormSql; /* Normalization of the associated SQL statement */ + DblquoteStr *pDblStr; /* List of double-quoted string literals */ +#endif void *pFree; /* Free this when deleting the vdbe */ VdbeFrame *pFrame; /* Parent frame */ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ @@ -20131,7 +20501,9 @@ int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*); SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*); SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*); +#ifndef SQLITE_OMIT_EXPLAIN SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*); +#endif SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *, int); SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*); @@ -20170,7 +20542,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*); #endif +#ifndef SQLITE_OMIT_EXPLAIN SQLITE_PRIVATE const char *sqlite3OpcodeName(int); +#endif SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); @@ -21002,7 +21376,7 @@ static int parseDateOrTime( return 0; }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){ return setDateTimeToCurrent(context, p); - }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){ + }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){ setRawDateNumber(p, r); return 0; } @@ -21336,7 +21710,7 @@ static int parseModifier( ** date is already on the appropriate weekday, this is a no-op. */ if( sqlite3_strnicmp(z, "weekday ", 8)==0 - && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8) + && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0 && (n=(int)r)==r && n>=0 && r<7 ){ sqlite3_int64 Z; computeYMD_HMS(p); @@ -21395,7 +21769,7 @@ static int parseModifier( double rRounder; int i; for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} - if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){ + if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){ rc = 1; break; } @@ -26869,6 +27243,9 @@ SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){ db->u1.isInterrupted = 1; } db->lookaside.bDisable++; + if( db->pParse ){ + db->pParse->rc = SQLITE_NOMEM_BKPT; + } } } @@ -27025,6 +27402,12 @@ static const et_info fmtinfo[] = { { 'r', 10, 1, etORDINAL, 0, 0 }, }; +/* Floating point constants used for rounding */ +static const double arRound[] = { + 5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05, + 5.0e-06, 5.0e-07, 5.0e-08, 5.0e-09, 5.0e-10, +}; + /* ** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point ** conversions will work. @@ -27062,7 +27445,8 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ static void setStrAccumError(StrAccum *p, u8 eError){ assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG ); p->accError = eError; - p->nAlloc = 0; + if( p->mxAlloc ) sqlite3_str_reset(p); + if( eError==SQLITE_TOOBIG ) sqlite3ErrorToParser(p->db, eError); } /* @@ -27081,6 +27465,28 @@ static char *getTextArg(PrintfArguments *p){ return (char*)sqlite3_value_text(p->apArg[p->nUsed++]); } +/* +** Allocate memory for a temporary buffer needed for printf rendering. +** +** If the requested size of the temp buffer is larger than the size +** of the output buffer in pAccum, then cause an SQLITE_TOOBIG error. +** Do the size check before the memory allocation to prevent rogue +** SQL from requesting large allocations using the precision or width +** field of the printf() function. +*/ +static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){ + char *z; + if( pAccum->accError ) return 0; + if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){ + setStrAccumError(pAccum, SQLITE_TOOBIG); + return 0; + } + z = sqlite3DbMallocRaw(pAccum->db, n); + if( z==0 ){ + setStrAccumError(pAccum, SQLITE_NOMEM); + } + return z; +} /* ** On machines with a small stack size, you can redefine the @@ -27163,6 +27569,9 @@ SQLITE_API void sqlite3_str_vappendf( flag_leftjustify = flag_prefix = cThousand = flag_alternateform = flag_altform2 = flag_zeropad = 0; done = 0; + width = 0; + flag_long = 0; + precision = -1; do{ switch( c ){ case '-': flag_leftjustify = 1; break; @@ -27173,80 +27582,93 @@ SQLITE_API void sqlite3_str_vappendf( case '0': flag_zeropad = 1; break; case ',': cThousand = ','; break; default: done = 1; break; - } - }while( !done && (c=(*++fmt))!=0 ); - /* Get the field width */ - if( c=='*' ){ - if( bArgList ){ - width = (int)getIntArg(pArgList); - }else{ - width = va_arg(ap,int); - } - if( width<0 ){ - flag_leftjustify = 1; - width = width >= -2147483647 ? -width : 0; - } - c = *++fmt; - }else{ - unsigned wx = 0; - while( c>='0' && c<='9' ){ - wx = wx*10 + c - '0'; - c = *++fmt; - } - testcase( wx>0x7fffffff ); - width = wx & 0x7fffffff; - } - assert( width>=0 ); + case 'l': { + flag_long = 1; + c = *++fmt; + if( c=='l' ){ + c = *++fmt; + flag_long = 2; + } + done = 1; + break; + } + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': { + unsigned wx = c - '0'; + while( (c = *++fmt)>='0' && c<='9' ){ + wx = wx*10 + c - '0'; + } + testcase( wx>0x7fffffff ); + width = wx & 0x7fffffff; #ifdef SQLITE_PRINTF_PRECISION_LIMIT - if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ - width = SQLITE_PRINTF_PRECISION_LIMIT; - } + if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ + width = SQLITE_PRINTF_PRECISION_LIMIT; + } #endif - - /* Get the precision */ - if( c=='.' ){ - c = *++fmt; - if( c=='*' ){ - if( bArgList ){ - precision = (int)getIntArg(pArgList); - }else{ - precision = va_arg(ap,int); + if( c!='.' && c!='l' ){ + done = 1; + }else{ + fmt--; + } + break; } - c = *++fmt; - if( precision<0 ){ - precision = precision >= -2147483647 ? -precision : -1; + case '*': { + if( bArgList ){ + width = (int)getIntArg(pArgList); + }else{ + width = va_arg(ap,int); + } + if( width<0 ){ + flag_leftjustify = 1; + width = width >= -2147483647 ? -width : 0; + } +#ifdef SQLITE_PRINTF_PRECISION_LIMIT + if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ + width = SQLITE_PRINTF_PRECISION_LIMIT; + } +#endif + if( (c = fmt[1])!='.' && c!='l' ){ + c = *++fmt; + done = 1; + } + break; } - }else{ - unsigned px = 0; - while( c>='0' && c<='9' ){ - px = px*10 + c - '0'; + case '.': { c = *++fmt; - } - testcase( px>0x7fffffff ); - precision = px & 0x7fffffff; - } - }else{ - precision = -1; - } - assert( precision>=(-1) ); + if( c=='*' ){ + if( bArgList ){ + precision = (int)getIntArg(pArgList); + }else{ + precision = va_arg(ap,int); + } + if( precision<0 ){ + precision = precision >= -2147483647 ? -precision : -1; + } + c = *++fmt; + }else{ + unsigned px = 0; + while( c>='0' && c<='9' ){ + px = px*10 + c - '0'; + c = *++fmt; + } + testcase( px>0x7fffffff ); + precision = px & 0x7fffffff; + } #ifdef SQLITE_PRINTF_PRECISION_LIMIT - if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){ - precision = SQLITE_PRINTF_PRECISION_LIMIT; - } + if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){ + precision = SQLITE_PRINTF_PRECISION_LIMIT; + } #endif - - - /* Get the conversion type modifier */ - if( c=='l' ){ - flag_long = 1; - c = *++fmt; - if( c=='l' ){ - flag_long = 2; - c = *++fmt; + if( c=='l' ){ + --fmt; + }else{ + done = 1; + } + break; + } } - }else{ - flag_long = 0; - } + }while( !done && (c=(*++fmt))!=0 ); + /* Fetch the info entry for the field */ infop = &fmtinfo[0]; xtype = etINVALID; @@ -27331,12 +27753,11 @@ SQLITE_API void sqlite3_str_vappendf( nOut = etBUFSIZE; zOut = buf; }else{ - u64 n = (u64)precision + 10 + precision/3; - zOut = zExtra = sqlite3Malloc( n ); - if( zOut==0 ){ - setStrAccumError(pAccum, SQLITE_NOMEM); - return; - } + u64 n; + n = (u64)precision + 10; + if( cThousand ) n += precision/3; + zOut = zExtra = printfTempBuf(pAccum, n); + if( zOut==0 ) return; nOut = (int)n; } bufpt = &zOut[nOut-1]; @@ -27405,8 +27826,18 @@ SQLITE_API void sqlite3_str_vappendf( } if( xtype==etGENERIC && precision>0 ) precision--; testcase( precision>0xfff ); - for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){} - if( xtype==etFLOAT ) realvalue += rounder; + idx = precision & 0xfff; + rounder = arRound[idx%10]; + while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; } + if( xtype==etFLOAT ){ + double rx = (double)realvalue; + sqlite3_uint64 u; + int ex; + memcpy(&u, &rx, sizeof(u)); + ex = -1023 + (int)((u>>52)&0x7ff); + if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16; + realvalue += rounder; + } /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; if( sqlite3IsNaN((double)realvalue) ){ @@ -27455,12 +27886,12 @@ SQLITE_API void sqlite3_str_vappendf( }else{ e2 = exp; } - if( MAX(e2,0)+(i64)precision+(i64)width > etBUFSIZE - 15 ){ - bufpt = zExtra - = sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 ); - if( bufpt==0 ){ - setStrAccumError(pAccum, SQLITE_NOMEM); - return; + { + i64 szBufNeeded; /* Size of a temporary buffer needed */ + szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15; + if( szBufNeeded > etBUFSIZE ){ + bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded); + if( bufpt==0 ) return; } } zOut = bufpt; @@ -27684,11 +28115,8 @@ SQLITE_API void sqlite3_str_vappendf( needQuote = !isnull && xtype==etSQLESCAPE2; n += i + 3; if( n>etBUFSIZE ){ - bufpt = zExtra = sqlite3Malloc( n ); - if( bufpt==0 ){ - setStrAccumError(pAccum, SQLITE_NOMEM); - return; - } + bufpt = zExtra = printfTempBuf(pAccum, n); + if( bufpt==0 ) return; }else{ bufpt = buf; } @@ -27778,9 +28206,8 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ return 0; } if( p->mxAlloc==0 ){ - N = p->nAlloc - p->nChar - 1; setStrAccumError(p, SQLITE_TOOBIG); - return N; + return p->nAlloc - p->nChar - 1; }else{ char *zOld = isMalloced(p) ? p->zText : 0; i64 szNew = p->nChar; @@ -27852,7 +28279,7 @@ SQLITE_API void sqlite3_str_append(sqlite3_str *p, const char *z, int N){ assert( z!=0 || N==0 ); assert( p->zText!=0 || p->nChar==0 || p->accError ); assert( N>=0 ); - assert( p->accError==0 || p->nAlloc==0 ); + assert( p->accError==0 || p->nAlloc==0 || p->mxAlloc==0 ); if( p->nChar+N >= p->nAlloc ){ enlargeAndAppend(p,z,N); }else if( N ){ @@ -28297,6 +28724,43 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m } } +/* +** Generate a human-readable description of a SrcList object. +*/ +SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ + int i; + for(i=0; inSrc; i++){ + const struct SrcList_item *pItem = &pSrc->a[i]; + StrAccum x; + char zLine[100]; + sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); + sqlite3_str_appendf(&x, "{%d,*}", pItem->iCursor); + if( pItem->zDatabase ){ + sqlite3_str_appendf(&x, " %s.%s", pItem->zDatabase, pItem->zName); + }else if( pItem->zName ){ + sqlite3_str_appendf(&x, " %s", pItem->zName); + } + if( pItem->pTab ){ + sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p", + pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab); + } + if( pItem->zAlias ){ + sqlite3_str_appendf(&x, " (AS %s)", pItem->zAlias); + } + if( pItem->fg.jointype & JT_LEFT ){ + sqlite3_str_appendf(&x, " LEFT-JOIN"); + } + sqlite3StrAccumFinish(&x); + sqlite3TreeViewItem(pView, zLine, inSrc-1); + if( pItem->pSelect ){ + sqlite3TreeViewSelect(pView, pItem->pSelect, 0); + } + if( pItem->fg.isTabFunc ){ + sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); + } + sqlite3TreeViewPop(pView); + } +} /* ** Generate a human-readable description of a Select object. @@ -28351,39 +28815,9 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m } #endif if( p->pSrc && p->pSrc->nSrc ){ - int i; pView = sqlite3TreeViewPush(pView, (n--)>0); sqlite3TreeViewLine(pView, "FROM"); - for(i=0; ipSrc->nSrc; i++){ - struct SrcList_item *pItem = &p->pSrc->a[i]; - StrAccum x; - char zLine[100]; - sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); - sqlite3_str_appendf(&x, "{%d,*}", pItem->iCursor); - if( pItem->zDatabase ){ - sqlite3_str_appendf(&x, " %s.%s", pItem->zDatabase, pItem->zName); - }else if( pItem->zName ){ - sqlite3_str_appendf(&x, " %s", pItem->zName); - } - if( pItem->pTab ){ - sqlite3_str_appendf(&x, " tabname=%Q", pItem->pTab->zName); - } - if( pItem->zAlias ){ - sqlite3_str_appendf(&x, " (AS %s)", pItem->zAlias); - } - if( pItem->fg.jointype & JT_LEFT ){ - sqlite3_str_appendf(&x, " LEFT-JOIN"); - } - sqlite3StrAccumFinish(&x); - sqlite3TreeViewItem(pView, zLine, ipSrc->nSrc-1); - if( pItem->pSelect ){ - sqlite3TreeViewSelect(pView, pItem->pSelect, 0); - } - if( pItem->fg.isTabFunc ){ - sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); - } - sqlite3TreeViewPop(pView); - } + sqlite3TreeViewSrcList(pView, p->pSrc); sqlite3TreeViewPop(pView); } if( p->pWhere ){ @@ -28478,24 +28912,62 @@ SQLITE_PRIVATE void sqlite3TreeViewBound( ** Generate a human-readable explanation for a Window object */ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){ + int nElement = 0; + if( pWin->pFilter ){ + sqlite3TreeViewItem(pView, "FILTER", 1); + sqlite3TreeViewExpr(pView, pWin->pFilter, 0); + sqlite3TreeViewPop(pView); + } pView = sqlite3TreeViewPush(pView, more); if( pWin->zName ){ - sqlite3TreeViewLine(pView, "OVER %s", pWin->zName); + sqlite3TreeViewLine(pView, "OVER %s (%p)", pWin->zName, pWin); }else{ - sqlite3TreeViewLine(pView, "OVER"); + sqlite3TreeViewLine(pView, "OVER (%p)", pWin); + } + if( pWin->zBase ) nElement++; + if( pWin->pOrderBy ) nElement++; + if( pWin->eFrmType ) nElement++; + if( pWin->eExclude ) nElement++; + if( pWin->zBase ){ + sqlite3TreeViewPush(pView, (--nElement)>0); + sqlite3TreeViewLine(pView, "window: %s", pWin->zBase); + sqlite3TreeViewPop(pView); } if( pWin->pPartition ){ - sqlite3TreeViewExprList(pView, pWin->pPartition, 1, "PARTITION-BY"); + sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY"); } if( pWin->pOrderBy ){ - sqlite3TreeViewExprList(pView, pWin->pOrderBy, 1, "ORDER-BY"); - } - if( pWin->eType ){ - sqlite3TreeViewItem(pView, pWin->eType==TK_RANGE ? "RANGE" : "ROWS", 0); + sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY"); + } + if( pWin->eFrmType ){ + char zBuf[30]; + const char *zFrmType = "ROWS"; + if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE"; + if( pWin->eFrmType==TK_GROUPS ) zFrmType = "GROUPS"; + sqlite3_snprintf(sizeof(zBuf),zBuf,"%s%s",zFrmType, + pWin->bImplicitFrame ? " (implied)" : ""); + sqlite3TreeViewItem(pView, zBuf, (--nElement)>0); sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1); sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0); sqlite3TreeViewPop(pView); } + if( pWin->eExclude ){ + char zBuf[30]; + const char *zExclude; + switch( pWin->eExclude ){ + case TK_NO: zExclude = "NO OTHERS"; break; + case TK_CURRENT: zExclude = "CURRENT ROW"; break; + case TK_GROUP: zExclude = "GROUP"; break; + case TK_TIES: zExclude = "TIES"; break; + default: + sqlite3_snprintf(sizeof(zBuf),zBuf,"invalid(%d)", pWin->eExclude); + zExclude = zBuf; + break; + } + sqlite3TreeViewPush(pView, 0); + sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude); + sqlite3TreeViewPop(pView); + } sqlite3TreeViewPop(pView); } #endif /* SQLITE_OMIT_WINDOWFUNC */ @@ -28645,7 +29117,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m }; assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT ); assert( pExpr->pRight ); - assert( pExpr->pRight->op==TK_TRUEFALSE ); + assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE ); x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight); zUniOp = azOp[x]; break; @@ -28673,7 +29145,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m }else{ pFarg = pExpr->x.pList; #ifndef SQLITE_OMIT_WINDOWFUNC - pWin = pExpr->pWin; + pWin = pExpr->y.pWin; #else pWin = 0; #endif @@ -29475,11 +29947,11 @@ SQLITE_PRIVATE u32 sqlite3Utf8Read( ** encoding, or if *pMem does not contain a string value. */ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ - int len; /* Maximum length of output string in bytes */ - unsigned char *zOut; /* Output buffer */ - unsigned char *zIn; /* Input iterator */ - unsigned char *zTerm; /* End of input */ - unsigned char *z; /* Output iterator */ + sqlite3_int64 len; /* Maximum length of output string in bytes */ + unsigned char *zOut; /* Output buffer */ + unsigned char *zIn; /* Input iterator */ + unsigned char *zTerm; /* End of input */ + unsigned char *z; /* Output iterator */ unsigned int c; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); @@ -29528,14 +30000,14 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired ** nul-terminator. */ pMem->n &= ~1; - len = pMem->n * 2 + 1; + len = 2 * (sqlite3_int64)pMem->n + 1; }else{ /* When converting from UTF-8 to UTF-16 the maximum growth is caused ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16 ** character. Two bytes are required in the output buffer for the ** nul-terminator. */ - len = pMem->n * 2 + 2; + len = 2 * (sqlite3_int64)pMem->n + 2; } /* Set zIn to point at the start of the input buffer and zTerm to point 1 @@ -29827,9 +30299,7 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){ */ /* #include "sqliteInt.h" */ /* #include */ -#if HAVE_ISNAN || SQLITE_HAVE_ISNAN -# include -#endif +#include /* ** Routine needed to support the testcase() macro. @@ -29842,15 +30312,23 @@ SQLITE_PRIVATE void sqlite3Coverage(int x){ #endif /* -** Give a callback to the test harness that can be used to simulate faults -** in places where it is difficult or expensive to do so purely by means -** of inputs. +** Calls to sqlite3FaultSim() are used to simulate a failure during testing, +** or to bypass normal error detection during testing in order to let +** execute proceed futher downstream. ** -** The intent of the integer argument is to let the fault simulator know -** which of multiple sqlite3FaultSim() calls has been hit. +** In deployment, sqlite3FaultSim() *always* return SQLITE_OK (0). The +** sqlite3FaultSim() function only returns non-zero during testing. ** -** Return whatever integer value the test callback returns, or return -** SQLITE_OK if no test callback is installed. +** During testing, if the test harness has set a fault-sim callback using +** a call to sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL), then +** each call to sqlite3FaultSim() is relayed to that application-supplied +** callback and the integer return value form the application-supplied +** callback is returned by sqlite3FaultSim(). +** +** The integer argument to sqlite3FaultSim() is a code to identify which +** sqlite3FaultSim() instance is being invoked. Each call to sqlite3FaultSim() +** should have a unique code. To prevent legacy testing applications from +** breaking, the codes should not be changed or reused. */ #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ @@ -29862,47 +30340,11 @@ SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Return true if the floating point value is Not a Number (NaN). -** -** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN. -** Otherwise, we have our own implementation that works on most systems. */ SQLITE_PRIVATE int sqlite3IsNaN(double x){ - int rc; /* The value return */ -#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN - /* - ** Systems that support the isnan() library function should probably - ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have - ** found that many systems do not have a working isnan() function so - ** this implementation is provided as an alternative. - ** - ** This NaN test sometimes fails if compiled on GCC with -ffast-math. - ** On the other hand, the use of -ffast-math comes with the following - ** warning: - ** - ** This option [-ffast-math] should never be turned on by any - ** -O option since it can result in incorrect output for programs - ** which depend on an exact implementation of IEEE or ISO - ** rules/specifications for math functions. - ** - ** Under MSVC, this NaN test may fail if compiled with a floating- - ** point precision mode other than /fp:precise. From the MSDN - ** documentation: - ** - ** The compiler [with /fp:precise] will properly handle comparisons - ** involving NaN. For example, x != x evaluates to true if x is NaN - ** ... - */ -#ifdef __FAST_MATH__ -# error SQLite will not work correctly with the -ffast-math option of GCC. -#endif - volatile double y = x; - volatile double z = y; - rc = (y!=z); -#else /* if HAVE_ISNAN */ - rc = isnan(x); -#endif /* HAVE_ISNAN */ - testcase( rc ); - return rc; + u64 y; + memcpy(&y,&x,sizeof(y)); + return IsNaN(y); } #endif /* SQLITE_OMIT_FLOATING_POINT */ @@ -30035,6 +30477,19 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ } } +/* +** If database connection db is currently parsing SQL, then transfer +** error code errCode to that parser if the parser has not already +** encountered some other kind of error. +*/ +SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3 *db, int errCode){ + Parse *pParse; + if( db==0 || (pParse = db->pParse)==0 ) return errCode; + pParse->rc = errCode; + pParse->nErr++; + return errCode; +} + /* ** Convert an SQL-style quoted string into a normal string by removing ** the quote characters. The conversion is done in-place. If the @@ -30048,7 +30503,7 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ ** dequoted string, exclusive of the zero terminator, if dequoting does ** occur. ** -** 2002-Feb-14: This routine is extended to remove MS-Access style +** 2002-02-14: This routine is extended to remove MS-Access style ** brackets from around identifiers. For example: "[a-b-c]" becomes ** "a-b-c". */ @@ -30074,6 +30529,11 @@ SQLITE_PRIVATE void sqlite3Dequote(char *z){ } z[j] = 0; } +SQLITE_PRIVATE void sqlite3DequoteExpr(Expr *p){ + assert( sqlite3Isquote(p->u.zToken[0]) ); + p->flags |= p->u.zToken[0]=='"' ? EP_Quoted|EP_DblQuoted : EP_Quoted; + sqlite3Dequote(p->u.zToken); +} /* ** Generate a Token object from a string @@ -30106,12 +30566,18 @@ SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){ } SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){ unsigned char *a, *b; - int c; + int c, x; a = (unsigned char *)zLeft; b = (unsigned char *)zRight; for(;;){ - c = (int)UpperToLower[*a] - (int)UpperToLower[*b]; - if( c || *a==0 ) break; + c = *a; + x = *b; + if( c==x ){ + if( c==0 ) break; + }else{ + c = (int)UpperToLower[c] - (int)UpperToLower[x]; + if( c ) break; + } a++; b++; } @@ -30139,15 +30605,15 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ static LONGDOUBLE_TYPE sqlite3Pow10(int E){ #if defined(_MSC_VER) static const LONGDOUBLE_TYPE x[] = { - 1.0e+001, - 1.0e+002, - 1.0e+004, - 1.0e+008, - 1.0e+016, - 1.0e+032, - 1.0e+064, - 1.0e+128, - 1.0e+256 + 1.0e+001L, + 1.0e+002L, + 1.0e+004L, + 1.0e+008L, + 1.0e+016L, + 1.0e+032L, + 1.0e+064L, + 1.0e+128L, + 1.0e+256L }; LONGDOUBLE_TYPE r = 1.0; int i; @@ -30177,8 +30643,15 @@ static LONGDOUBLE_TYPE sqlite3Pow10(int E){ ** uses the encoding enc. The string is not necessarily zero-terminated. ** ** Return TRUE if the result is a valid real number (or integer) and FALSE -** if the string is empty or contains extraneous text. Valid numbers -** are in one of these formats: +** if the string is empty or contains extraneous text. More specifically +** return +** 1 => The input string is a pure integer +** 2 or more => The input has a decimal point or eNNN clause +** 0 or less => The input string is not a valid number +** -1 => Not a valid number, but has a valid prefix which +** includes a decimal point and/or an eNNN clause +** +** Valid numbers are in one of these formats: ** ** [+-]digits[E[+-]digits] ** [+-]digits.[digits][E[+-]digits] @@ -30203,8 +30676,8 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en int e = 0; /* exponent */ int eValid = 1; /* True exponent is either not used or is well-formed */ double result; - int nDigits = 0; - int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ + int nDigit = 0; /* Number of digits processed */ + int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ @@ -30215,8 +30688,10 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en int i; incr = 2; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); + testcase( enc==SQLITE_UTF16LE ); + testcase( enc==SQLITE_UTF16BE ); for(i=3-enc; i=((LARGEST_INT64-9)/10) ){ + /* skip non-significant significand digits + ** (increase exponent by d to shift decimal left) */ + while( z=zEnd ) goto do_atof_calc; /* if decimal point is present */ if( *z=='.' ){ z+=incr; + eType++; /* copy digits from after decimal to significand ** (decrease exponent by d to shift decimal right) */ while( z=zEnd ) goto do_atof_calc; @@ -30263,6 +30741,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en if( *z=='e' || *z=='E' ){ z+=incr; eValid = 0; + eType++; /* This branch is needed to avoid a (harmless) buffer overread. The ** special comment alerts the mutation tester that the correct answer @@ -30361,7 +30840,13 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en *pResult = result; /* return true if number and no extra non-whitespace chracters after */ - return z==zEnd && nDigits>0 && eValid && nonNum==0; + if( z==zEnd && nDigit>0 && eValid && eType>0 ){ + return eType; + }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){ + return -1; + }else{ + return 0; + } #else return !sqlite3Atoi64(z, pResult, length, enc); #endif /* SQLITE_OMIT_FLOATING_POINT */ @@ -30404,6 +30889,7 @@ static int compare2pow63(const char *zNum, int incr){ ** ** Returns: ** +** -1 Not even a prefix of the input text looks like an integer ** 0 Successful transformation. Fits in a 64-bit signed integer. ** 1 Excess non-space text after the integer value ** 2 Integer too large for a 64-bit signed integer or is malformed @@ -30463,9 +30949,9 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc *pNum = (i64)u; } rc = 0; - if( (i==0 && zStart==zNum) /* No digits */ - || nonNum /* UTF16 with high-order bytes non-zero */ - ){ + if( i==0 && zStart==zNum ){ /* No digits */ + rc = -1; + }else if( nonNum ){ /* UTF16 with high-order bytes non-zero */ rc = 1; }else if( &zNum[i]=0 ){ + *v = *p; return 1; } - - p++; - b = *p; - /* b: p1 (unmasked) */ - if (!(b&0x80)) - { - a &= 0x7f; - a = a<<7; - a |= b; - *v = a; + if( ((signed char*)p)[1]>=0 ){ + *v = ((u32)(p[0]&0x7f)<<7) | p[1]; return 2; } @@ -30720,8 +31195,9 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); - p++; - a = a<<14; + a = ((u32)p[0])<<14; + b = p[1]; + p += 2; a |= *p; /* a: p0<<14 | p2 (unmasked) */ if (!(a&0x80)) @@ -31381,7 +31857,7 @@ SQLITE_PRIVATE VList *sqlite3VListAdd( assert( pIn==0 || pIn[0]>=3 ); /* Verify ok to add new elements */ if( pIn==0 || pIn[1]+nInt > pIn[0] ){ /* Enlarge the allocation */ - int nAlloc = (pIn ? pIn[0]*2 : 10) + nInt; + sqlite3_int64 nAlloc = (pIn ? 2*(sqlite3_int64)pIn[0] : 10) + nInt; VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int)); if( pOut==0 ) return pIn; if( pIn==0 ) pOut[1] = 2; @@ -31587,7 +32063,7 @@ static HashElem *findElementWithHash( unsigned int *pHash /* Write the hash value here */ ){ HashElem *elem; /* Used to loop thru the element list */ - int count; /* Number of elements left to test */ + unsigned int count; /* Number of elements left to test */ unsigned int h; /* The computed hash */ static HashElem nullElement = { 0, 0, 0, 0 }; @@ -31635,8 +32111,8 @@ static void removeElementGivenHash( if( pEntry->chain==elem ){ pEntry->chain = elem->next; } + assert( pEntry->count>0 ); pEntry->count--; - assert( pEntry->count>=0 ); } sqlite3_free( elem ); pH->count--; @@ -31811,25 +32287,25 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 89 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), /* 90 */ "Column" OpHelp("r[P3]=PX"), /* 91 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 92 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), - /* 93 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), - /* 94 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), - /* 96 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), - /* 97 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), - /* 98 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), - /* 99 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), - /* 100 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), - /* 101 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), - /* 102 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 103 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), - /* 104 */ "Count" OpHelp("r[P2]=count()"), - /* 105 */ "ReadCookie" OpHelp(""), - /* 106 */ "String8" OpHelp("r[P2]='P4'"), - /* 107 */ "SetCookie" OpHelp(""), - /* 108 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), - /* 109 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 110 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 92 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 93 */ "Count" OpHelp("r[P2]=count()"), + /* 94 */ "ReadCookie" OpHelp(""), + /* 95 */ "SetCookie" OpHelp(""), + /* 96 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), + /* 97 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), + /* 98 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), + /* 100 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), + /* 101 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), + /* 102 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), + /* 103 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), + /* 104 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), + /* 105 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), + /* 106 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 107 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), + /* 108 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 109 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 110 */ "String8" OpHelp("r[P2]='P4'"), /* 111 */ "OpenDup" OpHelp(""), /* 112 */ "OpenAutoindex" OpHelp("nColumn=P2"), /* 113 */ "OpenEphemeral" OpHelp("nColumn=P2"), @@ -31842,57 +32318,56 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 120 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), /* 121 */ "NewRowid" OpHelp("r[P2]=rowid"), /* 122 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), - /* 123 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), - /* 124 */ "Delete" OpHelp(""), - /* 125 */ "ResetCount" OpHelp(""), - /* 126 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), - /* 127 */ "SorterData" OpHelp("r[P2]=data"), - /* 128 */ "RowData" OpHelp("r[P2]=data"), - /* 129 */ "Rowid" OpHelp("r[P2]=rowid"), - /* 130 */ "NullRow" OpHelp(""), - /* 131 */ "SeekEnd" OpHelp(""), - /* 132 */ "SorterInsert" OpHelp("key=r[P2]"), - /* 133 */ "IdxInsert" OpHelp("key=r[P2]"), - /* 134 */ "IdxDelete" OpHelp("key=r[P2@P3]"), - /* 135 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), - /* 136 */ "IdxRowid" OpHelp("r[P2]=rowid"), - /* 137 */ "Destroy" OpHelp(""), - /* 138 */ "Clear" OpHelp(""), - /* 139 */ "ResetSorter" OpHelp(""), - /* 140 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), - /* 141 */ "Real" OpHelp("r[P2]=P4"), - /* 142 */ "SqlExec" OpHelp(""), - /* 143 */ "ParseSchema" OpHelp(""), - /* 144 */ "LoadAnalysis" OpHelp(""), - /* 145 */ "DropTable" OpHelp(""), - /* 146 */ "DropIndex" OpHelp(""), - /* 147 */ "DropTrigger" OpHelp(""), - /* 148 */ "IntegrityCk" OpHelp(""), - /* 149 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), - /* 150 */ "Param" OpHelp(""), - /* 151 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), - /* 152 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), - /* 153 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 154 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), - /* 155 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 156 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 157 */ "AggValue" OpHelp("r[P3]=value N=P2"), - /* 158 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 159 */ "Expire" OpHelp(""), - /* 160 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 161 */ "VBegin" OpHelp(""), - /* 162 */ "VCreate" OpHelp(""), - /* 163 */ "VDestroy" OpHelp(""), - /* 164 */ "VOpen" OpHelp(""), - /* 165 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 166 */ "VRename" OpHelp(""), - /* 167 */ "Pagecount" OpHelp(""), - /* 168 */ "MaxPgcnt" OpHelp(""), - /* 169 */ "Trace" OpHelp(""), - /* 170 */ "CursorHint" OpHelp(""), - /* 171 */ "Noop" OpHelp(""), - /* 172 */ "Explain" OpHelp(""), - /* 173 */ "Abortable" OpHelp(""), + /* 123 */ "Delete" OpHelp(""), + /* 124 */ "ResetCount" OpHelp(""), + /* 125 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 126 */ "SorterData" OpHelp("r[P2]=data"), + /* 127 */ "RowData" OpHelp("r[P2]=data"), + /* 128 */ "Rowid" OpHelp("r[P2]=rowid"), + /* 129 */ "NullRow" OpHelp(""), + /* 130 */ "SeekEnd" OpHelp(""), + /* 131 */ "SorterInsert" OpHelp("key=r[P2]"), + /* 132 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 133 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 134 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), + /* 135 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 136 */ "Destroy" OpHelp(""), + /* 137 */ "Clear" OpHelp(""), + /* 138 */ "ResetSorter" OpHelp(""), + /* 139 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), + /* 140 */ "SqlExec" OpHelp(""), + /* 141 */ "ParseSchema" OpHelp(""), + /* 142 */ "LoadAnalysis" OpHelp(""), + /* 143 */ "DropTable" OpHelp(""), + /* 144 */ "DropIndex" OpHelp(""), + /* 145 */ "Real" OpHelp("r[P2]=P4"), + /* 146 */ "DropTrigger" OpHelp(""), + /* 147 */ "IntegrityCk" OpHelp(""), + /* 148 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 149 */ "Param" OpHelp(""), + /* 150 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 151 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 152 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 153 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), + /* 154 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 155 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 156 */ "AggValue" OpHelp("r[P3]=value N=P2"), + /* 157 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 158 */ "Expire" OpHelp(""), + /* 159 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 160 */ "VBegin" OpHelp(""), + /* 161 */ "VCreate" OpHelp(""), + /* 162 */ "VDestroy" OpHelp(""), + /* 163 */ "VOpen" OpHelp(""), + /* 164 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 165 */ "VRename" OpHelp(""), + /* 166 */ "Pagecount" OpHelp(""), + /* 167 */ "MaxPgcnt" OpHelp(""), + /* 168 */ "Trace" OpHelp(""), + /* 169 */ "CursorHint" OpHelp(""), + /* 170 */ "Noop" OpHelp(""), + /* 171 */ "Explain" OpHelp(""), + /* 172 */ "Abortable" OpHelp(""), }; return azName[i]; } @@ -32038,12 +32513,10 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #define SQLITE_FSFLAGS_IS_MSDOS 0x1 /* -** If we are to be thread-safe, include the pthreads header and define -** the SQLITE_UNIX_THREADS macro. +** If we are to be thread-safe, include the pthreads header. */ #if SQLITE_THREADSAFE /* # include */ -# define SQLITE_UNIX_THREADS 1 #endif /* @@ -33219,8 +33692,7 @@ struct unixFileId { /* ** An instance of the following structure is allocated for each open -** inode. Or, on LinuxThreads, there is one of these structures for -** each inode opened by each thread. +** inode. ** ** A single inode can have multiple file descriptors, so each unixFile ** structure contains a pointer to an instance of this object and this @@ -33266,13 +33738,16 @@ struct unixInodeInfo { /* ** A lists of all unixInodeInfo objects. +** +** Must hold unixBigLock in order to read or write this variable. */ static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */ #ifdef SQLITE_DEBUG /* -** True if the inode mutex is held, or not. Used only within assert() -** to help verify correct mutex usage. +** True if the inode mutex (on the unixFile.pFileMutex field) is held, or not. +** This routine is used only within assert() to help verify correct mutex +** usage. */ int unixFileMutexHeld(unixFile *pFile){ assert( pFile->pInode ); @@ -33400,8 +33875,8 @@ static void closePendingFds(unixFile *pFile){ /* ** Release a unixInodeInfo structure previously allocated by findInodeInfo(). ** -** The mutex entered using the unixEnterMutex() function must be held -** when this function is called. +** The global mutex must be held when this routine is called, but the mutex +** on the inode being deleted must NOT be held. */ static void releaseInodeInfo(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; @@ -33436,8 +33911,7 @@ static void releaseInodeInfo(unixFile *pFile){ ** describes that file descriptor. Create a new one if necessary. The ** return value might be uninitialized if an error occurs. ** -** The mutex entered using the unixEnterMutex() function must be held -** when this function is called. +** The global mutex must held when calling this routine. ** ** Return an appropriate error code. */ @@ -33498,6 +33972,7 @@ static int findInodeInfo( #else fileId.ino = (u64)statbuf.st_ino; #endif + assert( unixMutexHeld() ); pInode = inodeList; while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){ pInode = pInode->pNext; @@ -33517,6 +33992,7 @@ static int findInodeInfo( } } pInode->nRef = 1; + assert( unixMutexHeld() ); pInode->pNext = inodeList; pInode->pPrev = 0; if( inodeList ) inodeList->pPrev = pInode; @@ -36314,18 +36790,18 @@ static int unixGetpagesize(void){ ** ** The following fields are read-only after the object is created: ** -** fid +** hShm ** zFilename ** -** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and +** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and ** unixMutexHeld() is true when reading or writing any other field ** in this structure. */ struct unixShmNode { unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */ - sqlite3_mutex *mutex; /* Mutex to access this object */ + sqlite3_mutex *pShmMutex; /* Mutex to access this object */ char *zFilename; /* Name of the mmapped file */ - int h; /* Open file descriptor */ + int hShm; /* Open file descriptor */ int szRegion; /* Size of shared-memory regions */ u16 nRegion; /* Size of array apRegion */ u8 isReadonly; /* True if read-only */ @@ -36347,16 +36823,16 @@ struct unixShmNode { ** The following fields are initialized when this object is created and ** are read-only thereafter: ** -** unixShm.pFile +** unixShm.pShmNode ** unixShm.id ** -** All other fields are read/write. The unixShm.pFile->mutex must be held -** while accessing any read/write fields. +** All other fields are read/write. The unixShm.pShmNode->pShmMutex must +** be held while accessing any read/write fields. */ struct unixShm { unixShmNode *pShmNode; /* The underlying unixShmNode object */ unixShm *pNext; /* Next unixShm with the same unixShmNode */ - u8 hasMutex; /* True if holding the unixShmNode mutex */ + u8 hasMutex; /* True if holding the unixShmNode->pShmMutex */ u8 id; /* Id of this connection within its unixShmNode */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ @@ -36386,7 +36862,8 @@ static int unixShmSystemLock( /* Access to the unixShmNode object is serialized by the caller */ pShmNode = pFile->pInode->pShmNode; - assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->mutex) ); + assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) ); + assert( pShmNode->nRef>0 || unixMutexHeld() ); /* Shared locks never span more than one byte */ assert( n==1 || lockType!=F_RDLCK ); @@ -36394,13 +36871,13 @@ static int unixShmSystemLock( /* Locks are within range */ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ /* Initialize the locking parameters */ f.l_type = lockType; f.l_whence = SEEK_SET; f.l_start = ofst; f.l_len = n; - rc = osSetPosixAdvisoryLock(pShmNode->h, &f, pFile); + rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile); rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY; } @@ -36472,18 +36949,18 @@ static void unixShmPurge(unixFile *pFd){ int nShmPerMap = unixShmRegionPerMap(); int i; assert( p->pInode==pFd->pInode ); - sqlite3_mutex_free(p->mutex); + sqlite3_mutex_free(p->pShmMutex); for(i=0; inRegion; i+=nShmPerMap){ - if( p->h>=0 ){ + if( p->hShm>=0 ){ osMunmap(p->apRegion[i], p->szRegion); }else{ sqlite3_free(p->apRegion[i]); } } sqlite3_free(p->apRegion); - if( p->h>=0 ){ - robust_close(pFd, p->h, __LINE__); - p->h = -1; + if( p->hShm>=0 ){ + robust_close(pFd, p->hShm, __LINE__); + p->hShm = -1; } p->pInode->pShmNode = 0; sqlite3_free(p); @@ -36525,7 +37002,7 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ lock.l_start = UNIX_SHM_DMS; lock.l_len = 1; lock.l_type = F_WRLCK; - if( osFcntl(pShmNode->h, F_GETLK, &lock)!=0 ) { + if( osFcntl(pShmNode->hShm, F_GETLK, &lock)!=0 ) { rc = SQLITE_IOERR_LOCK; }else if( lock.l_type==F_UNLCK ){ if( pShmNode->isReadonly ){ @@ -36533,7 +37010,12 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ rc = SQLITE_READONLY_CANTINIT; }else{ rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); - if( rc==SQLITE_OK && robust_ftruncate(pShmNode->h, 0) ){ + /* The first connection to attach must truncate the -shm file. We + ** truncate to 3 bytes (an arbitrary small number, less than the + ** -shm header size) rather than 0 as a system debugging aid, to + ** help detect if a -shm file truncation is legitimate or is the work + ** or a rogue process. */ + if( rc==SQLITE_OK && robust_ftruncate(pShmNode->hShm, 3) ){ rc = unixLogError(SQLITE_IOERR_SHMOPEN,"ftruncate",pShmNode->zFilename); } } @@ -36639,12 +37121,12 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ sqlite3_snprintf(nShmFilename, zShm, "%s-shm", zBasePath); sqlite3FileSuffix3(pDbFd->zPath, zShm); #endif - pShmNode->h = -1; + pShmNode->hShm = -1; pDbFd->pInode->pShmNode = pShmNode; pShmNode->pInode = pDbFd->pInode; if( sqlite3GlobalConfig.bCoreMutex ){ - pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pShmNode->mutex==0 ){ + pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pShmNode->pShmMutex==0 ){ rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } @@ -36652,11 +37134,11 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ if( pInode->bProcessLock==0 ){ if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ - pShmNode->h = robust_open(zShm, O_RDWR|O_CREAT, (sStat.st_mode&0777)); + pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT,(sStat.st_mode&0777)); } - if( pShmNode->h<0 ){ - pShmNode->h = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777)); - if( pShmNode->h<0 ){ + if( pShmNode->hShm<0 ){ + pShmNode->hShm = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777)); + if( pShmNode->hShm<0 ){ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm); goto shm_open_err; } @@ -36667,7 +37149,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ ** is owned by the same user that owns the original database. Otherwise, ** the original owner will not be able to connect. */ - robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid); + robustFchown(pShmNode->hShm, sStat.st_uid, sStat.st_gid); rc = unixLockSharedMemory(pDbFd, pShmNode); if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err; @@ -36687,13 +37169,13 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ ** the cover of the unixEnterMutex() mutex and the pointer from the ** new (struct unixShm) object to the pShmNode has been set. All that is ** left to do is to link the new object into the linked list starting - ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex - ** mutex. + ** at pShmNode->pFirst. This must be done while holding the + ** pShmNode->pShmMutex. */ - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); p->pNext = pShmNode->pFirst; pShmNode->pFirst = p; - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; /* Jump here on any error */ @@ -36745,7 +37227,7 @@ static int unixShmMap( p = pDbFd->pShm; pShmNode = p->pShmNode; - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); if( pShmNode->isUnlocked ){ rc = unixLockSharedMemory(pDbFd, pShmNode); if( rc!=SQLITE_OK ) goto shmpage_out; @@ -36753,8 +37235,8 @@ static int unixShmMap( } assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); assert( pShmNode->pInode==pDbFd->pInode ); - assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); - assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); + assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); + assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); /* Minimum number of regions required to be mapped. */ nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; @@ -36766,12 +37248,12 @@ static int unixShmMap( pShmNode->szRegion = szRegion; - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ /* The requested region is not mapped into this processes address space. ** Check to see if it has been allocated (i.e. if the wal-index file is ** large enough to contain the requested region). */ - if( osFstat(pShmNode->h, &sStat) ){ + if( osFstat(pShmNode->hShm, &sStat) ){ rc = SQLITE_IOERR_SHMSIZE; goto shmpage_out; } @@ -36799,7 +37281,7 @@ static int unixShmMap( assert( (nByte % pgsz)==0 ); for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){ int x = 0; - if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, &x)!=1 ){ + if( seekAndWriteFd(pShmNode->hShm, iPg*pgsz + pgsz-1,"",1,&x)!=1 ){ const char *zFile = pShmNode->zFilename; rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile); goto shmpage_out; @@ -36822,22 +37304,22 @@ static int unixShmMap( int nMap = szRegion*nShmPerMap; int i; void *pMem; - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ pMem = osMmap(0, nMap, pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, - MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion + MAP_SHARED, pShmNode->hShm, szRegion*(i64)pShmNode->nRegion ); if( pMem==MAP_FAILED ){ rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); goto shmpage_out; } }else{ - pMem = sqlite3_malloc64(szRegion); + pMem = sqlite3_malloc64(nMap); if( pMem==0 ){ rc = SQLITE_NOMEM_BKPT; goto shmpage_out; } - memset(pMem, 0, szRegion); + memset(pMem, 0, nMap); } for(i=0; iisReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; } @@ -36888,12 +37370,12 @@ static int unixShmLock( || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); - assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); - assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); + assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); + assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); mask = (1<<(ofst+n)) - (1<1 || mask==(1<mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); if( flags & SQLITE_SHM_UNLOCK ){ u16 allMask = 0; /* Mask of locks held by siblings */ @@ -36966,7 +37448,7 @@ static int unixShmLock( } } } - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", p->id, osGetpid(0), p->sharedMask, p->exclMask)); return rc; @@ -37016,14 +37498,14 @@ static int unixShmUnmap( /* Remove connection p from the set of connections associated ** with pShmNode */ - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} *pp = p->pNext; /* Free the connection p */ sqlite3_free(p); pDbFd->pShm = 0; - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); /* If pShmNode->nRef has reached 0, then close the underlying ** shared-memory file, too */ @@ -37032,7 +37514,7 @@ static int unixShmUnmap( assert( pShmNode->nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ - if( deleteFlag && pShmNode->h>=0 ){ + if( deleteFlag && pShmNode->hShm>=0 ){ osUnlink(pShmNode->zFilename); } unixShmPurge(pDbFd); @@ -40450,8 +40932,7 @@ struct winFile { int nFetchOut; /* Number of outstanding xFetch references */ HANDLE hMap; /* Handle for accessing memory mapping */ void *pMapRegion; /* Area memory mapped */ - sqlite3_int64 mmapSize; /* Usable size of mapped region */ - sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */ + sqlite3_int64 mmapSize; /* Size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif }; @@ -43072,6 +43553,26 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ DWORD lastErrno; #if SQLITE_MAX_MMAP_SIZE>0 sqlite3_int64 oldMmapSize; + if( pFile->nFetchOut>0 ){ + /* File truncation is a no-op if there are outstanding memory mapped + ** pages. This is because truncating the file means temporarily unmapping + ** the file, and that might delete memory out from under existing cursors. + ** + ** This can result in incremental vacuum not truncating the file, + ** if there is an active read cursor when the incremental vacuum occurs. + ** No real harm comes of this - the database file is not corrupted, + ** though some folks might complain that the file is bigger than it + ** needs to be. + ** + ** The only feasible work-around is to defer the truncation until after + ** all references to memory-mapped content are closed. That is doable, + ** but involves adding a few branches in the common write code path which + ** could slow down normal operations slightly. Hence, we have decided for + ** now to simply make trancations a no-op if there are pending reads. We + ** can maybe revisit this decision in the future. + */ + return SQLITE_OK; + } #endif assert( pFile ); @@ -44500,9 +45001,9 @@ static int winShmMap( static int winUnmapfile(winFile *pFile){ assert( pFile!=0 ); OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, " - "mmapSize=%lld, mmapSizeActual=%lld, mmapSizeMax=%lld\n", + "mmapSize=%lld, mmapSizeMax=%lld\n", osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion, - pFile->mmapSize, pFile->mmapSizeActual, pFile->mmapSizeMax)); + pFile->mmapSize, pFile->mmapSizeMax)); if( pFile->pMapRegion ){ if( !osUnmapViewOfFile(pFile->pMapRegion) ){ pFile->lastErrno = osGetLastError(); @@ -44514,7 +45015,6 @@ static int winUnmapfile(winFile *pFile){ } pFile->pMapRegion = 0; pFile->mmapSize = 0; - pFile->mmapSizeActual = 0; } if( pFile->hMap!=NULL ){ if( !osCloseHandle(pFile->hMap) ){ @@ -44625,7 +45125,6 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ } pFd->pMapRegion = pNew; pFd->mmapSize = nMap; - pFd->mmapSizeActual = nMap; } OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n", @@ -45427,7 +45926,6 @@ static int winOpen( pFile->hMap = NULL; pFile->pMapRegion = 0; pFile->mmapSize = 0; - pFile->mmapSizeActual = 0; pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap; #endif @@ -46320,7 +46818,8 @@ typedef struct MemFile MemFile; struct MemFile { sqlite3_file base; /* IO methods */ sqlite3_int64 sz; /* Size of the file */ - sqlite3_int64 szMax; /* Space allocated to aData */ + sqlite3_int64 szAlloc; /* Space allocated to aData */ + sqlite3_int64 szMax; /* Maximum allowed size of the file */ unsigned char *aData; /* content of the file */ int nMmap; /* Number of memory mapped pages */ unsigned mFlags; /* Flags */ @@ -46446,10 +46945,15 @@ static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){ if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){ return SQLITE_FULL; } + if( newSz>p->szMax ){ + return SQLITE_FULL; + } + newSz *= 2; + if( newSz>p->szMax ) newSz = p->szMax; pNew = sqlite3_realloc64(p->aData, newSz); if( pNew==0 ) return SQLITE_NOMEM; p->aData = pNew; - p->szMax = newSz; + p->szAlloc = newSz; return SQLITE_OK; } @@ -46463,10 +46967,11 @@ static int memdbWrite( sqlite_int64 iOfst ){ MemFile *p = (MemFile *)pFile; + if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ) return SQLITE_READONLY; if( iOfst+iAmt>p->sz ){ int rc; - if( iOfst+iAmt>p->szMax - && (rc = memdbEnlarge(p, (iOfst+iAmt)*2))!=SQLITE_OK + if( iOfst+iAmt>p->szAlloc + && (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK ){ return rc; } @@ -46512,6 +47017,11 @@ static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ */ static int memdbLock(sqlite3_file *pFile, int eLock){ MemFile *p = (MemFile *)pFile; + if( eLock>SQLITE_LOCK_SHARED + && (p->mFlags & SQLITE_DESERIALIZE_READONLY)!=0 + ){ + return SQLITE_READONLY; + } p->eLock = eLock; return SQLITE_OK; } @@ -46536,6 +47046,19 @@ static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){ *(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz); rc = SQLITE_OK; } + if( op==SQLITE_FCNTL_SIZE_LIMIT ){ + sqlite3_int64 iLimit = *(sqlite3_int64*)pArg; + if( iLimitsz ){ + if( iLimit<0 ){ + iLimit = p->szMax; + }else{ + iLimit = p->sz; + } + } + p->szMax = iLimit; + *(sqlite3_int64*)pArg = iLimit; + rc = SQLITE_OK; + } return rc; } @@ -46566,8 +47089,12 @@ static int memdbFetch( void **pp ){ MemFile *p = (MemFile *)pFile; - p->nMmap++; - *pp = (void*)(p->aData + iOfst); + if( iOfst+iAmt>p->sz ){ + *pp = 0; + }else{ + p->nMmap++; + *pp = (void*)(p->aData + iOfst); + } return SQLITE_OK; } @@ -46597,6 +47124,7 @@ static int memdbOpen( assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */ *pOutFlags = flags | SQLITE_OPEN_MEMORY; p->base.pMethods = &memdb_io_methods; + p->szMax = sqlite3GlobalConfig.mxMemdbSize; return SQLITE_OK; } @@ -46846,7 +47374,11 @@ SQLITE_API int sqlite3_deserialize( }else{ p->aData = pData; p->sz = szDb; + p->szAlloc = szBuf; p->szMax = szBuf; + if( p->szMaxszMax = sqlite3GlobalConfig.mxMemdbSize; + } p->mFlags = mFlags; rc = SQLITE_OK; } @@ -47324,7 +47856,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){ ** The PCache.pSynced variable is used to optimize searching for a dirty ** page to eject from the cache mid-transaction. It is better to eject ** a page that does not require a journal sync than one that does. -** Therefore, pSynced is maintained to that it *almost* always points +** Therefore, pSynced is maintained so that it *almost* always points ** to either the oldest page in the pDirty/pDirtyTail list that has a ** clear PGHDR_NEED_SYNC flag or to a page that is older than this one ** (so that the right page to eject can be found by following pDirtyPrev @@ -47535,9 +48067,10 @@ static int numberOfCachePages(PCache *p){ ** suggested cache size is set to N. */ return p->szCache; }else{ - /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then - ** the number of cache pages is adjusted to use approximately abs(N*1024) - ** bytes of memory. */ + /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the + ** number of cache pages is adjusted to be a number of pages that would + ** use approximately abs(N*1024) bytes of memory based on the current + ** page size. */ return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); } } @@ -48148,6 +48681,15 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){ return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0; } +#ifdef SQLITE_DIRECT_OVERFLOW_READ +/* +** Return true if there are one or more dirty pages in the cache. Else false. +*/ +SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache){ + return (pCache->pDirty!=0); +} +#endif + #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* ** For all dirty pages currently in the cache, invoke the specified @@ -48258,20 +48800,32 @@ typedef struct PGroup PGroup; ** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of ** PgHdr1.pCache->szPage bytes is allocated directly before this structure ** in memory. +** +** Note: Variables isBulkLocal and isAnchor were once type "u8". That works, +** but causes a 2-byte gap in the structure for most architectures (since +** pointers must be either 4 or 8-byte aligned). As this structure is located +** in memory directly after the associated page data, if the database is +** corrupt, code at the b-tree layer may overread the page buffer and +** read part of this structure before the corruption is detected. This +** can cause a valgrind error if the unitialized gap is accessed. Using u16 +** ensures there is no such gap, and therefore no bytes of unitialized memory +** in the structure. */ struct PgHdr1 { sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */ unsigned int iKey; /* Key value (page number) */ - u8 isBulkLocal; /* This page from bulk local storage */ - u8 isAnchor; /* This is the PGroup.lru element */ + u16 isBulkLocal; /* This page from bulk local storage */ + u16 isAnchor; /* This is the PGroup.lru element */ PgHdr1 *pNext; /* Next in hash table chain */ PCache1 *pCache; /* Cache that currently owns this page */ PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */ PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */ + /* NB: pLruPrev is only valid if pLruNext!=0 */ }; /* -** A page is pinned if it is no on the LRU list +** A page is pinned if it is not on the LRU list. To be "pinned" means +** that the page is in active use and must not be deallocated. */ #define PAGE_IS_PINNED(p) ((p)->pLruNext==0) #define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0) @@ -48332,6 +48886,7 @@ struct PCache1 { unsigned int nMax; /* Configured "cache_size" value */ unsigned int n90pct; /* nMax*9/10 */ unsigned int iMaxKey; /* Largest key seen since xTruncate() */ + unsigned int nPurgeableDummy; /* pnPurgeable points here when not used*/ /* Hash table of all pages. The following variables may only be accessed ** when the accessor is holding the PGroup mutex. @@ -48466,6 +49021,7 @@ static int pcache1InitBulk(PCache1 *pCache){ pX->isBulkLocal = 1; pX->isAnchor = 0; pX->pNext = pCache->pFree; + pX->pLruPrev = 0; /* Initializing this saves a valgrind error */ pCache->pFree = pX; zBulk += pCache->szAlloc; }while( --nBulk ); @@ -48641,6 +49197,7 @@ static void pcache1FreePage(PgHdr1 *p){ ** exists, this function falls back to sqlite3Malloc(). */ SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){ + assert( sz<=65536+8 ); /* These allocations are never very large */ return pcache1Alloc(sz); } @@ -48735,7 +49292,8 @@ static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){ pPage->pLruPrev->pLruNext = pPage->pLruNext; pPage->pLruNext->pLruPrev = pPage->pLruPrev; pPage->pLruNext = 0; - pPage->pLruPrev = 0; + /* pPage->pLruPrev = 0; + ** No need to clear pLruPrev as it is never accessed if pLruNext is 0 */ assert( pPage->isAnchor==0 ); assert( pPage->pCache->pGroup->lru.isAnchor==1 ); pPage->pCache->nRecyclable--; @@ -48928,6 +49486,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ }else{ pGroup = &pcache1.grp; } + pcache1EnterMutex(pGroup); if( pGroup->lru.isAnchor==0 ){ pGroup->lru.isAnchor = 1; pGroup->lru.pLruPrev = pGroup->lru.pLruNext = &pGroup->lru; @@ -48937,7 +49496,6 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ pCache->szExtra = szExtra; pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1)); pCache->bPurgeable = (bPurgeable ? 1 : 0); - pcache1EnterMutex(pGroup); pcache1ResizeHash(pCache); if( bPurgeable ){ pCache->nMin = 10; @@ -48945,8 +49503,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; pCache->pnPurgeable = &pGroup->nPurgeable; }else{ - static unsigned int dummyCurrentPage; - pCache->pnPurgeable = &dummyCurrentPage; + pCache->pnPurgeable = &pCache->nPurgeableDummy; } pcache1LeaveMutex(pGroup); if( pCache->nHash==0 ){ @@ -49073,8 +49630,9 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( pPage->iKey = iKey; pPage->pNext = pCache->apHash[h]; pPage->pCache = pCache; - pPage->pLruPrev = 0; pPage->pLruNext = 0; + /* pPage->pLruPrev = 0; + ** No need to clear pLruPrev since it is not accessed when pLruNext==0 */ *(void **)pPage->page.pExtra = 0; pCache->apHash[h] = pPage; if( iKey>pCache->iMaxKey ){ @@ -49234,7 +49792,7 @@ static void pcache1Unpin( /* It is an error to call this function if the page is already ** part of the PGroup LRU list. */ - assert( pPage->pLruPrev==0 && pPage->pLruNext==0 ); + assert( pPage->pLruNext==0 ); assert( PAGE_IS_PINNED(pPage) ); if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){ @@ -50911,19 +51469,33 @@ static const unsigned char aJournalMagic[] = { */ #define isOpen(pFd) ((pFd)->pMethods!=0) +#ifdef SQLITE_DIRECT_OVERFLOW_READ /* -** Return true if this pager uses a write-ahead log to read page pgno. -** Return false if the pager reads pgno directly from the database. +** Return true if page pgno can be read directly from the database file +** by the b-tree layer. This is the case if: +** +** * the database file is open, +** * there are no dirty pages in the cache, and +** * the desired page is not currently in the wal file. */ -#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_DIRECT_OVERFLOW_READ) -SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno pgno){ - u32 iRead = 0; - int rc; - if( pPager->pWal==0 ) return 0; - rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); - return rc || iRead; +SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ + if( pPager->fd->pMethods==0 ) return 0; + if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; +#ifdef SQLITE_HAS_CODEC + if( pPager->xCodec!=0 ) return 0; +#endif +#ifndef SQLITE_OMIT_WAL + if( pPager->pWal ){ + u32 iRead = 0; + int rc; + rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); + return (rc==SQLITE_OK && iRead==0); + } +#endif + return 1; } #endif + #ifndef SQLITE_OMIT_WAL # define pagerUseWal(x) ((x)->pWal!=0) #else @@ -53861,8 +54433,14 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR rc = sqlite3OsFileSize(pPager->fd, &nByte); } if( rc==SQLITE_OK ){ - pNew = (char *)sqlite3PageMalloc(pageSize); - if( !pNew ) rc = SQLITE_NOMEM_BKPT; + /* 8 bytes of zeroed overrun space is sufficient so that the b-tree + * cell header parser will never run off the end of the allocation */ + pNew = (char *)sqlite3PageMalloc(pageSize+8); + if( !pNew ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + memset(pNew+pageSize, 0, 8); + } } if( rc==SQLITE_OK ){ @@ -53914,7 +54492,10 @@ SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){ pPager->mxPgno = mxPage; } assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */ - assert( pPager->mxPgno>=pPager->dbSize ); /* OP_MaxPgcnt enforces this */ + /* assert( pPager->mxPgno>=pPager->dbSize ); */ + /* OP_MaxPgcnt ensures that the parameter passed to this function is not + ** less than the total number of valid pages in the database. But this + ** may be less than Pager.dbSize, and so the assert() above is not valid */ return pPager->mxPgno; } @@ -57107,7 +57688,11 @@ SQLITE_PRIVATE void sqlite3PagerSetCodec( void (*xCodecFree)(void*), void *pCodec ){ - if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); + if( pPager->xCodecFree ){ + pPager->xCodecFree(pPager->pCodec); + }else{ + pager_reset(pPager); + } pPager->xCodec = pPager->memDb ? 0 : xCodec; pPager->xCodecSizeChng = xCodecSizeChng; pPager->xCodecFree = xCodecFree; @@ -57236,8 +57821,12 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i */ pPg->flags &= ~PGHDR_NEED_SYNC; pPgOld = sqlite3PagerLookup(pPager, pgno); - assert( !pPgOld || pPgOld->nRef==1 ); + assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB ); if( pPgOld ){ + if( pPgOld->nRef>1 ){ + sqlite3PagerUnrefNotNull(pPgOld); + return SQLITE_CORRUPT_BKPT; + } pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); if( pPager->tempFile ){ /* Do not discard pages from an in-memory database since we might @@ -57765,7 +58354,7 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pS */ SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager){ assert( pPager->pWal ); - return sqlite3WalSnapshotUnlock(pPager->pWal); + sqlite3WalSnapshotUnlock(pPager->pWal); } #endif /* SQLITE_ENABLE_SNAPSHOT */ @@ -58366,7 +58955,7 @@ static SQLITE_NOINLINE int walIndexPageRealloc( /* Enlarge the pWal->apWiData[] array if required */ if( pWal->nWiData<=iPage ){ - int nByte = sizeof(u32*)*(iPage+1); + sqlite3_int64 nByte = sizeof(u32*)*(iPage+1); volatile u32 **apNew; apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte); if( !apNew ){ @@ -58470,6 +59059,7 @@ static void walChecksumBytes( assert( nByte>=8 ); assert( (nByte&0x00000007)==0 ); + assert( nByte<=65536 ); if( nativeCksum ){ do { @@ -58777,6 +59367,7 @@ static void walCleanupHash(Wal *pWal){ int iLimit = 0; /* Zero values greater than this */ int nByte; /* Number of bytes to zero in aPgno[] */ int i; /* Used to iterate through aHash[] */ + int rc; /* Return code form walHashGet() */ assert( pWal->writeLock ); testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 ); @@ -58787,11 +59378,12 @@ static void walCleanupHash(Wal *pWal){ /* Obtain pointers to the hash-table and page-number array containing ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed - ** that the page said hash-table and array reside on is already mapped. + ** that the page said hash-table and array reside on is already mapped.(1) */ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) ); assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] ); - walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc); + rc = walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc); + if( NEVER(rc) ) return; /* Defense-in-depth, in case (1) above is wrong */ /* Zero all hash-table entries that correspond to frame numbers greater ** than pWal->hdr.mxFrame. @@ -59405,7 +59997,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ WalIterator *p; /* Return value */ int nSegment; /* Number of segments to merge */ u32 iLast; /* Last frame in log */ - int nByte; /* Number of bytes to allocate */ + sqlite3_int64 nByte; /* Number of bytes to allocate */ int i; /* Iterator variable */ ht_slot *aTmp; /* Temp space used by merge-sort */ int rc = SQLITE_OK; /* Return Code */ @@ -60696,9 +61288,9 @@ SQLITE_PRIVATE int sqlite3WalFindFrame( } nCollide = HASHTABLE_NSLOT; for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ - u32 iFrame = sLoc.aHash[iKey] + sLoc.iZero; - if( iFrame<=iLast && iFrame>=pWal->minFrame - && sLoc.aPgno[sLoc.aHash[iKey]]==pgno ){ + u32 iH = sLoc.aHash[iKey]; + u32 iFrame = iH + sLoc.iZero; + if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH]==pgno ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } @@ -61941,7 +62533,7 @@ struct MemPage { u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ - u16 nFree; /* Number of free bytes on the page */ + int nFree; /* Number of free bytes on the page. -1 for unknown */ u16 nCell; /* Number of cells on this page, local and ovfl */ u16 maskPage; /* Mask for page offset */ u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th @@ -62149,9 +62741,16 @@ struct CellInfo { ** found at self->pBt->mutex. ** ** skipNext meaning: -** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op. -** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op. -** eState==FAULT: Cursor fault with skipNext as error code. +** The meaning of skipNext depends on the value of eState: +** +** eState Meaning of skipNext +** VALID skipNext is meaningless and is ignored +** INVALID skipNext is meaningless and is ignored +** SKIPNEXT sqlite3BtreeNext() is a no-op if skipNext>0 and +** sqlite3BtreePrevious() is no-op if skipNext<0. +** REQUIRESEEK restoreCursorPosition() restores the cursor to +** eState=SKIPNEXT if skipNext!=0 +** FAULT skipNext holds the cursor fault error code. */ struct BtCursor { u8 eState; /* One of the CURSOR_XXX constants (see below) */ @@ -63315,13 +63914,19 @@ static int saveCursorKey(BtCursor *pCur){ /* Only the rowid is required for a table btree */ pCur->nKey = sqlite3BtreeIntegerKey(pCur); }else{ - /* For an index btree, save the complete key content */ + /* For an index btree, save the complete key content. It is possible + ** that the current key is corrupt. In that case, it is possible that + ** the sqlite3VdbeRecordUnpack() function may overread the buffer by + ** up to the size of 1 varint plus 1 8-byte value when the cursor + ** position is restored. Hence the 17 bytes of padding allocated + ** below. */ void *pKey; pCur->nKey = sqlite3BtreePayloadSize(pCur); - pKey = sqlite3Malloc( pCur->nKey ); + pKey = sqlite3Malloc( pCur->nKey + 9 + 8 ); if( pKey ){ rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ + memset(((u8*)pKey)+pCur->nKey, 0, 9+8); pCur->pKey = pKey; }else{ sqlite3_free(pKey); @@ -63453,11 +64058,12 @@ static int btreeMoveto( UnpackedRecord *pIdxKey; /* Unpacked index key */ if( pKey ){ + KeyInfo *pKeyInfo = pCur->pKeyInfo; assert( nKey==(i64)(int)nKey ); - pIdxKey = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo); + pIdxKey = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; - sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey); - if( pIdxKey->nField==0 ){ + sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); + if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ rc = SQLITE_CORRUPT_BKPT; goto moveto_done; } @@ -63481,19 +64087,23 @@ static int btreeMoveto( */ static int btreeRestoreCursorPosition(BtCursor *pCur){ int rc; - int skipNext; + int skipNext = 0; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState>=CURSOR_REQUIRESEEK ); if( pCur->eState==CURSOR_FAULT ){ return pCur->skipNext; } pCur->eState = CURSOR_INVALID; - rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); + if( sqlite3FaultSim(410) ){ + rc = SQLITE_IOERR; + }else{ + rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); + } if( rc==SQLITE_OK ){ sqlite3_free(pCur->pKey); pCur->pKey = 0; assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID ); - pCur->skipNext |= skipNext; + if( skipNext ) pCur->skipNext = skipNext; if( pCur->skipNext && pCur->eState==CURSOR_VALID ){ pCur->eState = CURSOR_SKIPNEXT; } @@ -63563,7 +64173,6 @@ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow) if( pCur->eState!=CURSOR_VALID ){ *pDifferentRow = 1; }else{ - assert( pCur->skipNext==0 ); *pDifferentRow = 0; } return SQLITE_OK; @@ -63647,6 +64256,13 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ *pRC = rc; return; } + if( ((char*)sqlite3PagerGetExtra(pDbPage))[0]!=0 ){ + /* The first byte of the extra data is the MemPage.isInit byte. + ** If that byte is set, it means this page is also being used + ** as a btree page. */ + *pRC = SQLITE_CORRUPT_BKPT; + goto ptrmap_exit; + } offset = PTRMAP_PTROFFSET(iPtrmap, key); if( offset<0 ){ *pRC = SQLITE_CORRUPT_BKPT; @@ -63709,7 +64325,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ #else /* if defined SQLITE_OMIT_AUTOVACUUM */ #define ptrmapPut(w,x,y,z,rc) #define ptrmapGet(w,x,y,z) SQLITE_OK - #define ptrmapPutOvflPtr(x, y, rc) + #define ptrmapPutOvflPtr(x, y, z, rc) #endif /* @@ -64002,17 +64618,24 @@ static u16 cellSize(MemPage *pPage, int iCell){ #ifndef SQLITE_OMIT_AUTOVACUUM /* -** If the cell pCell, part of page pPage contains a pointer -** to an overflow page, insert an entry into the pointer-map -** for the overflow page. +** The cell pCell is currently part of page pSrc but will ultimately be part +** of pPage. (pSrc and pPager are often the same.) If pCell contains a +** pointer to an overflow page, insert an entry into the pointer-map for +** the overflow page that will be valid after pCell has been moved to pPage. */ -static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){ +static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ CellInfo info; if( *pRC ) return; assert( pCell!=0 ); pPage->xParseCell(pPage, pCell, &info); if( info.nLocalaDataEnd, pCell, pCell+info.nLocal) ){ + testcase( pSrc!=pPage ); + *pRC = SQLITE_CORRUPT_BKPT; + return; + } + ovfl = get4byte(&pCell[info.nSize-4]); ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC); } } @@ -64056,7 +64679,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ hdr = pPage->hdrOffset; cellOffset = pPage->cellOffset; nCell = pPage->nCell; - assert( nCell==get2byte(&data[hdr+3]) ); + assert( nCell==get2byte(&data[hdr+3]) || CORRUPT_DB ); iCellFirst = cellOffset + 2*nCell; usableSize = pPage->pBt->usableSize; @@ -64067,19 +64690,10 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ ** reconstruct the entire page. */ if( (int)data[hdr+7]<=nMaxFrag ){ int iFree = get2byte(&data[hdr+1]); + if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); if( iFree ){ int iFree2 = get2byte(&data[iFree]); - - /* pageFindSlot() has already verified that free blocks are sorted - ** in order of offset within the page, and that no block extends - ** past the end of the page. Provided the two free slots do not - ** overlap, this guarantees that the memmove() calls below will not - ** overwrite the usableSize byte buffer, even if the database page - ** is corrupt. */ - assert( iFree2==0 || iFree2>iFree ); - assert( iFree+get2byte(&data[iFree+2]) <= usableSize ); - assert( iFree2==0 || iFree2+get2byte(&data[iFree2+2]) <= usableSize ); - + if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ u8 *pEnd = &data[cellOffset + nCell*2]; u8 *pAddr; @@ -64090,12 +64704,15 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ return SQLITE_CORRUPT_PAGE(pPage); } if( iFree2 ){ - assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */ + if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage); sz2 = get2byte(&data[iFree2+2]); - assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize ); + if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); sz += sz2; + }else if( iFree+sz>usableSize ){ + return SQLITE_CORRUPT_PAGE(pPage); } + cbrk = top+sz; assert( cbrk+(iFree-top) <= usableSize ); memmove(&data[cbrk], &data[top], iFree-top); @@ -64146,6 +64763,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ data[hdr+7] = 0; defragment_out: + assert( pPage->nFree>=0 ); if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ return SQLITE_CORRUPT_PAGE(pPage); } @@ -64173,16 +64791,16 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ ** causes the fragmentation count to exceed 60. */ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ - const int hdr = pPg->hdrOffset; - u8 * const aData = pPg->aData; - int iAddr = hdr + 1; - int pc = get2byte(&aData[iAddr]); - int x; - int usableSize = pPg->pBt->usableSize; - int size; /* Size of the free slot */ + const int hdr = pPg->hdrOffset; /* Offset to page header */ + u8 * const aData = pPg->aData; /* Page data */ + int iAddr = hdr + 1; /* Address of ptr to pc */ + int pc = get2byte(&aData[iAddr]); /* Address of a free slot */ + int x; /* Excess size of the slot */ + int maxPC = pPg->pBt->usableSize - nByte; /* Max address for a usable slot */ + int size; /* Size of the free slot */ assert( pc>0 ); - while( pc<=usableSize-4 ){ + while( pc<=maxPC ){ /* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each ** freeblock form a big-endian integer which is the size of the freeblock ** in bytes, including the 4-byte header. */ @@ -64190,10 +64808,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ if( (x = size - nByte)>=0 ){ testcase( x==4 ); testcase( x==3 ); - if( size+pc > usableSize ){ - *pRc = SQLITE_CORRUPT_PAGE(pPg); - return 0; - }else if( x<4 ){ + if( x<4 ){ /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total ** number of bytes in fragments may not exceed 60. */ if( aData[hdr+7]>57 ) return 0; @@ -64202,21 +64817,31 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ ** fragmented bytes within the page. */ memcpy(&aData[iAddr], &aData[pc], 2); aData[hdr+7] += (u8)x; + }else if( x+pc > maxPC ){ + /* This slot extends off the end of the usable part of the page */ + *pRc = SQLITE_CORRUPT_PAGE(pPg); + return 0; }else{ /* The slot remains on the free-list. Reduce its size to account - ** for the portion used by the new allocation. */ + ** for the portion used by the new allocation. */ put2byte(&aData[pc+2], x); } return &aData[pc + x]; } iAddr = pc; pc = get2byte(&aData[pc]); - if( pcmaxPC+nByte-4 ){ + /* The free slot chain extends off the end of the page */ *pRc = SQLITE_CORRUPT_PAGE(pPg); } - return 0; } @@ -64257,7 +64882,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ ** However, that integer is too large to be stored in a 2-byte unsigned ** integer, so a value of 0 is used in its place. */ top = get2byte(&data[hdr+5]); - assert( top<=(int)pPage->pBt->usableSize ); /* Prevent by getAndInitPage() */ + assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */ if( gap>top ){ if( top==0 && pPage->pBt->usableSize==65536 ){ top = 65536; @@ -64266,9 +64891,9 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ } } - /* If there is enough space between gap and top for one more cell pointer - ** array entry offset, and if the freelist is not empty, then search the - ** freelist looking for a free slot big enough to satisfy the request. + /* If there is enough space between gap and top for one more cell pointer, + ** and if the freelist is not empty, then search the + ** freelist looking for a slot big enough to satisfy the request. */ testcase( gap+2==top ); testcase( gap+1==top ); @@ -64290,6 +64915,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ testcase( gap+2+nByte==top ); if( gap+2+nByte>top ){ assert( pPage->nCell>0 || CORRUPT_DB ); + assert( pPage->nFree>=0 ); rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte))); if( rc ) return rc; top = get2byteNotZero(&data[hdr+5]); @@ -64298,7 +64924,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ /* Allocate memory from the gap in between the cell pointer array - ** and the cell content area. The btreeInitPage() call has already + ** and the cell content area. The btreeComputeFreeSpace() call has already ** validated the freelist. Given that the freelist is valid, there ** is no way that the allocation can extend off the end of the page. ** The assert() below verifies the previous sentence. @@ -64317,7 +64943,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ ** ** Adjacent freeblocks are coalesced. ** -** Note that even though the freeblock list was checked by btreeInitPage(), +** Even though the freeblock list was checked by btreeComputeFreeSpace(), ** that routine will not detect overlap between cells or freeblocks. Nor ** does it detect cells or freeblocks that encrouch into the reserved bytes ** at the end of the page. So do additional corruption checks inside this @@ -64479,21 +65105,14 @@ static int decodeFlags(MemPage *pPage, int flagByte){ } /* -** Initialize the auxiliary information for a disk block. -** -** Return SQLITE_OK on success. If we see that the page does -** not contain a well-formed database page, then return -** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not -** guarantee that the page is well-formed. It only shows that -** we failed to detect any corruption. +** Compute the amount of freespace on the page. In other words, fill +** in the pPage->nFree field. */ -static int btreeInitPage(MemPage *pPage){ +static int btreeComputeFreeSpace(MemPage *pPage){ int pc; /* Address of a freeblock within pPage->aData[] */ u8 hdr; /* Offset to beginning of page header */ u8 *data; /* Equal to pPage->aData */ - BtShared *pBt; /* The main btree structure */ int usableSize; /* Amount of usable space on each page */ - u16 cellOffset; /* Offset from start of page to first cell pointer */ int nFree; /* Number of unused bytes on the page */ int top; /* First byte of the cell content area */ int iCellFirst; /* First allowable cell or freeblock offset */ @@ -64505,71 +65124,18 @@ static int btreeInitPage(MemPage *pPage){ assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); - assert( pPage->isInit==0 ); + assert( pPage->isInit==1 ); + assert( pPage->nFree<0 ); - pBt = pPage->pBt; + usableSize = pPage->pBt->usableSize; hdr = pPage->hdrOffset; data = pPage->aData; - /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating - ** the b-tree page type. */ - if( decodeFlags(pPage, data[hdr]) ){ - return SQLITE_CORRUPT_PAGE(pPage); - } - assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); - pPage->maskPage = (u16)(pBt->pageSize - 1); - pPage->nOverflow = 0; - usableSize = pBt->usableSize; - pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize; - pPage->aDataEnd = &data[usableSize]; - pPage->aCellIdx = &data[cellOffset]; - pPage->aDataOfst = &data[pPage->childPtrSize]; /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates ** the start of the cell content area. A zero value for this integer is ** interpreted as 65536. */ top = get2byteNotZero(&data[hdr+5]); - /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the - ** number of cells on the page. */ - pPage->nCell = get2byte(&data[hdr+3]); - if( pPage->nCell>MX_CELL(pBt) ){ - /* To many cells for a single page. The page must be corrupt */ - return SQLITE_CORRUPT_PAGE(pPage); - } - testcase( pPage->nCell==MX_CELL(pBt) ); - /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only - ** possible for a root page of a table that contains no rows) then the - ** offset to the cell content area will equal the page size minus the - ** bytes of reserved space. */ - assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB ); - - /* A malformed database page might cause us to read past the end - ** of page when parsing a cell. - ** - ** The following block of code checks early to see if a cell extends - ** past the end of a page boundary and causes SQLITE_CORRUPT to be - ** returned if it does. - */ - iCellFirst = cellOffset + 2*pPage->nCell; + iCellFirst = hdr + 8 + pPage->childPtrSize + 2*pPage->nCell; iCellLast = usableSize - 4; - if( pBt->db->flags & SQLITE_CellSizeCk ){ - int i; /* Index into the cell pointer array */ - int sz; /* Size of a cell */ - - if( !pPage->leaf ) iCellLast--; - for(i=0; inCell; i++){ - pc = get2byteAligned(&data[cellOffset+i*2]); - testcase( pc==iCellFirst ); - testcase( pc==iCellLast ); - if( pciCellLast ){ - return SQLITE_CORRUPT_PAGE(pPage); - } - sz = pPage->xCellSize(pPage, &data[pc]); - testcase( pc+sz==usableSize ); - if( pc+sz>usableSize ){ - return SQLITE_CORRUPT_PAGE(pPage); - } - } - if( !pPage->leaf ) iCellLast++; - } /* Compute the total free space on the page ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the @@ -64613,11 +65179,104 @@ static int btreeInitPage(MemPage *pPage){ ** serves to verify that the offset to the start of the cell-content ** area, according to the page header, lies within the page. */ - if( nFree>usableSize ){ + if( nFree>usableSize || nFreenFree = (u16)(nFree - iCellFirst); + return SQLITE_OK; +} + +/* +** Do additional sanity check after btreeInitPage() if +** PRAGMA cell_size_check=ON +*/ +static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ + int iCellFirst; /* First allowable cell or freeblock offset */ + int iCellLast; /* Last possible cell or freeblock offset */ + int i; /* Index into the cell pointer array */ + int sz; /* Size of a cell */ + int pc; /* Address of a freeblock within pPage->aData[] */ + u8 *data; /* Equal to pPage->aData */ + int usableSize; /* Maximum usable space on the page */ + int cellOffset; /* Start of cell content area */ + + iCellFirst = pPage->cellOffset + 2*pPage->nCell; + usableSize = pPage->pBt->usableSize; + iCellLast = usableSize - 4; + data = pPage->aData; + cellOffset = pPage->cellOffset; + if( !pPage->leaf ) iCellLast--; + for(i=0; inCell; i++){ + pc = get2byteAligned(&data[cellOffset+i*2]); + testcase( pc==iCellFirst ); + testcase( pc==iCellLast ); + if( pciCellLast ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + sz = pPage->xCellSize(pPage, &data[pc]); + testcase( pc+sz==usableSize ); + if( pc+sz>usableSize ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + } + return SQLITE_OK; +} + +/* +** Initialize the auxiliary information for a disk block. +** +** Return SQLITE_OK on success. If we see that the page does +** not contain a well-formed database page, then return +** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not +** guarantee that the page is well-formed. It only shows that +** we failed to detect any corruption. +*/ +static int btreeInitPage(MemPage *pPage){ + u8 *data; /* Equal to pPage->aData */ + BtShared *pBt; /* The main btree structure */ + + assert( pPage->pBt!=0 ); + assert( pPage->pBt->db!=0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); + assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); + assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); + assert( pPage->isInit==0 ); + + pBt = pPage->pBt; + data = pPage->aData + pPage->hdrOffset; + /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating + ** the b-tree page type. */ + if( decodeFlags(pPage, data[0]) ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); + pPage->maskPage = (u16)(pBt->pageSize - 1); + pPage->nOverflow = 0; + pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize; + pPage->aCellIdx = data + pPage->childPtrSize + 8; + pPage->aDataEnd = pPage->aData + pBt->usableSize; + pPage->aDataOfst = pPage->aData + pPage->childPtrSize; + /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the + ** number of cells on the page. */ + pPage->nCell = get2byte(&data[3]); + if( pPage->nCell>MX_CELL(pBt) ){ + /* To many cells for a single page. The page must be corrupt */ + return SQLITE_CORRUPT_PAGE(pPage); + } + testcase( pPage->nCell==MX_CELL(pBt) ); + /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only + ** possible for a root page of a table that contains no rows) then the + ** offset to the cell content area will equal the page size minus the + ** bytes of reserved space. */ + assert( pPage->nCell>0 + || get2byteNotZero(&data[5])==(int)pBt->usableSize + || CORRUPT_DB ); + pPage->nFree = -1; /* Indicate that this value is yet uncomputed */ pPage->isInit = 1; + if( pBt->db->flags & SQLITE_CellSizeCk ){ + return btreeCellSizeCheck(pPage); + } return SQLITE_OK; } @@ -64760,19 +65419,18 @@ static int getAndInitPage( if( pgno>btreePagecount(pBt) ){ rc = SQLITE_CORRUPT_BKPT; - goto getAndInitPage_error; + goto getAndInitPage_error1; } rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); if( rc ){ - goto getAndInitPage_error; + goto getAndInitPage_error1; } *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); if( (*ppPage)->isInit==0 ){ btreePageFromDbPage(pDbPage, pgno, pBt); rc = btreeInitPage(*ppPage); if( rc!=SQLITE_OK ){ - releasePage(*ppPage); - goto getAndInitPage_error; + goto getAndInitPage_error2; } } assert( (*ppPage)->pgno==pgno ); @@ -64782,12 +65440,13 @@ static int getAndInitPage( ** compatible with the root page. */ if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ rc = SQLITE_CORRUPT_PGNO(pgno); - releasePage(*ppPage); - goto getAndInitPage_error; + goto getAndInitPage_error2; } return SQLITE_OK; -getAndInitPage_error: +getAndInitPage_error2: + releasePage(*ppPage); +getAndInitPage_error1: if( pCur ){ pCur->iPage--; pCur->pPage = pCur->apPage[pCur->iPage]; @@ -65647,9 +66306,9 @@ static int newDatabase(BtShared*); static int lockBtree(BtShared *pBt){ int rc; /* Result code from subfunctions */ MemPage *pPage1; /* Page 1 of the database file */ - int nPage; /* Number of pages in the database */ - int nPageFile = 0; /* Number of pages in the database file */ - int nPageHeader; /* Number of pages in the database according to hdr */ + u32 nPage; /* Number of pages in the database */ + u32 nPageFile = 0; /* Number of pages in the database file */ + u32 nPageHeader; /* Number of pages in the database according to hdr */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( pBt->pPage1==0 ); @@ -65662,7 +66321,7 @@ static int lockBtree(BtShared *pBt){ ** a valid database file. */ nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData); - sqlite3PagerPagecount(pBt->pPager, &nPageFile); + sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile); if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){ nPage = nPageFile; } @@ -65743,6 +66402,7 @@ static int lockBtree(BtShared *pBt){ ){ goto page1_init_failed; } + pBt->btsFlags |= BTS_PAGESIZE_FIXED; assert( (pageSize & 7)==0 ); /* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte ** integer at offset 20 is the number of bytes of space at the end of @@ -65767,7 +66427,7 @@ static int lockBtree(BtShared *pBt){ pageSize-usableSize); return rc; } - if( (pBt->db->flags & SQLITE_WriteSchema)==0 && nPage>nPageFile ){ + if( sqlite3WritableSchema(pBt->db)==0 && nPage>nPageFile ){ rc = SQLITE_CORRUPT_BKPT; goto page1_init_failed; } @@ -66133,7 +66793,7 @@ static int setChildPtrmaps(MemPage *pPage){ for(i=0; ileaf ){ Pgno childPgno = get4byte(pCell); @@ -66241,6 +66901,7 @@ static int relocatePage( eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ); assert( sqlite3_mutex_held(pBt->mutex) ); assert( pDbPage->pBt==pBt ); + if( iDbPage<3 ) return SQLITE_CORRUPT_BKPT; /* Move page iDbPage from its current location to page number iFreePage */ TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", @@ -66746,6 +67407,18 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr return rc; } +/* +** Set the pBt->nPage field correctly, according to the current +** state of the database. Assume pBt->pPage1 is valid. +*/ +static void btreeSetNPage(BtShared *pBt, MemPage *pPage1){ + int nPage = get4byte(&pPage1->aData[28]); + testcase( nPage==0 ); + if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); + testcase( pBt->nPage!=nPage ); + pBt->nPage = nPage; +} + /* ** Rollback the transaction in progress. ** @@ -66791,11 +67464,7 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ ** call btreeGetPage() on page 1 again to make ** sure pPage1->aData is set correctly. */ if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ - int nPage = get4byte(28+(u8*)pPage1->aData); - testcase( nPage==0 ); - if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); - testcase( pBt->nPage!=nPage ); - pBt->nPage = nPage; + btreeSetNPage(pBt, pPage1); releasePageOne(pPage1); } assert( countValidCursors(pBt, 1)==0 ); @@ -66875,12 +67544,11 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ pBt->nPage = 0; } rc = newDatabase(pBt); - pBt->nPage = get4byte(28 + pBt->pPage1->aData); + btreeSetNPage(pBt, pBt->pPage1); - /* The database size was written into the offset 28 of the header - ** when the transaction started, so we know that the value at offset - ** 28 is nonzero. */ - assert( pBt->nPage>0 ); + /* pBt->nPage might be zero if the database was corrupt when + ** the transaction was started. Otherwise, it must be at least 1. */ + assert( CORRUPT_DB || pBt->nPage>0 ); } sqlite3BtreeLeave(p); } @@ -67058,6 +67726,7 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ sqlite3_free(pCur->aOverflow); sqlite3_free(pCur->pKey); sqlite3BtreeLeave(pBtree); + pCur->pBtree = 0; } return SQLITE_OK; } @@ -67156,6 +67825,25 @@ SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){ return pCur->info.nPayload; } +/* +** Return an upper bound on the size of any record for the table +** that the cursor is pointing into. +** +** This is an optimization. Everything will still work if this +** routine always returns 2147483647 (which is the largest record +** that SQLite can handle) or more. But returning a smaller value might +** prevent large memory allocations when trying to interpret a +** corrupt datrabase. +** +** The current implementation merely returns the size of the underlying +** database file. +*/ +SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + assert( pCur->eState==CURSOR_VALID ); + return pCur->pBt->pageSize * (sqlite3_int64)pCur->pBt->nPage; +} + /* ** Given the page number of an overflow page in the database (parameter ** ovfl), this function finds the page number of the next page in the @@ -67412,9 +68100,6 @@ static int accessPayload( /* Need to read this page properly. It contains some of the ** range of data that is being read (eOp==0) or written (eOp!=0). */ -#ifdef SQLITE_DIRECT_OVERFLOW_READ - sqlite3_file *fd; /* File from which to do direct overflow read */ -#endif int a = amt; if( a + offset > ovflSize ){ a = ovflSize - offset; @@ -67425,7 +68110,7 @@ static int accessPayload( ** ** 1) this is a read operation, and ** 2) data is required from the start of this overflow page, and - ** 3) there is no open write-transaction, and + ** 3) there are no dirty pages in the page-cache ** 4) the database is file-backed, and ** 5) the page is not in the WAL file ** 6) at least 4 bytes have already been read into the output buffer @@ -67436,11 +68121,10 @@ static int accessPayload( */ if( eOp==0 /* (1) */ && offset==0 /* (2) */ - && pBt->inTransaction==TRANS_READ /* (3) */ - && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (4) */ - && 0==sqlite3PagerUseWal(pBt->pPager, nextPage) /* (5) */ + && sqlite3PagerDirectReadOk(pBt->pPager, nextPage) /* (3,4,5) */ && &pBuf[-4]>=pBufStart /* (6) */ ){ + sqlite3_file *fd = sqlite3PagerFile(pBt->pPager); u8 aSave[4]; u8 *aWrite = &pBuf[-4]; assert( aWrite>=pBufStart ); /* due to (6) */ @@ -67850,23 +68534,6 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ return rc; } -/* -** This function is a no-op if cursor pCur does not point to a valid row. -** Otherwise, if pCur is valid, configure it so that the next call to -** sqlite3BtreeNext() is a no-op. -*/ -#ifndef SQLITE_OMIT_WINDOWFUNC -SQLITE_PRIVATE void sqlite3BtreeSkipNext(BtCursor *pCur){ - /* We believe that the cursor must always be in the valid state when - ** this routine is called, but the proof is difficult, so we add an - ** ALWaYS() test just in case we are wrong. */ - if( ALWAYS(pCur->eState==CURSOR_VALID) ){ - pCur->eState = CURSOR_SKIPNEXT; - pCur->skipNext = 1; - } -} -#endif /* SQLITE_OMIT_WINDOWFUNC */ - /* Move the cursor to the last entry in the table. Return SQLITE_OK ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. @@ -67889,6 +68556,7 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ assert( pCur->ix==pCur->pPage->nCell-1 ); assert( pCur->pPage->leaf ); #endif + *pRes = 0; return SQLITE_OK; } @@ -67974,7 +68642,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( ** try to get there using sqlite3BtreeNext() rather than a full ** binary search. This is an optimization only. The correct answer ** is still obtained without this case, only a little more slowely */ - if( pCur->info.nKey+1==intKey && !pCur->skipNext ){ + if( pCur->info.nKey+1==intKey ){ *pRes = 0; rc = sqlite3BtreeNext(pCur, 0); if( rc==SQLITE_OK ){ @@ -68110,29 +68778,31 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( ** case this happens. */ void *pCellKey; u8 * const pCellBody = pCell - pPage->childPtrSize; + const int nOverrun = 18; /* Size of the overrun padding */ pPage->xParseCell(pPage, pCellBody, &pCur->info); nCell = (int)pCur->info.nKey; testcase( nCell<0 ); /* True if key size is 2^32 or more */ testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */ testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ testcase( nCell==2 ); /* Minimum legal index key size */ - if( nCell<2 ){ + if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ rc = SQLITE_CORRUPT_PAGE(pPage); goto moveto_finish; } - pCellKey = sqlite3Malloc( nCell+18 ); + pCellKey = sqlite3Malloc( nCell+nOverrun ); if( pCellKey==0 ){ rc = SQLITE_NOMEM_BKPT; goto moveto_finish; } pCur->ix = (u16)idx; rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); + memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */ pCur->curFlags &= ~BTCF_ValidOvfl; if( rc ){ sqlite3_free(pCellKey); goto moveto_finish; } - c = xRecordCompare(nCell, pCellKey, pIdxKey); + c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); sqlite3_free(pCellKey); } assert( @@ -68248,7 +68918,6 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); - assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); if( pCur->eState!=CURSOR_VALID ){ assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); rc = restoreCursorPosition(pCur); @@ -68258,14 +68927,9 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ if( CURSOR_INVALID==pCur->eState ){ return SQLITE_DONE; } - if( pCur->skipNext ){ - assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT ); + if( pCur->eState==CURSOR_SKIPNEXT ){ pCur->eState = CURSOR_VALID; - if( pCur->skipNext>0 ){ - pCur->skipNext = 0; - return SQLITE_OK; - } - pCur->skipNext = 0; + if( pCur->skipNext>0 ) return SQLITE_OK; } } @@ -68320,7 +68984,6 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int flags){ UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ assert( cursorOwnsBtShared(pCur) ); assert( flags==0 || flags==1 ); - assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur); @@ -68361,7 +69024,6 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){ MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); - assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 ); assert( pCur->info.nSize==0 ); if( pCur->eState!=CURSOR_VALID ){ @@ -68372,14 +69034,9 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){ if( CURSOR_INVALID==pCur->eState ){ return SQLITE_DONE; } - if( pCur->skipNext ){ - assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT ); + if( CURSOR_SKIPNEXT==pCur->eState ){ pCur->eState = CURSOR_VALID; - if( pCur->skipNext<0 ){ - pCur->skipNext = 0; - return SQLITE_OK; - } - pCur->skipNext = 0; + if( pCur->skipNext<0 ) return SQLITE_OK; } } @@ -68414,7 +69071,6 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int flags){ assert( cursorOwnsBtShared(pCur) ); assert( flags==0 || flags==1 ); - assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); pCur->info.nSize = 0; @@ -68750,7 +69406,7 @@ static int allocateBtreePage( TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); } - assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); + assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) ); end_allocate_page: releasePage(pTrunk); @@ -68778,13 +69434,15 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ MemPage *pPage1 = pBt->pPage1; /* Local reference to page 1 */ MemPage *pPage; /* Page being freed. May be NULL. */ int rc; /* Return Code */ - int nFree; /* Initial number of pages on free-list */ + u32 nFree; /* Initial number of pages on free-list */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( CORRUPT_DB || iPage>1 ); assert( !pMemPage || pMemPage->pgno==iPage ); - if( iPage<2 ) return SQLITE_CORRUPT_BKPT; + if( iPage<2 || iPage>pBt->nPage ){ + return SQLITE_CORRUPT_BKPT; + } if( pMemPage ){ pPage = pMemPage; sqlite3PagerRef(pPage->pDbPage); @@ -69195,6 +69853,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ assert( CORRUPT_DB || sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->nFree>=0 ); data = pPage->aData; ptr = &pPage->aCellIdx[2*idx]; pc = get2byte(ptr); @@ -69265,6 +69924,7 @@ static void insertCell( ** might be less than 8 (leaf-size + pointer) on the interior node. Hence ** the term after the || in the following assert(). */ assert( sz==pPage->xCellSize(pPage, pCell) || (sz==8 && iChild>0) ); + assert( pPage->nFree>=0 ); if( pPage->nOverflow || sz+2>pPage->nFree ){ if( pTemp ){ memcpy(pTemp, pCell, sz); @@ -69305,9 +69965,16 @@ static void insertCell( assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB ); assert( idx+sz <= (int)pPage->pBt->usableSize ); pPage->nFree -= (u16)(2 + sz); - memcpy(&data[idx], pCell, sz); if( iChild ){ + /* In a corrupt database where an entry in the cell index section of + ** a btree page has a value of 3 or less, the pCell value might point + ** as many as 4 bytes in front of the start of the aData buffer for + ** the source page. Make sure this does not cause problems by not + ** reading the first 4 bytes */ + memcpy(&data[idx+4], pCell+4, sz-4); put4byte(&data[idx], iChild); + }else{ + memcpy(&data[idx], pCell, sz); } pIns = pPage->aCellIdx + i*2; memmove(pIns+2, pIns, 2*(pPage->nCell - i)); @@ -69315,21 +69982,100 @@ static void insertCell( pPage->nCell++; /* increment the cell count */ if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++; - assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell ); + assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB ); #ifndef SQLITE_OMIT_AUTOVACUUM if( pPage->pBt->autoVacuum ){ /* The cell may contain a pointer to an overflow page. If so, write ** the entry for the overflow page into the pointer map. */ - ptrmapPutOvflPtr(pPage, pCell, pRC); + ptrmapPutOvflPtr(pPage, pPage, pCell, pRC); } #endif } } +/* +** The following parameters determine how many adjacent pages get involved +** in a balancing operation. NN is the number of neighbors on either side +** of the page that participate in the balancing operation. NB is the +** total number of pages that participate, including the target page and +** NN neighbors on either side. +** +** The minimum value of NN is 1 (of course). Increasing NN above 1 +** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance +** in exchange for a larger degradation in INSERT and UPDATE performance. +** The value of NN appears to give the best results overall. +** +** (Later:) The description above makes it seem as if these values are +** tunable - as if you could change them and recompile and it would all work. +** But that is unlikely. NB has been 3 since the inception of SQLite and +** we have never tested any other value. +*/ +#define NN 1 /* Number of neighbors on either side of pPage */ +#define NB 3 /* (NN*2+1): Total pages involved in the balance */ + /* ** A CellArray object contains a cache of pointers and sizes for a ** consecutive sequence of cells that might be held on multiple pages. +** +** The cells in this array are the divider cell or cells from the pParent +** page plus up to three child pages. There are a total of nCell cells. +** +** pRef is a pointer to one of the pages that contributes cells. This is +** used to access information such as MemPage.intKey and MemPage.pBt->pageSize +** which should be common to all pages that contribute cells to this array. +** +** apCell[] and szCell[] hold, respectively, pointers to the start of each +** cell and the size of each cell. Some of the apCell[] pointers might refer +** to overflow cells. In other words, some apCel[] pointers might not point +** to content area of the pages. +** +** A szCell[] of zero means the size of that cell has not yet been computed. +** +** The cells come from as many as four different pages: +** +** ----------- +** | Parent | +** ----------- +** / | \ +** / | \ +** --------- --------- --------- +** |Child-1| |Child-2| |Child-3| +** --------- --------- --------- +** +** The order of cells is in the array is for an index btree is: +** +** 1. All cells from Child-1 in order +** 2. The first divider cell from Parent +** 3. All cells from Child-2 in order +** 4. The second divider cell from Parent +** 5. All cells from Child-3 in order +** +** For a table-btree (with rowids) the items 2 and 4 are empty because +** content exists only in leaves and there are no divider cells. +** +** For an index btree, the apEnd[] array holds pointer to the end of page +** for Child-1, the Parent, Child-2, the Parent (again), and Child-3, +** respectively. The ixNx[] array holds the number of cells contained in +** each of these 5 stages, and all stages to the left. Hence: +** +** ixNx[0] = Number of cells in Child-1. +** ixNx[1] = Number of cells in Child-1 plus 1 for first divider. +** ixNx[2] = Number of cells in Child-1 and Child-2 + 1 for 1st divider. +** ixNx[3] = Number of cells in Child-1 and Child-2 + both divider cells +** ixNx[4] = Total number of cells. +** +** For a table-btree, the concept is similar, except only apEnd[0]..apEnd[2] +** are used and they point to the leaf pages only, and the ixNx value are: +** +** ixNx[0] = Number of cells in Child-1. +** ixNx[1] = Number of cells in Child-1 and Child-2. +** ixNx[2] = Total number of cells. +** +** Sometimes when deleting, a child page can have zero cells. In those +** cases, ixNx[] entries with higher indexes, and the corresponding apEnd[] +** entries, shift down. The end result is that each ixNx[] entry should +** be larger than the previous */ typedef struct CellArray CellArray; struct CellArray { @@ -69337,6 +70083,8 @@ struct CellArray { MemPage *pRef; /* Reference page */ u8 **apCell; /* All cells begin balanced */ u16 *szCell; /* Local size of all cells in apCell[] */ + u8 *apEnd[NB*2]; /* MemPage.aDataEnd values */ + int ixNx[NB*2]; /* Index of at which we move to the next apEnd[] */ }; /* @@ -69387,36 +70135,59 @@ static u16 cachedCellSize(CellArray *p, int N){ ** responsibility of the caller to set it correctly. */ static int rebuildPage( - MemPage *pPg, /* Edit this page */ + CellArray *pCArray, /* Content to be added to page pPg */ + int iFirst, /* First cell in pCArray to use */ int nCell, /* Final number of cells on page */ - u8 **apCell, /* Array of cells */ - u16 *szCell /* Array of cell sizes */ + MemPage *pPg /* The page to be reconstructed */ ){ const int hdr = pPg->hdrOffset; /* Offset of header on pPg */ u8 * const aData = pPg->aData; /* Pointer to data for pPg */ const int usableSize = pPg->pBt->usableSize; u8 * const pEnd = &aData[usableSize]; - int i; + int i = iFirst; /* Which cell to copy from pCArray*/ + u32 j; /* Start of cell content area */ + int iEnd = i+nCell; /* Loop terminator */ u8 *pCellptr = pPg->aCellIdx; u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); u8 *pData; + int k; /* Current slot in pCArray->apEnd[] */ + u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */ + + assert( i(u32)usableSize) ){ j = 0; } + memcpy(&pTmp[j], &aData[j], usableSize - j); - i = get2byte(&aData[hdr+5]); - memcpy(&pTmp[i], &aData[i], usableSize - i); + for(k=0; pCArray->ixNx[k]<=i && ALWAYS(kapEnd[k]; pData = pEnd; - for(i=0; iapCell[i]; + u16 sz = pCArray->szCell[i]; + assert( sz>0 ); if( SQLITE_WITHIN(pCell,aData,pEnd) ){ + if( ((uptr)(pCell+sz))>(uptr)pEnd ) return SQLITE_CORRUPT_BKPT; pCell = &pTmp[pCell - aData]; + }else if( (uptr)(pCell+sz)>(uptr)pSrcEnd + && (uptr)(pCell)<(uptr)pSrcEnd + ){ + return SQLITE_CORRUPT_BKPT; } - pData -= szCell[i]; + + pData -= sz; put2byte(pCellptr, (pData - aData)); pCellptr += 2; if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT; - memcpy(pData, pCell, szCell[i]); - assert( szCell[i]==pPg->xCellSize(pPg, pCell) || CORRUPT_DB ); - testcase( szCell[i]!=pPg->xCellSize(pPg,pCell) ); + memcpy(pData, pCell, sz); + assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB ); + testcase( sz!=pPg->xCellSize(pPg,pCell) ); + i++; + if( i>=iEnd ) break; + if( pCArray->ixNx[k]<=i ){ + k++; + pSrcEnd = pCArray->apEnd[k]; + } } /* The pPg->nFree field is now set incorrectly. The caller will fix it. */ @@ -69431,12 +70202,11 @@ static int rebuildPage( } /* -** Array apCell[] contains nCell pointers to b-tree cells. Array szCell -** contains the size in bytes of each such cell. This function attempts to -** add the cells stored in the array to page pPg. If it cannot (because -** the page needs to be defragmented before the cells will fit), non-zero -** is returned. Otherwise, if the cells are added successfully, zero is -** returned. +** The pCArray objects contains pointers to b-tree cells and the cell sizes. +** This function attempts to add the cells stored in the array to page pPg. +** If it cannot (because the page needs to be defragmented before the cells +** will fit), non-zero is returned. Otherwise, if the cells are added +** successfully, zero is returned. ** ** Argument pCellptr points to the first entry in the cell-pointer array ** (part of page pPg) to populate. After cell apCell[0] is written to the @@ -69458,18 +70228,23 @@ static int rebuildPage( static int pageInsertArray( MemPage *pPg, /* Page to add cells to */ u8 *pBegin, /* End of cell-pointer array */ - u8 **ppData, /* IN/OUT: Page content -area pointer */ + u8 **ppData, /* IN/OUT: Page content-area pointer */ u8 *pCellptr, /* Pointer to cell-pointer area */ int iFirst, /* Index of first cell to add */ int nCell, /* Number of cells to add to pPg */ CellArray *pCArray /* Array of cells */ ){ - int i; - u8 *aData = pPg->aData; - u8 *pData = *ppData; - int iEnd = iFirst + nCell; + int i = iFirst; /* Loop counter - cell index to insert */ + u8 *aData = pPg->aData; /* Complete page */ + u8 *pData = *ppData; /* Content area. A subset of aData[] */ + int iEnd = iFirst + nCell; /* End of loop. One past last cell to ins */ + int k; /* Current slot in pCArray->apEnd[] */ + u8 *pEnd; /* Maximum extent of cell data */ assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */ - for(i=iFirst; iixNx[k]<=i && ALWAYS(kapEnd[k]; + while( 1 /*Exit by break*/ ){ int sz, rc; u8 *pSlot; sz = cachedCellSize(pCArray, i); @@ -69484,20 +70259,33 @@ static int pageInsertArray( assert( (pSlot+sz)<=pCArray->apCell[i] || pSlot>=(pCArray->apCell[i]+sz) || CORRUPT_DB ); + if( (uptr)(pCArray->apCell[i]+sz)>(uptr)pEnd + && (uptr)(pCArray->apCell[i])<(uptr)pEnd + ){ + assert( CORRUPT_DB ); + (void)SQLITE_CORRUPT_BKPT; + return 1; + } memmove(pSlot, pCArray->apCell[i], sz); put2byte(pCellptr, (pSlot - aData)); pCellptr += 2; + i++; + if( i>=iEnd ) break; + if( pCArray->ixNx[k]<=i ){ + k++; + pEnd = pCArray->apEnd[k]; + } } *ppData = pData; return 0; } /* -** Array apCell[] contains nCell pointers to b-tree cells. Array szCell -** contains the size in bytes of each such cell. This function adds the -** space associated with each cell in the array that is currently stored -** within the body of pPg to the pPg free-list. The cell-pointers and other -** fields of the page are not updated. +** The pCArray object contains pointers to b-tree cells and their sizes. +** +** This function adds the space associated with each cell in the array +** that is currently stored within the body of pPg to the pPg free-list. +** The cell-pointers and other fields of the page are not updated. ** ** This function returns the total number of cells added to the free-list. */ @@ -69547,9 +70335,9 @@ static int pageFreeArray( } /* -** apCell[] and szCell[] contains pointers to and sizes of all cells in the -** pages being balanced. The current page, pPg, has pPg->nCell cells starting -** with apCell[iOld]. After balancing, this page should hold nNew cells +** pCArray contains pointers to and sizes of all cells in the page being +** balanced. The current page, pPg, has pPg->nCell cells starting with +** pCArray->apCell[iOld]. After balancing, this page should hold nNew cells ** starting at apCell[iNew]. ** ** This routine makes the necessary adjustments to pPg so that it contains @@ -69581,13 +70369,17 @@ static int editPage( #endif /* Remove cells from the start and end of the page */ + assert( nCell>=0 ); if( iOldnCell ) return SQLITE_CORRUPT_BKPT; memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2); nCell -= nShift; } if( iNewEnd < iOldEnd ){ - nCell -= pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray); + int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray); + assert( nCell>=nTail ); + nCell -= nTail; } pData = &aData[get2byteNotZero(&aData[hdr+5])]; @@ -69597,6 +70389,7 @@ static int editPage( if( iNew=0 ); pCellptr = pPg->aCellIdx; memmove(&pCellptr[nAdd*2], pCellptr, nCell*2); if( pageInsertArray( @@ -69611,7 +70404,9 @@ static int editPage( int iCell = (iOld + pPg->aiOvfl[i]) - iNew; if( iCell>=0 && iCellaCellIdx[iCell * 2]; - memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); + if( nCell>iCell ){ + memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); + } nCell++; if( pageInsertArray( pPg, pBegin, &pData, pCellptr, @@ -69621,6 +70416,7 @@ static int editPage( } /* Append cells to the end of the page */ + assert( nCell>=0 ); pCellptr = &pPg->aCellIdx[nCell*2]; if( pageInsertArray( pPg, pBegin, &pData, pCellptr, @@ -69649,24 +70445,9 @@ static int editPage( editpage_fail: /* Unable to edit this page. Rebuild it from scratch instead. */ populateCellCache(pCArray, iNew, nNew); - return rebuildPage(pPg, nNew, &pCArray->apCell[iNew], &pCArray->szCell[iNew]); + return rebuildPage(pCArray, iNew, nNew, pPg); } -/* -** The following parameters determine how many adjacent pages get involved -** in a balancing operation. NN is the number of neighbors on either side -** of the page that participate in the balancing operation. NB is the -** total number of pages that participate, including the target page and -** NN neighbors on either side. -** -** The minimum value of NN is 1 (of course). Increasing NN above 1 -** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance -** in exchange for a larger degradation in INSERT and UPDATE performance. -** The value of NN appears to give the best results overall. -*/ -#define NN 1 /* Number of neighbors on either side of pPage */ -#define NB (NN*2+1) /* Total pages involved in the balance */ - #ifndef SQLITE_OMIT_QUICKBALANCE /* @@ -69701,9 +70482,10 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); assert( pPage->nOverflow==1 ); - - /* This error condition is now caught prior to reaching this function */ - if( NEVER(pPage->nCell==0) ) return SQLITE_CORRUPT_BKPT; + + if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; /* dbfuzz001.test */ + assert( pPage->nFree>=0 ); + assert( pParent->nFree>=0 ); /* Allocate a new page. This page will become the right-sibling of ** pPage. Make the parent page writable, so that the new divider cell @@ -69717,12 +70499,22 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ u8 *pCell = pPage->apOvfl[0]; u16 szCell = pPage->xCellSize(pPage, pCell); u8 *pStop; + CellArray b; assert( sqlite3PagerIswriteable(pNew->pDbPage) ); - assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) ); + assert( CORRUPT_DB || pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) ); zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF); - rc = rebuildPage(pNew, 1, &pCell, &szCell); - if( NEVER(rc) ) return rc; + b.nCell = 1; + b.pRef = pPage; + b.apCell = &pCell; + b.szCell = &szCell; + b.apEnd[0] = pPage->aDataEnd; + b.ixNx[0] = 2; + rc = rebuildPage(&b, 0, 1, pNew); + if( NEVER(rc) ){ + releasePage(pNew); + return rc; + } pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell; /* If this is an auto-vacuum database, update the pointer map @@ -69737,7 +70529,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ if( ISAUTOVACUUM ){ ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc); if( szCell>pNew->minLocal ){ - ptrmapPutOvflPtr(pNew, pCell, &rc); + ptrmapPutOvflPtr(pNew, pNew, pCell, &rc); } } @@ -69863,6 +70655,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){ */ pTo->isInit = 0; rc = btreeInitPage(pTo); + if( rc==SQLITE_OK ) rc = btreeComputeFreeSpace(pTo); if( rc!=SQLITE_OK ){ *pRC = rc; return; @@ -69960,10 +70753,6 @@ static int balance_nonroot( assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); -#if 0 - TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno)); -#endif - /* At this point pParent may have at most one overflow cell. And if ** this overflow cell is present, it must be the cell with ** index iParentIdx. This scenario comes about when this function @@ -69975,6 +70764,7 @@ static int balance_nonroot( if( !aOvflSpace ){ return SQLITE_NOMEM_BKPT; } + assert( pParent->nFree>=0 ); /* Find the sibling pages to balance. Also locate the cells in pParent ** that divide the siblings. An attempt is made to find NN siblings on @@ -70014,7 +70804,13 @@ static int balance_nonroot( memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; } - nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; + if( apOld[i]->nFree<0 ){ + rc = btreeComputeFreeSpace(apOld[i]); + if( rc ){ + memset(apOld, 0, (i)*sizeof(MemPage*)); + goto balance_cleanup; + } + } if( (i--)==0 ) break; if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){ @@ -70058,6 +70854,7 @@ static int balance_nonroot( /* Make nMaxCells a multiple of 4 in order to preserve 8-byte ** alignment */ + nMaxCells = nOld*(MX_CELL(pBt) + ArraySize(pParent->apOvfl)); nMaxCells = (nMaxCells + 3)&~3; /* @@ -70068,7 +70865,7 @@ static int balance_nonroot( + nMaxCells*sizeof(u16) /* b.szCell */ + pBt->pageSize; /* aSpace1 */ - assert( szScratch<=6*(int)pBt->pageSize ); + assert( szScratch<=7*(int)pBt->pageSize ); b.apCell = sqlite3StackAllocRaw(0, szScratch ); if( b.apCell==0 ){ rc = SQLITE_NOMEM_BKPT; @@ -70104,6 +70901,7 @@ static int balance_nonroot( u16 maskPage = pOld->maskPage; u8 *piCell = aData + pOld->cellOffset; u8 *piEnd; + VVA_ONLY( int nCellAtStart = b.nCell; ) /* Verify that all sibling pages are of the same "type" (table-leaf, ** table-interior, index-leaf, or index-interior). @@ -70132,6 +70930,10 @@ static int balance_nonroot( */ memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); if( pOld->nOverflow>0 ){ + if( limitaiOvfl[0] ){ + rc = SQLITE_CORRUPT_BKPT; + goto balance_cleanup; + } limit = pOld->aiOvfl[0]; for(j=0; jnCell+pOld->nOverflow) ); cntOld[i] = b.nCell; if( iusableSize - 12 + leafCorrection; - for(i=0; iaDataEnd; + b.ixNx[k] = cntOld[i]; + if( k && b.ixNx[k]==b.ixNx[k-1] ){ + k--; /* Omit b.ixNx[] entry for child pages with no cells */ + } + if( !leafData ){ + k++; + b.apEnd[k] = pParent->aDataEnd; + b.ixNx[k] = cntOld[i]+1; + } + assert( p->nFree>=0 ); szNew[i] = usableSpace - p->nFree; for(j=0; jnOverflow; j++){ szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]); @@ -70429,19 +71243,20 @@ static int balance_nonroot( ** populated, not here. */ if( ISAUTOVACUUM ){ - MemPage *pNew = apNew[0]; - u8 *aOld = pNew->aData; + MemPage *pOld; + MemPage *pNew = pOld = apNew[0]; int cntOldNext = pNew->nCell + pNew->nOverflow; - int usableSize = pBt->usableSize; int iNew = 0; int iOld = 0; for(i=0; i=0 && iOldnCell + pOld->nOverflow + !leafData; - aOld = pOld->aData; } if( i==cntNew[iNew] ){ pNew = apNew[++iNew]; @@ -70456,13 +71271,13 @@ static int balance_nonroot( ** overflow cell), we can skip updating the pointer map entries. */ if( iOld>=nNew || pNew->pgno!=aPgno[iOld] - || !SQLITE_WITHIN(pCell,aOld,&aOld[usableSize]) + || !SQLITE_WITHIN(pCell,pOld->aData,pOld->aDataEnd) ){ if( !leafCorrection ){ ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc); } if( cachedCellSize(&b,i)>pNew->minLocal ){ - ptrmapPutOvflPtr(pNew, pCell, &rc); + ptrmapPutOvflPtr(pNew, pOld, pCell, &rc); } if( rc ) goto balance_cleanup; } @@ -70607,7 +71422,8 @@ static int balance_nonroot( rc = defragmentPage(apNew[0], -1); testcase( rc!=SQLITE_OK ); assert( apNew[0]->nFree == - (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) + (get2byteNotZero(&apNew[0]->aData[5]) - apNew[0]->cellOffset + - apNew[0]->nCell*2) || rc!=SQLITE_OK ); copyNodeContent(apNew[0], pParent, &rc); @@ -70706,7 +71522,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){ } assert( sqlite3PagerIswriteable(pChild->pDbPage) ); assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); - assert( pChild->nCell==pRoot->nCell ); + assert( pChild->nCell==pRoot->nCell || CORRUPT_DB ); TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno)); @@ -70748,6 +71564,7 @@ static int balance(BtCursor *pCur){ int iPage = pCur->iPage; MemPage *pPage = pCur->pPage; + if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break; if( iPage==0 ){ if( pPage->nOverflow ){ /* The root page of the b-tree is overfull. In this case call the @@ -70776,6 +71593,9 @@ static int balance(BtCursor *pCur){ int const iIdx = pCur->aiIdx[iPage-1]; rc = sqlite3PagerWrite(pParent->pDbPage); + if( rc==SQLITE_OK && pParent->nFree<0 ){ + rc = btreeComputeFreeSpace(pParent); + } if( rc==SQLITE_OK ){ #ifndef SQLITE_OMIT_QUICKBALANCE if( pPage->intKeyLeaf @@ -70886,7 +71706,11 @@ static int btreeOverwriteContent( if( memcmp(pDest, ((u8*)pX->pData) + iOffset, iAmt)!=0 ){ int rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; - memcpy(pDest, ((u8*)pX->pData) + iOffset, iAmt); + /* In a corrupt database, it is possible for the source and destination + ** buffers to overlap. This is harmless since the database is already + ** corrupt but it does cause valgrind and ASAN warnings. So use + ** memmove(). */ + memmove(pDest, ((u8*)pX->pData) + iOffset, iAmt); } } return SQLITE_OK; @@ -71118,6 +71942,10 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( pPage = pCur->pPage; assert( pPage->intKey || pX->nKey>=0 ); assert( pPage->leaf || !pPage->intKey ); + if( pPage->nFree<0 ){ + rc = btreeComputeFreeSpace(pPage); + if( rc ) return rc; + } TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, @@ -71260,14 +72088,18 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); - assert( pCur->ixpPage->nCell ); - assert( pCur->eState==CURSOR_VALID ); assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 ); + if( pCur->eState==CURSOR_REQUIRESEEK ){ + rc = btreeRestoreCursorPosition(pCur); + if( rc ) return rc; + } + assert( pCur->eState==CURSOR_VALID ); iCellDepth = pCur->iPage; iCellIdx = pCur->ix; pPage = pCur->pPage; pCell = findCell(pPage, iCellIdx); + if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ) return SQLITE_CORRUPT; /* If the bPreserve flag is set to true, then the cursor position must ** be preserved following this delete operation. If the current delete @@ -71281,6 +72113,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ if( bPreserve ){ if( !pPage->leaf || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3) + || pPage->nCell==1 /* See dbfuzz001.test for a test case */ ){ /* A b-tree rebalance will be required after deleting this entry. ** Save the cursor key. */ @@ -71337,6 +72170,10 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ Pgno n; unsigned char *pTmp; + if( pLeaf->nFree<0 ){ + rc = btreeComputeFreeSpace(pLeaf); + if( rc ) return rc; + } if( iCellDepthiPage-1 ){ n = pCur->apPage[iCellDepth+1]->pgno; }else{ @@ -71695,6 +72532,9 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ assert( sqlite3BtreeHoldsMutex(p) ); assert( p->inTrans==TRANS_WRITE ); assert( iTable>=2 ); + if( iTable>btreePagecount(pBt) ){ + return SQLITE_CORRUPT_BKPT; + } rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( rc ) return rc; @@ -72043,10 +72883,10 @@ static void checkList( IntegrityCk *pCheck, /* Integrity checking context */ int isFreeList, /* True for a freelist. False for overflow page list */ int iPage, /* Page number for first page in the list */ - int N /* Expected number of pages in the list */ + u32 N /* Expected number of pages in the list */ ){ int i; - int expected = N; + u32 expected = N; int nErrAtStart = pCheck->nErr; while( iPage!=0 && pCheck->mxErr ){ DbPage *pOvflPage; @@ -72059,18 +72899,18 @@ static void checkList( } pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage); if( isFreeList ){ - int n = get4byte(&pOvflData[4]); + u32 n = (u32)get4byte(&pOvflData[4]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pCheck->pBt->autoVacuum ){ checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0); } #endif - if( n>(int)pCheck->pBt->usableSize/4-2 ){ + if( n>pCheck->pBt->usableSize/4-2 ){ checkAppendMsg(pCheck, "freelist leaf count too big on page %d", iPage); N--; }else{ - for(i=0; ipBt->autoVacuum ){ @@ -72228,6 +73068,11 @@ static int checkTreePage( "btreeInitPage() returns error code %d", rc); goto end_of_check; } + if( (rc = btreeComputeFreeSpace(pPage))!=0 ){ + assert( rc==SQLITE_CORRUPT ); + checkAppendMsg(pCheck, "free space corruption", rc); + goto end_of_check; + } data = pPage->aData; hdr = pPage->hdrOffset; @@ -72300,7 +73145,7 @@ static int checkTreePage( /* Check the content overflow list */ if( info.nPayload>info.nLocal ){ - int nPage; /* Number of pages on the overflow chain */ + u32 nPage; /* Number of pages on the overflow chain */ Pgno pgnoOvfl; /* First page of the overflow chain */ assert( pc + info.nSize - 4 <= usableSize ); nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4); @@ -72360,9 +73205,9 @@ static int checkTreePage( i = get2byte(&data[hdr+1]); while( i>0 ){ int size, j; - assert( (u32)i<=usableSize-4 ); /* Enforced by btreeInitPage() */ + assert( (u32)i<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ size = get2byte(&data[i+2]); - assert( (u32)(i+size)<=usableSize ); /* Enforced by btreeInitPage() */ + assert( (u32)(i+size)<=usableSize ); /* due to btreeComputeFreeSpace() */ btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1)); /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a ** big-endian integer which is the offset in the b-tree page of the next @@ -72371,8 +73216,8 @@ static int checkTreePage( j = get2byte(&data[i]); /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of ** increasing offset. */ - assert( j==0 || j>i+size ); /* Enforced by btreeInitPage() */ - assert( (u32)j<=usableSize-4 ); /* Enforced by btreeInitPage() */ + assert( j==0 || j>i+size ); /* Enforced by btreeComputeFreeSpace() */ + assert( (u32)j<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ i = j; } /* Analyze the min-heap looking for overlap between cells and/or @@ -72447,7 +73292,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( Pgno i; IntegrityCk sCheck; BtShared *pBt = p->pBt; - int savedDbFlags = pBt->db->flags; + u64 savedDbFlags = pBt->db->flags; char zErr[100]; VVA_ONLY( int nRef ); @@ -72514,7 +73359,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( } #endif testcase( pBt->db->flags & SQLITE_CellSizeCk ); - pBt->db->flags &= ~SQLITE_CellSizeCk; + pBt->db->flags &= ~(u64)SQLITE_CellSizeCk; for(i=0; (int)iflags & MEM_Dyn)==0 || p->szMalloc==0 ); - /* Cannot be both MEM_Int and MEM_Real at the same time */ - assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) ); + /* Cannot have more than one of MEM_Int, MEM_Real, or MEM_IntReal */ + assert( ISPOWEROF2(p->flags & (MEM_Int|MEM_Real|MEM_IntReal)) ); if( p->flags & MEM_Null ){ /* Cannot be both MEM_Null and some other type */ @@ -73716,7 +74566,7 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 ); /* No other bits set */ - assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype + assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype|MEM_FromBind |MEM_Dyn|MEM_Ephem|MEM_Static))==0 ); }else{ /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn, @@ -73751,9 +74601,31 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ } #endif +/* +** Render a Mem object which is one of MEM_Int, MEM_Real, or MEM_IntReal +** into a buffer. +*/ +static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ + StrAccum acc; + assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) ); + sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0); + if( p->flags & MEM_Int ){ + sqlite3_str_appendf(&acc, "%lld", p->u.i); + }else if( p->flags & MEM_IntReal ){ + sqlite3_str_appendf(&acc, "%!.15g", (double)p->u.i); + }else{ + sqlite3_str_appendf(&acc, "%!.15g", p->u.r); + } + assert( acc.zText==zBuf && acc.mxAlloc<=0 ); + zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */ +} + #ifdef SQLITE_DEBUG /* -** Check that string value of pMem agrees with its integer or real value. +** Validity checks on pMem. pMem holds a string. +** +** (1) Check that string value of pMem agrees with its integer or real value. +** (2) Check that the string is correctly zero terminated ** ** A single int or real value always converts to the same strings. But ** many different strings can be converted into the same int or real. @@ -73771,17 +74643,24 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ ** ** This routine is for use inside of assert() statements only. */ -SQLITE_PRIVATE int sqlite3VdbeMemConsistentDualRep(Mem *p){ +SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){ char zBuf[100]; char *z; int i, j, incr; if( (p->flags & MEM_Str)==0 ) return 1; - if( (p->flags & (MEM_Int|MEM_Real))==0 ) return 1; - if( p->flags & MEM_Int ){ - sqlite3_snprintf(sizeof(zBuf),zBuf,"%lld",p->u.i); - }else{ - sqlite3_snprintf(sizeof(zBuf),zBuf,"%!.15g",p->u.r); - } + if( p->flags & MEM_Term ){ + /* Insure that the string is properly zero-terminated. Pay particular + ** attention to the case where p->n is odd */ + if( p->szMalloc>0 && p->z==p->zMalloc ){ + assert( p->enc==SQLITE_UTF8 || p->szMalloc >= ((p->n+1)&~1)+2 ); + assert( p->enc!=SQLITE_UTF8 || p->szMalloc >= p->n+1 ); + } + assert( p->z[p->n]==0 ); + assert( p->enc==SQLITE_UTF8 || p->z[(p->n+1)&~1]==0 ); + assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 ); + } + if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1; + vdbeMemRenderNum(sizeof(zBuf), zBuf, p); z = p->z; i = j = 0; incr = 1; @@ -73837,8 +74716,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ } /* -** Make sure pMem->z points to a writable allocation of at least -** min(n,32) bytes. +** Make sure pMem->z points to a writable allocation of at least n bytes. ** ** If the bPreserve argument is true, then copy of the content of ** pMem->z into the new allocation. pMem must be either a string or @@ -73857,7 +74735,6 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre assert( pMem->szMalloc==0 || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) ); - if( n<32 ) n = 32; if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); bPreserve = 0; @@ -73895,34 +74772,40 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre ** ** Any prior string or blob content in the pMem object may be discarded. ** The pMem->xDel destructor is called, if it exists. Though MEM_Str -** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null -** values are preserved. +** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, MEM_IntReal, +** and MEM_Null values are preserved. ** ** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM) ** if unable to complete the resizing. */ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ - assert( szNew>0 ); + assert( CORRUPT_DB || szNew>0 ); assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 ); if( pMem->szMallocflags & MEM_Dyn)==0 ); pMem->z = pMem->zMalloc; - pMem->flags &= (MEM_Null|MEM_Int|MEM_Real); + pMem->flags &= (MEM_Null|MEM_Int|MEM_Real|MEM_IntReal); return SQLITE_OK; } /* ** It is already known that pMem contains an unterminated string. ** Add the zero terminator. +** +** Three bytes of zero are added. In this way, there is guaranteed +** to be a double-zero byte at an even byte boundary in order to +** terminate a UTF16 string, even if the initial size of the buffer +** is an odd number of bytes. */ static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ - if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ + if( sqlite3VdbeMemGrow(pMem, pMem->n+3, 1) ){ return SQLITE_NOMEM_BKPT; } pMem->z[pMem->n] = 0; pMem->z[pMem->n+1] = 0; + pMem->z[pMem->n+2] = 0; pMem->flags |= MEM_Term; return SQLITE_OK; } @@ -73959,13 +74842,15 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; assert( pMem->flags & MEM_Zero ); - assert( pMem->flags&MEM_Blob ); + assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) ); + testcase( sqlite3_value_nochange(pMem) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); /* Set nByte to the number of bytes required to store the expanded blob. */ nByte = pMem->n + pMem->u.nZero; if( nByte<=0 ){ + if( (pMem->flags & MEM_Blob)==0 ) return SQLITE_OK; nByte = 1; } if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ @@ -73994,12 +74879,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ } /* -** Add MEM_Str to the set of representations for the given Mem. Numbers -** are converted using sqlite3_snprintf(). Converting a BLOB to a string -** is a no-op. +** Add MEM_Str to the set of representations for the given Mem. This +** routine is only called if pMem is a number of some kind, not a NULL +** or a BLOB. ** -** Existing representations MEM_Int and MEM_Real are invalidated if -** bForce is true but are retained if bForce is false. +** Existing representations MEM_Int, MEM_Real, or MEM_IntReal are invalidated +** if bForce is true but are retained if bForce is false. ** ** A MEM_Null value will never be passed to this function. This function is ** used for converting values to text for returning to the user (i.e. via @@ -74008,13 +74893,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ ** user and the latter is an internal programming error. */ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ - int fg = pMem->flags; const int nByte = 32; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( !(fg&MEM_Zero) ); - assert( !(fg&(MEM_Str|MEM_Blob)) ); - assert( fg&(MEM_Int|MEM_Real) ); + assert( !(pMem->flags&MEM_Zero) ); + assert( !(pMem->flags&(MEM_Str|MEM_Blob)) ); + assert( pMem->flags&(MEM_Int|MEM_Real|MEM_IntReal) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -74024,22 +74908,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ return SQLITE_NOMEM_BKPT; } - /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 - ** string representation of the value. Then, if the required encoding - ** is UTF-16le or UTF-16be do a translation. - ** - ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. - */ - if( fg & MEM_Int ){ - sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i); - }else{ - assert( fg & MEM_Real ); - sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r); - } - pMem->n = sqlite3Strlen30(pMem->z); + vdbeMemRenderNum(nByte, pMem->z, pMem); + assert( pMem->z!=0 ); + pMem->n = sqlite3Strlen30NN(pMem->z); pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str|MEM_Term; - if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real); + if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); sqlite3VdbeChangeEncoding(pMem, enc); return SQLITE_OK; } @@ -74213,7 +75087,8 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); flags = pMem->flags; - if( flags & MEM_Int ){ + if( flags & (MEM_Int|MEM_IntReal) ){ + testcase( flags & MEM_IntReal ); return pMem->u.i; }else if( flags & MEM_Real ){ return doubleToInt64(pMem->u.r); @@ -74242,7 +75117,8 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( pMem->flags & MEM_Real ){ return pMem->u.r; - }else if( pMem->flags & MEM_Int ){ + }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pMem->flags & MEM_IntReal ); return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ return memRealValue(pMem); @@ -74257,7 +75133,8 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ ** Return the value ifNull if pMem is NULL. */ SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){ - if( pMem->flags & MEM_Int ) return pMem->u.i!=0; + testcase( pMem->flags & MEM_IntReal ); + if( pMem->flags & (MEM_Int|MEM_IntReal) ) return pMem->u.i!=0; if( pMem->flags & MEM_Null ) return ifNull; return sqlite3VdbeRealValue(pMem)!=0.0; } @@ -74320,17 +75197,21 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ /* Compare a floating point value to an integer. Return true if the two ** values are the same within the precision of the floating point value. ** +** This function assumes that i was obtained by assignment from r1. +** ** For some versions of GCC on 32-bit machines, if you do the more obvious ** comparison of "r1==(double)i" you sometimes get an answer of false even ** though the r1 and (double)i values are bit-for-bit the same. */ -static int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ +SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ double r2 = (double)i; - return memcmp(&r1, &r2, sizeof(r1))==0; + return r1==0.0 + || (memcmp(&r1, &r2, sizeof(r1))==0 + && i >= -2251799813685248LL && i < 2251799813685248LL); } /* -** Convert pMem so that it has types MEM_Real or MEM_Int or both. +** Convert pMem so that it has type MEM_Real or MEM_Int. ** Invalidate any prior representations. ** ** Every effort is made to force the conversion, even if the input @@ -74338,25 +75219,26 @@ static int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ ** as much of the string as we can and ignore the rest. */ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ - if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_Real ); + testcase( pMem->flags & MEM_IntReal ); + testcase( pMem->flags & MEM_Null ); + if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){ int rc; + sqlite3_int64 ix; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc); - if( rc==0 ){ + rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1) + || sqlite3RealSameAsInt(pMem->u.r, (ix = (i64)pMem->u.r)) + ){ + pMem->u.i = ix; MemSetTypeFlag(pMem, MEM_Int); }else{ - i64 i = pMem->u.i; - sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); - if( rc==1 && sqlite3RealSameAsInt(pMem->u.r, i) ){ - pMem->u.i = i; - MemSetTypeFlag(pMem, MEM_Int); - }else{ - MemSetTypeFlag(pMem, MEM_Real); - } + MemSetTypeFlag(pMem, MEM_Real); } } - assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 ); + assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))!=0 ); pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero); return SQLITE_OK; } @@ -74399,7 +75281,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ pMem->flags |= (pMem->flags&MEM_Blob)>>3; sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); - pMem->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero); + pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero); break; } } @@ -74583,7 +75465,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ ** dual type, are allowed, as long as the underlying value is the ** same. */ u16 mFlags = pMem->flags & pX->flags & pX->mScopyFlags; - assert( (mFlags&MEM_Int)==0 || pMem->u.i==pX->u.i ); + assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i ); assert( (mFlags&MEM_Real)==0 || pMem->u.r==pX->u.r ); assert( (mFlags&MEM_Str)==0 || (pMem->n==pX->n && pMem->z==pX->z) ); assert( (mFlags&MEM_Blob)==0 || sqlite3BlobCompare(pMem,pX)==0 ); @@ -74705,7 +75587,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( assert( enc!=0 ); if( enc==SQLITE_UTF8 ){ nByte = 0x7fffffff & (int)strlen(z); - if( nByte>iLimit ) nByte = iLimit+1; }else{ for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){} } @@ -74717,29 +75598,30 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( ** management (one of MEM_Dyn or MEM_Static). */ if( xDel==SQLITE_TRANSIENT ){ - int nAlloc = nByte; + u32 nAlloc = nByte; if( flags&MEM_Term ){ nAlloc += (enc==SQLITE_UTF8?1:2); } if( nByte>iLimit ){ - return SQLITE_TOOBIG; + return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); } testcase( nAlloc==0 ); testcase( nAlloc==31 ); testcase( nAlloc==32 ); - if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){ + if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){ return SQLITE_NOMEM_BKPT; } memcpy(pMem->z, z, nAlloc); - }else if( xDel==SQLITE_DYNAMIC ){ - sqlite3VdbeMemRelease(pMem); - pMem->zMalloc = pMem->z = (char *)z; - pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); }else{ sqlite3VdbeMemRelease(pMem); pMem->z = (char *)z; - pMem->xDel = xDel; - flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); + if( xDel==SQLITE_DYNAMIC ){ + pMem->zMalloc = pMem->z; + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); + }else{ + pMem->xDel = xDel; + flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); + } } pMem->n = nByte; @@ -74782,6 +75664,9 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize( ){ int rc; pMem->flags = MEM_Null; + if( sqlite3BtreeMaxRecordSize(pCur)z); if( rc==SQLITE_OK ){ @@ -74855,7 +75740,7 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 || pVal->db->mallocFailed ); if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ - assert( sqlite3VdbeMemConsistentDualRep(pVal) ); + assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; }else{ return 0; @@ -74878,7 +75763,7 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( !sqlite3VdbeMemIsRowSet(pVal) ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ - assert( sqlite3VdbeMemConsistentDualRep(pVal) ); + assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; } if( pVal->flags&MEM_Null ){ @@ -75143,7 +76028,12 @@ static int valueFromExpr( }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); } - if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str; + assert( (pVal->flags & MEM_IntReal)==0 ); + if( pVal->flags & (MEM_Int|MEM_IntReal|MEM_Real) ){ + testcase( pVal->flags & MEM_Int ); + testcase( pVal->flags & MEM_Real ); + pVal->flags &= ~MEM_Str; + } if( enc!=SQLITE_UTF8 ){ rc = sqlite3VdbeChangeEncoding(pVal, enc); } @@ -75166,7 +76056,7 @@ static int valueFromExpr( }else if( op==TK_NULL ){ pVal = valueNew(db, pCtx); if( pVal==0 ) goto no_mem; - sqlite3VdbeMemNumerify(pVal); + sqlite3VdbeMemSetNull(pVal); } #ifndef SQLITE_OMIT_BLOB_LITERAL else if( op==TK_BLOB ){ @@ -75188,9 +76078,11 @@ static int valueFromExpr( } #endif else if( op==TK_TRUEFALSE ){ - pVal = valueNew(db, pCtx); - pVal->flags = MEM_Int; - pVal->u.i = pExpr->u.zToken[4]==0; + pVal = valueNew(db, pCtx); + if( pVal ){ + pVal->flags = MEM_Int; + pVal->u.i = pExpr->u.zToken[4]==0; + } } *ppVal = pVal; @@ -75583,7 +76475,7 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){ pParse->pVdbe = p; assert( pParse->aLabel==0 ); assert( pParse->nLabel==0 ); - assert( pParse->nOpAlloc==0 ); + assert( p->nOpAlloc==0 ); assert( pParse->szOpAlloc==0 ); sqlite3VdbeAddOp2(p, OP_Init, 0, 1); return p; @@ -75613,6 +76505,43 @@ SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlag p->zSql = sqlite3DbStrNDup(p->db, z, n); } +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Add a new element to the Vdbe->pDblStr list. +*/ +SQLITE_PRIVATE void sqlite3VdbeAddDblquoteStr(sqlite3 *db, Vdbe *p, const char *z){ + if( p ){ + int n = sqlite3Strlen30(z); + DblquoteStr *pStr = sqlite3DbMallocRawNN(db, + sizeof(*pStr)+n+1-sizeof(pStr->z)); + if( pStr ){ + pStr->pNextStr = p->pDblStr; + p->pDblStr = pStr; + memcpy(pStr->z, z, n+1); + } + } +} +#endif + +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** zId of length nId is a double-quoted identifier. Check to see if +** that identifier is really used as a string literal. +*/ +SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString( + Vdbe *pVdbe, /* The prepared statement */ + const char *zId /* The double-quoted identifier, already dequoted */ +){ + DblquoteStr *pStr; + assert( zId!=0 ); + if( pVdbe->pDblStr==0 ) return 0; + for(pStr=pVdbe->pDblStr; pStr; pStr=pStr->pNextStr){ + if( strcmp(zId, pStr->z)==0 ) return 1; + } + return 0; +} +#endif + /* ** Swap all content between two VDBE structures. */ @@ -75632,6 +76561,11 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; +#if 0 + zTmp = pA->zNormSql; + pA->zNormSql = pB->zNormSql; + pB->zNormSql = zTmp; +#endif pB->expmask = pA->expmask; pB->prepFlags = pA->prepFlags; memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter)); @@ -75644,7 +76578,7 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ ** to 1024/sizeof(Op). ** ** If an out-of-memory error occurs while resizing the array, return -** SQLITE_NOMEM. In this case Vdbe.aOp and Parse.nOpAlloc remain +** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain ** unchanged (this is so that any opcodes already allocated can be ** correctly deallocated along with the rest of the Vdbe). */ @@ -75660,9 +76594,11 @@ static int growOpArray(Vdbe *v, int nOp){ ** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current ** size of the op array or add 1KB of space, whichever is smaller. */ #ifdef SQLITE_TEST_REALLOC_STRESS - int nNew = (p->nOpAlloc>=512 ? p->nOpAlloc*2 : p->nOpAlloc+nOp); + sqlite3_int64 nNew = (v->nOpAlloc>=512 ? 2*(sqlite3_int64)v->nOpAlloc + : (sqlite3_int64)v->nOpAlloc+nOp); #else - int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op))); + sqlite3_int64 nNew = (v->nOpAlloc ? 2*(sqlite3_int64)v->nOpAlloc + : (sqlite3_int64)(1024/sizeof(Op))); UNUSED_PARAMETER(nOp); #endif @@ -75673,11 +76609,11 @@ static int growOpArray(Vdbe *v, int nOp){ } assert( nOp<=(1024/sizeof(Op)) ); - assert( nNew>=(p->nOpAlloc+nOp) ); + assert( nNew>=(v->nOpAlloc+nOp) ); pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); if( pNew ){ p->szOpAlloc = sqlite3DbMallocSize(p->db, pNew); - p->nOpAlloc = p->szOpAlloc/sizeof(Op); + v->nOpAlloc = p->szOpAlloc/sizeof(Op); v->aOp = pNew; } return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT); @@ -75711,9 +76647,9 @@ static void test_addop_breakpoint(void){ ** operand. */ static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){ - assert( p->pParse->nOpAlloc<=p->nOp ); + assert( p->nOpAlloc<=p->nOp ); if( growOpArray(p, 1) ) return 1; - assert( p->pParse->nOpAlloc>p->nOp ); + assert( p->nOpAlloc>p->nOp ); return sqlite3VdbeAddOp3(p, op, p1, p2, p3); } SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ @@ -75723,7 +76659,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ i = p->nOp; assert( p->magic==VDBE_MAGIC_INIT ); assert( op>=0 && op<0xff ); - if( p->pParse->nOpAlloc<=i ){ + if( p->nOpAlloc<=i ){ return growOp3(p, op, p1, p2, p3); } p->nOp++; @@ -75855,13 +76791,29 @@ SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse *pParse){ } /* -** Add a new OP_Explain opcode. +** Set a debugger breakpoint on the following routine in order to +** monitor the EXPLAIN QUERY PLAN code generation. +*/ +#if defined(SQLITE_DEBUG) +SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char *z1, const char *z2){ + (void)z1; + (void)z2; +} +#endif + +/* +** Add a new OP_ opcode. ** ** If the bPush flag is true, then make this opcode the parent for ** subsequent Explains until sqlite3VdbeExplainPop() is called. */ SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ - if( pParse->explain==2 ){ +#ifndef SQLITE_DEBUG + /* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined. + ** But omit them (for performance) during production builds */ + if( pParse->explain==2 ) +#endif + { char *zMsg; Vdbe *v; va_list ap; @@ -75873,7 +76825,10 @@ SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt iThis = v->nOp; sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0, zMsg, P4_DYNAMIC); - if( bPush) pParse->addrExplain = iThis; + sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetOp(v,-1)->p4.z); + if( bPush){ + pParse->addrExplain = iThis; + } } } @@ -75881,6 +76836,7 @@ SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt ** Pop the EXPLAIN QUERY PLAN stack one level. */ SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse *pParse){ + sqlite3ExplainBreakpoint("POP", 0); pParse->addrExplain = sqlite3VdbeExplainParent(pParse); } #endif /* SQLITE_OMIT_EXPLAIN */ @@ -75945,21 +76901,22 @@ SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){ ** The VDBE knows that a P2 value is a label because labels are ** always negative and P2 values are suppose to be non-negative. ** Hence, a negative P2 value is a label that has yet to be resolved. +** (Later:) This is only true for opcodes that have the OPFLG_JUMP +** property. +** +** Variable usage notes: ** -** Zero is returned if a malloc() fails. +** Parse.aLabel[x] Stores the address that the x-th label resolves +** into. For testing (SQLITE_DEBUG), unresolved +** labels stores -1, but that is not required. +** Parse.nLabelAlloc Number of slots allocated to Parse.aLabel[] +** Parse.nLabel The *negative* of the number of labels that have +** been issued. The negative is stored because +** that gives a performance improvement over storing +** the equivalent positive value. */ -SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){ - Parse *p = v->pParse; - int i = p->nLabel++; - assert( v->magic==VDBE_MAGIC_INIT ); - if( (i & (i-1))==0 ){ - p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, - (i*2+1)*sizeof(p->aLabel[0])); - } - if( p->aLabel ){ - p->aLabel[i] = -1; - } - return ADDR(i); +SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse *pParse){ + return --pParse->nLabel; } /* @@ -75967,18 +76924,35 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){ ** be inserted. The parameter "x" must have been obtained from ** a prior call to sqlite3VdbeMakeLabel(). */ +static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){ + int nNewSize = 10 - p->nLabel; + p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, + nNewSize*sizeof(p->aLabel[0])); + if( p->aLabel==0 ){ + p->nLabelAlloc = 0; + }else{ +#ifdef SQLITE_DEBUG + int i; + for(i=p->nLabelAlloc; iaLabel[i] = -1; +#endif + p->nLabelAlloc = nNewSize; + p->aLabel[j] = v->nOp; + } +} SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){ Parse *p = v->pParse; int j = ADDR(x); assert( v->magic==VDBE_MAGIC_INIT ); - assert( jnLabel ); + assert( j<-p->nLabel ); assert( j>=0 ); - if( p->aLabel ){ #ifdef SQLITE_DEBUG - if( p->db->flags & SQLITE_VdbeAddopTrace ){ - printf("RESOLVE LABEL %d to %d\n", x, v->nOp); - } + if( p->db->flags & SQLITE_VdbeAddopTrace ){ + printf("RESOLVE LABEL %d to %d\n", x, v->nOp); + } #endif + if( p->nLabelAlloc + p->nLabel < 0 ){ + resizeResolveLabel(p,v,j); + }else{ assert( p->aLabel[j]==(-1) ); /* Labels may only be resolved once */ p->aLabel[j] = v->nOp; } @@ -76094,6 +77068,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ int hasAbort = 0; int hasFkCounter = 0; int hasCreateTable = 0; + int hasCreateIndex = 0; int hasInitCoroutine = 0; Op *pOp; VdbeOpIter sIter; @@ -76103,13 +77078,23 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ while( (pOp = opIterNext(&sIter))!=0 ){ int opcode = pOp->opcode; if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename + || opcode==OP_VDestroy + || (opcode==OP_Function0 && pOp->p4.pFunc->funcFlags&SQLITE_FUNC_INTERNAL) || ((opcode==OP_Halt || opcode==OP_HaltIfNull) - && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort)) + && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort)) ){ hasAbort = 1; break; } if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1; + if( mayAbort ){ + /* hasCreateIndex may also be set for some DELETE statements that use + ** OP_Clear. So this routine may end up returning true in the case + ** where a "DELETE FROM tbl" has a statement-journal but does not + ** require one. This is not so bad - it is an inefficiency, not a bug. */ + if( opcode==OP_CreateBtree && pOp->p3==BTREE_BLOBKEY ) hasCreateIndex = 1; + if( opcode==OP_Clear ) hasCreateIndex = 1; + } if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1; #ifndef SQLITE_OMIT_FOREIGN_KEY if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){ @@ -76125,7 +77110,8 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ ** true for this case to prevent the assert() in the callers frame ** from failing. */ return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter - || (hasCreateTable && hasInitCoroutine) ); + || (hasCreateTable && hasInitCoroutine) || hasCreateIndex + ); } #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ @@ -76253,7 +77239,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to ** have non-negative values for P2. */ assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ); - assert( ADDR(pOp->p2)nLabel ); + assert( ADDR(pOp->p2)<-pParse->nLabel ); pOp->p2 = aLabel[ADDR(pOp->p2)]; } break; @@ -76292,7 +77278,7 @@ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){ */ #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){ - assert( p->nOp + N <= p->pParse->nOpAlloc ); + assert( p->nOp + N <= p->nOpAlloc ); } #endif @@ -76364,7 +77350,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList( VdbeOp *pOut, *pFirst; assert( nOp>0 ); assert( p->magic==VDBE_MAGIC_INIT ); - if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){ + if( p->nOp + nOp > p->nOpAlloc && growOpArray(p, nOp) ){ return 0; } pFirst = pOut = &p->aOp[p->nOp]; @@ -76410,7 +77396,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus( LogEst nEst, /* Estimated number of output rows */ const char *zName /* Name of table or index being scanned */ ){ - int nByte = (p->nScan+1) * sizeof(ScanStatus); + sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); ScanStatus *aNew; aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); if( aNew ){ @@ -76997,7 +77983,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ Mem *pMem = pOp->p4.pMem; if( pMem->flags & MEM_Str ){ zP4 = pMem->z; - }else if( pMem->flags & MEM_Int ){ + }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){ sqlite3_str_appendf(&x, "%lld", pMem->u.i); }else if( pMem->flags & MEM_Real ){ sqlite3_str_appendf(&x, "%.16g", pMem->u.r); @@ -77531,9 +78517,9 @@ SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){ ** of a ReusableSpace object by the allocSpace() routine below. */ struct ReusableSpace { - u8 *pSpace; /* Available memory */ - int nFree; /* Bytes of available memory */ - int nNeeded; /* Total bytes that could not be allocated */ + u8 *pSpace; /* Available memory */ + sqlite3_int64 nFree; /* Bytes of available memory */ + sqlite3_int64 nNeeded; /* Total bytes that could not be allocated */ }; /* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf @@ -77553,7 +78539,7 @@ struct ReusableSpace { static void *allocSpace( struct ReusableSpace *p, /* Bulk memory available for allocation */ void *pBuf, /* Pointer to a prior allocation */ - int nByte /* Bytes of memory needed */ + sqlite3_int64 nByte /* Bytes of memory needed */ ){ assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) ); if( pBuf==0 ){ @@ -77686,19 +78672,27 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( ** the leftover memory at the end of the opcode array. This can significantly ** reduce the amount of memory held by a prepared statement. */ - do { - x.nNeeded = 0; - p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem)); - p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem)); - p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*)); - p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*)); + x.nNeeded = 0; + p->aMem = allocSpace(&x, 0, nMem*sizeof(Mem)); + p->aVar = allocSpace(&x, 0, nVar*sizeof(Mem)); + p->apArg = allocSpace(&x, 0, nArg*sizeof(Mem*)); + p->apCsr = allocSpace(&x, 0, nCursor*sizeof(VdbeCursor*)); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS - p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64)); + p->anExec = allocSpace(&x, 0, p->nOp*sizeof(i64)); #endif - if( x.nNeeded==0 ) break; + if( x.nNeeded ){ x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded); x.nFree = x.nNeeded; - }while( !db->mallocFailed ); + if( !db->mallocFailed ){ + p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem)); + p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem)); + p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*)); + p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*)); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64)); +#endif + } + } p->pVList = pParse->pVList; pParse->pVList = 0; @@ -78351,7 +79345,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ } /* Check for immediate foreign key violations. */ - if( p->rc==SQLITE_OK ){ + if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ sqlite3VdbeCheckFk(p, 0); } @@ -78390,7 +79384,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ }else{ db->nDeferredCons = 0; db->nDeferredImmCons = 0; - db->flags &= ~SQLITE_DeferFKs; + db->flags &= ~(u64)SQLITE_DeferFKs; sqlite3CommitInternalChanges(db); } }else{ @@ -78703,6 +79697,16 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); +#ifdef SQLITE_ENABLE_NORMALIZE + sqlite3DbFree(db, p->zNormSql); + { + DblquoteStr *pThis, *pNext; + for(pThis=p->pDblStr; pThis; pThis=pNext){ + pNext = pThis->pNextStr; + sqlite3DbFree(db, pThis); + } + } +#endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS { int i; @@ -78867,6 +79871,8 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){ /* ** Return the serial-type for the value stored in pMem. +** +** This routine might convert a large MEM_IntReal value into MEM_Real. */ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ int flags = pMem->flags; @@ -78877,11 +79883,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ *pLen = 0; return 0; } - if( flags&MEM_Int ){ + if( flags&(MEM_Int|MEM_IntReal) ){ /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ # define MAX_6BYTE ((((i64)0x00008000)<<32)-1) i64 i = pMem->u.i; u64 u; + testcase( flags & MEM_Int ); + testcase( flags & MEM_IntReal ); if( i<0 ){ u = ~i; }else{ @@ -78901,6 +79909,15 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ if( u<=2147483647 ){ *pLen = 4; return 4; } if( u<=MAX_6BYTE ){ *pLen = 6; return 5; } *pLen = 8; + if( flags&MEM_IntReal ){ + /* If the value is IntReal and is going to take up 8 bytes to store + ** as an integer, then we might as well make it an 8-byte floating + ** point value */ + pMem->u.r = (double)pMem->u.i; + pMem->flags &= ~MEM_IntReal; + pMem->flags |= MEM_Real; + return 7; + } return 6; } if( flags&MEM_Real ){ @@ -79074,7 +80091,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ ** routine so that in most cases the overhead of moving the stack pointer ** is avoided. */ -static u32 SQLITE_NOINLINE serialGet( +static u32 serialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ @@ -79106,7 +80123,7 @@ static u32 SQLITE_NOINLINE serialGet( assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); swapMixedEndianFloat(x); memcpy(&pMem->u.r, &x, sizeof(x)); - pMem->flags = sqlite3IsNaN(pMem->u.r) ? MEM_Null : MEM_Real; + pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real; } return 8; } @@ -79242,7 +80259,7 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( UnpackedRecord *p /* Populate this structure before returning. */ ){ const unsigned char *aKey = (const unsigned char *)pKey; - int d; + u32 d; u32 idx; /* Offset in aKey[] to read from */ u16 u; /* Unsigned loop counter */ u32 szHdr; @@ -79253,7 +80270,7 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( idx = getVarint32(aKey, szHdr); d = szHdr; u = 0; - while( idx=p->nField ) break; } + if( d>(u32)nKey && u ){ + assert( CORRUPT_DB ); + /* In a corrupt record entry, the last pMem might have been set up using + ** uninitialized memory. Overwrite its value with NULL, to prevent + ** warnings from MSAN. */ + sqlite3VdbeMemSetNull(pMem-1); + } assert( u<=pKeyInfo->nKeyField + 1 ); p->nField = u; } @@ -79331,8 +80355,8 @@ static int vdbeRecordCompareDebug( ** Use that approximation to avoid the more expensive call to ** sqlite3VdbeSerialTypeLen() in the common case. */ - if( d1+serial_type1+2>(u32)nKey1 - && d1+sqlite3VdbeSerialTypeLen(serial_type1)>(u32)nKey1 + if( d1+(u64)serial_type1+2>(u64)nKey1 + && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1 ){ break; } @@ -79343,7 +80367,8 @@ static int vdbeRecordCompareDebug( /* Do the comparison */ - rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]); + rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], + pKeyInfo->nAllField>i ? pKeyInfo->aColl[i] : 0); if( rc!=0 ){ assert( mem1.szMalloc==0 ); /* See comment below */ if( pKeyInfo->aSortOrder[i] ){ @@ -79548,8 +80573,13 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C /* At least one of the two values is a number */ - if( combined_flags&(MEM_Int|MEM_Real) ){ - if( (f1 & f2 & MEM_Int)!=0 ){ + if( combined_flags&(MEM_Int|MEM_Real|MEM_IntReal) ){ + testcase( combined_flags & MEM_Int ); + testcase( combined_flags & MEM_Real ); + testcase( combined_flags & MEM_IntReal ); + if( (f1 & f2 & (MEM_Int|MEM_IntReal))!=0 ){ + testcase( f1 & f2 & MEM_Int ); + testcase( f1 & f2 & MEM_IntReal ); if( pMem1->u.i < pMem2->u.i ) return -1; if( pMem1->u.i > pMem2->u.i ) return +1; return 0; @@ -79559,15 +80589,23 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C if( pMem1->u.r > pMem2->u.r ) return +1; return 0; } - if( (f1&MEM_Int)!=0 ){ + if( (f1&(MEM_Int|MEM_IntReal))!=0 ){ + testcase( f1 & MEM_Int ); + testcase( f1 & MEM_IntReal ); if( (f2&MEM_Real)!=0 ){ return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r); + }else if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ + if( pMem1->u.i < pMem2->u.i ) return -1; + if( pMem1->u.i > pMem2->u.i ) return +1; + return 0; }else{ return -1; } } if( (f1&MEM_Real)!=0 ){ - if( (f2&MEM_Int)!=0 ){ + if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ + testcase( f2 & MEM_Int ); + testcase( f2 & MEM_IntReal ); return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r); }else{ return -1; @@ -79699,12 +80737,12 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( }else{ idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; - if( d1>(unsigned)nKey1 ){ - pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; - return 0; /* Corruption */ - } i = 0; } + if( d1>(unsigned)nKey1 ){ + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ + } VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField @@ -79716,7 +80754,9 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( u32 serial_type; /* RHS is an integer */ - if( pRhs->flags & MEM_Int ){ + if( pRhs->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pRhs->flags & MEM_Int ); + testcase( pRhs->flags & MEM_IntReal ); serial_type = aKey1[idx1]; testcase( serial_type==12 ); if( serial_type>=10 ){ @@ -79774,10 +80814,12 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( mem1.n = (serial_type - 12) / 2; testcase( (d1+mem1.n)==(unsigned)nKey1 ); testcase( (d1+mem1.n+1)==(unsigned)nKey1 ); - if( (d1+mem1.n) > (unsigned)nKey1 ){ + if( (d1+mem1.n) > (unsigned)nKey1 + || (pKeyInfo = pPKey2->pKeyInfo)->nAllField<=i + ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ - }else if( (pKeyInfo = pPKey2->pKeyInfo)->aColl[i] ){ + }else if( pKeyInfo->aColl[i] ){ mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; mem1.flags = MEM_Str; @@ -80059,7 +81101,9 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ testcase( flags & MEM_Real ); testcase( flags & MEM_Null ); testcase( flags & MEM_Blob ); - if( (flags & (MEM_Real|MEM_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){ + if( (flags & (MEM_Real|MEM_IntReal|MEM_Null|MEM_Blob))==0 + && p->pKeyInfo->aColl[0]==0 + ){ assert( flags & MEM_Str ); return vdbeRecordCompareString; } @@ -80104,7 +81148,9 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ (void)getVarint32((u8*)m.z, szHdr); testcase( szHdr==3 ); testcase( szHdr==m.n ); - if( unlikely(szHdr<3 || (int)szHdr>m.n) ){ + testcase( szHdr>0x7fffffff ); + assert( m.n>=0 ); + if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){ goto idx_rowid_corruption; } @@ -80475,14 +81521,16 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ sqlite3_int64 iNow; sqlite3_int64 iElapse; assert( p->startTime>0 ); - assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 ); + assert( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 ); assert( db->init.busy==0 ); assert( p->zSql!=0 ); sqlite3OsCurrentTimeInt64(db->pVfs, &iNow); iElapse = (iNow - p->startTime)*1000000; +#ifndef SQLITE_OMIT_DEPRECATED if( db->xProfile ){ db->xProfile(db->pProfileArg, p->zSql, iElapse); } +#endif if( db->mTrace & SQLITE_TRACE_PROFILE ){ db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse); } @@ -80645,39 +81693,86 @@ SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){ */ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ static const u8 aType[] = { - SQLITE_BLOB, /* 0x00 */ - SQLITE_NULL, /* 0x01 */ - SQLITE_TEXT, /* 0x02 */ - SQLITE_NULL, /* 0x03 */ - SQLITE_INTEGER, /* 0x04 */ - SQLITE_NULL, /* 0x05 */ - SQLITE_INTEGER, /* 0x06 */ - SQLITE_NULL, /* 0x07 */ - SQLITE_FLOAT, /* 0x08 */ - SQLITE_NULL, /* 0x09 */ - SQLITE_FLOAT, /* 0x0a */ - SQLITE_NULL, /* 0x0b */ - SQLITE_INTEGER, /* 0x0c */ - SQLITE_NULL, /* 0x0d */ - SQLITE_INTEGER, /* 0x0e */ - SQLITE_NULL, /* 0x0f */ - SQLITE_BLOB, /* 0x10 */ - SQLITE_NULL, /* 0x11 */ - SQLITE_TEXT, /* 0x12 */ - SQLITE_NULL, /* 0x13 */ - SQLITE_INTEGER, /* 0x14 */ - SQLITE_NULL, /* 0x15 */ - SQLITE_INTEGER, /* 0x16 */ - SQLITE_NULL, /* 0x17 */ - SQLITE_FLOAT, /* 0x18 */ - SQLITE_NULL, /* 0x19 */ - SQLITE_FLOAT, /* 0x1a */ - SQLITE_NULL, /* 0x1b */ - SQLITE_INTEGER, /* 0x1c */ - SQLITE_NULL, /* 0x1d */ - SQLITE_INTEGER, /* 0x1e */ - SQLITE_NULL, /* 0x1f */ + SQLITE_BLOB, /* 0x00 (not possible) */ + SQLITE_NULL, /* 0x01 NULL */ + SQLITE_TEXT, /* 0x02 TEXT */ + SQLITE_NULL, /* 0x03 (not possible) */ + SQLITE_INTEGER, /* 0x04 INTEGER */ + SQLITE_NULL, /* 0x05 (not possible) */ + SQLITE_INTEGER, /* 0x06 INTEGER + TEXT */ + SQLITE_NULL, /* 0x07 (not possible) */ + SQLITE_FLOAT, /* 0x08 FLOAT */ + SQLITE_NULL, /* 0x09 (not possible) */ + SQLITE_FLOAT, /* 0x0a FLOAT + TEXT */ + SQLITE_NULL, /* 0x0b (not possible) */ + SQLITE_INTEGER, /* 0x0c (not possible) */ + SQLITE_NULL, /* 0x0d (not possible) */ + SQLITE_INTEGER, /* 0x0e (not possible) */ + SQLITE_NULL, /* 0x0f (not possible) */ + SQLITE_BLOB, /* 0x10 BLOB */ + SQLITE_NULL, /* 0x11 (not possible) */ + SQLITE_TEXT, /* 0x12 (not possible) */ + SQLITE_NULL, /* 0x13 (not possible) */ + SQLITE_INTEGER, /* 0x14 INTEGER + BLOB */ + SQLITE_NULL, /* 0x15 (not possible) */ + SQLITE_INTEGER, /* 0x16 (not possible) */ + SQLITE_NULL, /* 0x17 (not possible) */ + SQLITE_FLOAT, /* 0x18 FLOAT + BLOB */ + SQLITE_NULL, /* 0x19 (not possible) */ + SQLITE_FLOAT, /* 0x1a (not possible) */ + SQLITE_NULL, /* 0x1b (not possible) */ + SQLITE_INTEGER, /* 0x1c (not possible) */ + SQLITE_NULL, /* 0x1d (not possible) */ + SQLITE_INTEGER, /* 0x1e (not possible) */ + SQLITE_NULL, /* 0x1f (not possible) */ + SQLITE_FLOAT, /* 0x20 INTREAL */ + SQLITE_NULL, /* 0x21 (not possible) */ + SQLITE_TEXT, /* 0x22 INTREAL + TEXT */ + SQLITE_NULL, /* 0x23 (not possible) */ + SQLITE_FLOAT, /* 0x24 (not possible) */ + SQLITE_NULL, /* 0x25 (not possible) */ + SQLITE_FLOAT, /* 0x26 (not possible) */ + SQLITE_NULL, /* 0x27 (not possible) */ + SQLITE_FLOAT, /* 0x28 (not possible) */ + SQLITE_NULL, /* 0x29 (not possible) */ + SQLITE_FLOAT, /* 0x2a (not possible) */ + SQLITE_NULL, /* 0x2b (not possible) */ + SQLITE_FLOAT, /* 0x2c (not possible) */ + SQLITE_NULL, /* 0x2d (not possible) */ + SQLITE_FLOAT, /* 0x2e (not possible) */ + SQLITE_NULL, /* 0x2f (not possible) */ + SQLITE_BLOB, /* 0x30 (not possible) */ + SQLITE_NULL, /* 0x31 (not possible) */ + SQLITE_TEXT, /* 0x32 (not possible) */ + SQLITE_NULL, /* 0x33 (not possible) */ + SQLITE_FLOAT, /* 0x34 (not possible) */ + SQLITE_NULL, /* 0x35 (not possible) */ + SQLITE_FLOAT, /* 0x36 (not possible) */ + SQLITE_NULL, /* 0x37 (not possible) */ + SQLITE_FLOAT, /* 0x38 (not possible) */ + SQLITE_NULL, /* 0x39 (not possible) */ + SQLITE_FLOAT, /* 0x3a (not possible) */ + SQLITE_NULL, /* 0x3b (not possible) */ + SQLITE_FLOAT, /* 0x3c (not possible) */ + SQLITE_NULL, /* 0x3d (not possible) */ + SQLITE_FLOAT, /* 0x3e (not possible) */ + SQLITE_NULL, /* 0x3f (not possible) */ }; +#ifdef SQLITE_DEBUG + { + int eType = SQLITE_BLOB; + if( pVal->flags & MEM_Null ){ + eType = SQLITE_NULL; + }else if( pVal->flags & (MEM_Real|MEM_IntReal) ){ + eType = SQLITE_FLOAT; + }else if( pVal->flags & MEM_Int ){ + eType = SQLITE_INTEGER; + }else if( pVal->flags & MEM_Str ){ + eType = SQLITE_TEXT; + } + assert( eType == aType[pVal->flags&MEM_AffMask] ); + } +#endif return aType[pVal->flags&MEM_AffMask]; } @@ -80686,6 +81781,11 @@ SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){ return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero); } +/* Return true if a parameter value originated from an sqlite3_bind() */ +SQLITE_API int sqlite3_value_frombind(sqlite3_value *pVal){ + return (pVal->flags&MEM_FromBind)!=0; +} + /* Make a copy of an sqlite3_value object */ SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){ @@ -80922,6 +82022,21 @@ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ sqlite3OomFault(pCtx->pOut->db); } +#ifndef SQLITE_UNTESTABLE +/* Force the INT64 value currently stored as the result to be +** a MEM_IntReal value. See the SQLITE_TESTCTRL_RESULT_INTREAL +** test-control. +*/ +SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context *pCtx){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + if( pCtx->pOut->flags & MEM_Int ){ + pCtx->pOut->flags &= ~MEM_Int; + pCtx->pOut->flags |= MEM_IntReal; + } +} +#endif + + /* ** This function is called after a transaction has been committed. It ** invokes callbacks registered with sqlite3_wal_hook() as required. @@ -80996,7 +82111,7 @@ static int sqlite3Step(Vdbe *p){ return SQLITE_NOMEM_BKPT; } - if( p->pc<=0 && p->expired ){ + if( p->pc<0 && p->expired ){ p->rc = SQLITE_SCHEMA; rc = SQLITE_ERROR; goto end_of_step; @@ -81015,7 +82130,7 @@ static int sqlite3Step(Vdbe *p){ ); #ifndef SQLITE_OMIT_TRACE - if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0) + if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 && !db->init.busy && p->zSql ){ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime); }else{ @@ -81042,16 +82157,18 @@ static int sqlite3Step(Vdbe *p){ db->nVdbeExec--; } + if( rc!=SQLITE_ROW ){ #ifndef SQLITE_OMIT_TRACE - /* If the statement completed successfully, invoke the profile callback */ - if( rc!=SQLITE_ROW ) checkProfileCallback(db, p); + /* If the statement completed successfully, invoke the profile callback */ + checkProfileCallback(db, p); #endif - if( rc==SQLITE_DONE && db->autoCommit ){ - assert( p->rc==SQLITE_OK ); - p->rc = doWalCallbacks(db); - if( p->rc!=SQLITE_OK ){ - rc = SQLITE_ERROR; + if( rc==SQLITE_DONE && db->autoCommit ){ + assert( p->rc==SQLITE_OK ); + p->rc = doWalCallbacks(db); + if( p->rc!=SQLITE_OK ){ + rc = SQLITE_ERROR; + } } } @@ -81071,9 +82188,9 @@ static int sqlite3Step(Vdbe *p){ || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE ); assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp ); - if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 - && rc!=SQLITE_ROW - && rc!=SQLITE_DONE + if( rc!=SQLITE_ROW + && rc!=SQLITE_DONE + && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){ /* If this statement was prepared using saved SQL and an ** error has occurred, then return the error code in p->rc to the @@ -81529,10 +82646,10 @@ SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){ ** or a constant) then useTypes 2, 3, and 4 return NULL. */ static const void *columnName( - sqlite3_stmt *pStmt, - int N, - const void *(*xFunc)(Mem*), - int useType + sqlite3_stmt *pStmt, /* The statement */ + int N, /* Which column to get the name for */ + int useUtf16, /* True to return the name as UTF16 */ + int useType /* What type of name */ ){ const void *ret; Vdbe *p; @@ -81553,8 +82670,15 @@ static const void *columnName( N += useType*n; sqlite3_mutex_enter(db->mutex); assert( db->mallocFailed==0 ); - ret = xFunc(&p->aColName[N]); - /* A malloc may have failed inside of the xFunc() call. If this +#ifndef SQLITE_OMIT_UTF16 + if( useUtf16 ){ + ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]); + }else +#endif + { + ret = sqlite3_value_text((sqlite3_value*)&p->aColName[N]); + } + /* A malloc may have failed inside of the _text() call. If this ** is the case, clear the mallocFailed flag and return NULL. */ if( db->mallocFailed ){ @@ -81571,13 +82695,11 @@ static const void *columnName( ** statement pStmt. */ SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME); + return columnName(pStmt, N, 0, COLNAME_NAME); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME); + return columnName(pStmt, N, 1, COLNAME_NAME); } #endif @@ -81596,13 +82718,11 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ ** of the result set of SQL statement pStmt. */ SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE); + return columnName(pStmt, N, 0, COLNAME_DECLTYPE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE); + return columnName(pStmt, N, 1, COLNAME_DECLTYPE); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_DECLTYPE */ @@ -81614,13 +82734,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE); + return columnName(pStmt, N, 0, COLNAME_DATABASE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE); + return columnName(pStmt, N, 1, COLNAME_DATABASE); } #endif /* SQLITE_OMIT_UTF16 */ @@ -81630,13 +82748,11 @@ SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE); + return columnName(pStmt, N, 0, COLNAME_TABLE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE); + return columnName(pStmt, N, 1, COLNAME_TABLE); } #endif /* SQLITE_OMIT_UTF16 */ @@ -81646,13 +82762,11 @@ SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN); + return columnName(pStmt, N, 0, COLNAME_COLUMN); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN); + return columnName(pStmt, N, 1, COLNAME_COLUMN); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_ENABLE_COLUMN_METADATA */ @@ -81695,7 +82809,7 @@ static int vdbeUnbind(Vdbe *p, int i){ pVar = &p->aVar[i]; sqlite3VdbeMemRelease(pVar); pVar->flags = MEM_Null; - sqlite3Error(p->db, SQLITE_OK); + p->db->errCode = SQLITE_OK; /* If the bit corresponding to this variable in Vdbe.expmask is set, then ** binding a new value to this variable invalidates the current query plan. @@ -82020,6 +83134,14 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){ return pStmt ? ((Vdbe*)pStmt)->readOnly : 1; } +/* +** Return 1 if the statement is an EXPLAIN and return 2 if the +** statement is an EXPLAIN QUERY PLAN +*/ +SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){ + return pStmt ? ((Vdbe*)pStmt)->explain : 0; +} + /* ** Return true if the prepared statement is in need of being reset. */ @@ -82115,6 +83237,22 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){ #endif } +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Return the normalized SQL associated with a prepared statement. +*/ +SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe *)pStmt; + if( p==0 ) return 0; + if( p->zNormSql==0 && ALWAYS(p->zSql!=0) ){ + sqlite3_mutex_enter(p->db->mutex); + p->zNormSql = sqlite3Normalize(p, p->zSql); + sqlite3_mutex_leave(p->db->mutex); + } + return p->zNormSql; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ + #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Allocate and populate an UnpackedRecord structure based on the serialized @@ -82185,7 +83323,9 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa }else if( iIdx>=p->pUnpacked->nField ){ *ppValue = (sqlite3_value *)columnNullValue(); }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ - if( pMem->flags & MEM_Int ){ + if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pMem); } } @@ -82504,7 +83644,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( pVar = &p->aVar[idx-1]; if( pVar->flags & MEM_Null ){ sqlite3_str_append(&out, "NULL", 4); - }else if( pVar->flags & MEM_Int ){ + }else if( pVar->flags & (MEM_Int|MEM_IntReal) ){ sqlite3_str_appendf(&out, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ sqlite3_str_appendf(&out, "%!.15g", pVar->u.r); @@ -82693,12 +83833,20 @@ SQLITE_API int sqlite3_found_count = 0; ** feature is used for test suite validation only and does not appear an ** production builds. ** -** M is an integer between 2 and 4. 2 indicates a ordinary two-way -** branch (I=0 means fall through and I=1 means taken). 3 indicates -** a 3-way branch where the third way is when one of the operands is -** NULL. 4 indicates the OP_Jump instruction which has three destinations -** depending on whether the first operand is less than, equal to, or greater -** than the second. +** M is the type of branch. I is the direction taken for this instance of +** the branch. +** +** M: 2 - two-way branch (I=0: fall-thru 1: jump ) +** 3 - two-way + NULL (I=0: fall-thru 1: jump 2: NULL ) +** 4 - OP_Jump (I=0: jump p1 1: jump p2 2: jump p3) +** +** In other words, if M is 2, then I is either 0 (for fall-through) or +** 1 (for when the branch is taken). If M is 3, the I is 0 for an +** ordinary fall-through, I is 1 if the branch was taken, and I is 2 +** if the result of comparison is NULL. For M=3, I=2 the jump may or +** may not be taken, depending on the SQLITE_JUMPIFNULL flags in p5. +** When M is 4, that means that an OP_Jump is being run. I is 0, 1, or 2 +** depending on if the operands are less than, equal, or greater than. ** ** iSrcLine is the source code line (from the __LINE__ macro) that ** generated the VDBE instruction combined with flag bits. The source @@ -82709,9 +83857,9 @@ SQLITE_API int sqlite3_found_count = 0; ** alternate branch are never taken. If a branch is never taken then ** flags should be 0x06 since only the fall-through approach is allowed. ** -** Bit 0x04 of the flags indicates an OP_Jump opcode that is only +** Bit 0x08 of the flags indicates an OP_Jump opcode that is only ** interested in equal or not-equal. In other words, I==0 and I==2 -** should be treated the same. +** should be treated as equivalent ** ** Since only a line number is retained, not the filename, this macro ** only works for amalgamation builds. But that is ok, since these macros @@ -82735,6 +83883,18 @@ SQLITE_API int sqlite3_found_count = 0; mNever = iSrcLine >> 24; assert( (I & mNever)==0 ); if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ + /* Invoke the branch coverage callback with three arguments: + ** iSrcLine - the line number of the VdbeCoverage() macro, with + ** flags removed. + ** I - Mask of bits 0x07 indicating which cases are are + ** fulfilled by this instance of the jump. 0x01 means + ** fall-thru, 0x02 means taken, 0x04 means NULL. Any + ** impossible cases (ex: if the comparison is never NULL) + ** are filled in automatically so that the coverage + ** measurement logic does not flag those impossible cases + ** as missed coverage. + ** M - Type of jump. Same as M argument above + */ I |= mNever; if( M==2 ) I |= 0x04; if( M==4 ){ @@ -82746,14 +83906,6 @@ SQLITE_API int sqlite3_found_count = 0; } #endif -/* -** Convert the given register into a string if it isn't one -** already. Return non-zero if a malloc() fails. -*/ -#define Stringify(P, enc) \ - if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc,0)) \ - { goto no_mem; } - /* ** An ephemeral string value (signified by the MEM_Ephem flag) contains ** a pointer to a dynamically allocated string where some other entity @@ -82811,6 +83963,11 @@ static VdbeCursor *allocateCursor( assert( iCur>=0 && iCurnCursor ); if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/ + /* Before calling sqlite3VdbeFreeCursor(), ensure the isEphemeral flag + ** is clear. Otherwise, if this is an ephemeral cursor created by + ** OP_OpenDup, the cursor will not be closed and will still be part + ** of a BtShared.pCursor list. */ + if( p->apCsr[iCur]->pBtx==0 ) p->apCsr[iCur]->isEphemeral = 0; sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); p->apCsr[iCur] = 0; } @@ -82830,6 +83987,21 @@ static VdbeCursor *allocateCursor( return pCx; } +/* +** The string in pRec is known to look like an integer and to have a +** floating point value of rValue. Return true and set *piValue to the +** integer value if the string is in range to be an integer. Otherwise, +** return false. +*/ +static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){ + i64 iValue = (double)rValue; + if( sqlite3RealSameAsInt(rValue,iValue) ){ + *piValue = iValue; + return 1; + } + return 0==sqlite3Atoi64(pRec->z, piValue, pRec->n, pRec->enc); +} + /* ** Try to convert a value into a numeric representation if we can ** do so without loss of information. In other words, if the string @@ -82847,12 +84019,12 @@ static VdbeCursor *allocateCursor( */ static void applyNumericAffinity(Mem *pRec, int bTryForInt){ double rValue; - i64 iValue; u8 enc = pRec->enc; - assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str ); - if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; - if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ - pRec->u.i = iValue; + int rc; + assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str ); + rc = sqlite3AtoF(pRec->z, &rValue, pRec->n, enc); + if( rc<=0 ) return; + if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){ pRec->flags |= MEM_Int; }else{ pRec->u.r = rValue; @@ -82906,11 +84078,14 @@ static void applyAffinity( ** there is already a string rep, but it is pointless to waste those ** CPU cycles. */ if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/ - if( (pRec->flags&(MEM_Real|MEM_Int)) ){ + if( (pRec->flags&(MEM_Real|MEM_Int|MEM_IntReal)) ){ + testcase( pRec->flags & MEM_Int ); + testcase( pRec->flags & MEM_Real ); + testcase( pRec->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pRec, enc, 1); } } - pRec->flags &= ~(MEM_Real|MEM_Int); + pRec->flags &= ~(MEM_Real|MEM_Int|MEM_IntReal); } } @@ -82949,12 +84124,21 @@ SQLITE_PRIVATE void sqlite3ValueApplyAffinity( ** accordingly. */ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ - assert( (pMem->flags & (MEM_Int|MEM_Real))==0 ); + int rc; + sqlite3_int64 ix; + assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ); assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ); - if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){ - return 0; - } - if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==0 ){ + ExpandBlob(pMem); + rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + if( rc<=0 ){ + if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){ + pMem->u.i = ix; + return MEM_Int; + }else{ + return MEM_Real; + } + }else if( rc==1 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){ + pMem->u.i = ix; return MEM_Int; } return MEM_Real; @@ -82968,10 +84152,15 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ ** But it does set pMem->u.r and pMem->u.i appropriately. */ static u16 numericType(Mem *pMem){ - if( pMem->flags & (MEM_Int|MEM_Real) ){ - return pMem->flags & (MEM_Int|MEM_Real); + if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal) ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_Real ); + testcase( pMem->flags & MEM_IntReal ); + return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal); } if( pMem->flags & (MEM_Str|MEM_Blob) ){ + testcase( pMem->flags & MEM_Str ); + testcase( pMem->flags & MEM_Blob ); return computeNumericType(pMem); } return 0; @@ -83067,6 +84256,8 @@ static void memTracePrint(Mem *p){ printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL"); }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ printf(" si:%lld", p->u.i); + }else if( (p->flags & (MEM_IntReal))!=0 ){ + printf(" ir:%lld", p->u.i); }else if( p->flags & MEM_Int ){ printf(" i:%lld", p->u.i); #ifndef SQLITE_OMIT_FLOATING_POINT @@ -83276,6 +84467,15 @@ SQLITE_PRIVATE int sqlite3VdbeExec( assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ sqlite3VdbeEnter(p); +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + if( db->xProgress ){ + u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; + assert( 0 < db->nProgressOps ); + nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps); + }else{ + nProgressLimit = 0xffffffff; + } +#endif if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ @@ -83289,15 +84489,6 @@ SQLITE_PRIVATE int sqlite3VdbeExec( db->busyHandler.nBusy = 0; if( db->u1.isInterrupted ) goto abort_due_to_interrupt; sqlite3VdbeIOTraceSql(p); -#ifndef SQLITE_OMIT_PROGRESS_CALLBACK - if( db->xProgress ){ - u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; - assert( 0 < db->nProgressOps ); - nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps); - }else{ - nProgressLimit = 0xffffffff; - } -#endif #ifdef SQLITE_DEBUG sqlite3BeginBenignMalloc(); if( p->pc==0 @@ -83473,10 +84664,11 @@ case OP_Goto: { /* jump */ ** If the progress callback returns non-zero, exit the virtual machine with ** a return code SQLITE_ABORT. */ - if( nVmStep>=nProgressLimit && db->xProgress!=0 ){ + while( nVmStep>=nProgressLimit && db->xProgress!=0 ){ assert( db->nProgressOps!=0 ); - nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps); + nProgressLimit += db->nProgressOps; if( db->xProgress(db->pProgressArg) ){ + nProgressLimit = 0xffffffff; rc = SQLITE_INTERRUPT; goto abort_due_to_error; } @@ -83755,6 +84947,7 @@ case OP_String8: { /* same as TK_STRING, out2 */ if( encoding!=SQLITE_UTF8 ){ rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG ); + if( rc ) goto too_big; if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z ); assert( VdbeMemDynamic(pOut)==0 ); @@ -83767,7 +84960,6 @@ case OP_String8: { /* same as TK_STRING, out2 */ pOp->p4.z = pOut->z; pOp->p1 = pOut->n; } - testcase( rc==SQLITE_TOOBIG ); #endif if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; @@ -83889,7 +85081,10 @@ case OP_Variable: { /* out2 */ goto too_big; } pOut = &aMem[pOp->p2]; - sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static); + if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut); + memcpy(pOut, pVar, MEMCELLSIZE); + pOut->flags &= ~(MEM_Dyn|MEM_Ephem); + pOut->flags |= MEM_Static|MEM_FromBind; UPDATE_MAX_BLOBSIZE(pOut); break; } @@ -84022,18 +85217,6 @@ case OP_ResultRow: { assert( pOp->p1>0 ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); -#ifndef SQLITE_OMIT_PROGRESS_CALLBACK - /* Run the progress counter just before returning. - */ - if( db->xProgress!=0 - && nVmStep>=nProgressLimit - && db->xProgress(db->pProgressArg)!=0 - ){ - rc = SQLITE_INTERRUPT; - goto abort_due_to_error; - } -#endif - /* If this statement has violated immediate foreign key constraints, do ** not return the number of rows modified. And do not RELEASE the statement ** transaction. It needs to be rolled back. */ @@ -84105,33 +85288,57 @@ case OP_ResultRow: { ** to avoid a memcpy(). */ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ - i64 nByte; + i64 nByte; /* Total size of the output string or blob */ + u16 flags1; /* Initial flags for P1 */ + u16 flags2; /* Initial flags for P2 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; pOut = &aMem[pOp->p3]; + testcase( pIn1==pIn2 ); + testcase( pOut==pIn2 ); assert( pIn1!=pOut ); - if( (pIn1->flags | pIn2->flags) & MEM_Null ){ + flags1 = pIn1->flags; + testcase( flags1 & MEM_Null ); + testcase( pIn2->flags & MEM_Null ); + if( (flags1 | pIn2->flags) & MEM_Null ){ sqlite3VdbeMemSetNull(pOut); break; } - if( ExpandBlob(pIn1) || ExpandBlob(pIn2) ) goto no_mem; - Stringify(pIn1, encoding); - Stringify(pIn2, encoding); + if( (flags1 & (MEM_Str|MEM_Blob))==0 ){ + if( sqlite3VdbeMemStringify(pIn1,encoding,0) ) goto no_mem; + flags1 = pIn1->flags & ~MEM_Str; + }else if( (flags1 & MEM_Zero)!=0 ){ + if( sqlite3VdbeMemExpandBlob(pIn1) ) goto no_mem; + flags1 = pIn1->flags & ~MEM_Str; + } + flags2 = pIn2->flags; + if( (flags2 & (MEM_Str|MEM_Blob))==0 ){ + if( sqlite3VdbeMemStringify(pIn2,encoding,0) ) goto no_mem; + flags2 = pIn2->flags & ~MEM_Str; + }else if( (flags2 & MEM_Zero)!=0 ){ + if( sqlite3VdbeMemExpandBlob(pIn2) ) goto no_mem; + flags2 = pIn2->flags & ~MEM_Str; + } nByte = pIn1->n + pIn2->n; if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } - if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){ + if( sqlite3VdbeMemGrow(pOut, (int)nByte+3, pOut==pIn2) ){ goto no_mem; } MemSetTypeFlag(pOut, MEM_Str); if( pOut!=pIn2 ){ memcpy(pOut->z, pIn2->z, pIn2->n); + assert( (pIn2->flags & MEM_Dyn) == (flags2 & MEM_Dyn) ); + pIn2->flags = flags2; } memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); + assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); + pIn1->flags = flags1; pOut->z[nByte]=0; pOut->z[nByte+1] = 0; + pOut->z[nByte+2] = 0; pOut->flags |= MEM_Term; pOut->n = (int)nByte; pOut->enc = encoding; @@ -84182,7 +85389,6 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ - char bIntint; /* Started out as two integer operands */ u16 flags; /* Combined MEM_* flags from both inputs */ u16 type1; /* Numeric type of left operand */ u16 type2; /* Numeric type of right operand */ @@ -84200,7 +85406,6 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ if( (type1 & type2 & MEM_Int)!=0 ){ iA = pIn1->u.i; iB = pIn2->u.i; - bIntint = 1; switch( pOp->opcode ){ case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break; case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break; @@ -84223,7 +85428,6 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ }else if( (flags & MEM_Null)!=0 ){ goto arithmetic_result_is_null; }else{ - bIntint = 0; fp_math: rA = sqlite3VdbeRealValue(pIn1); rB = sqlite3VdbeRealValue(pIn2); @@ -84238,8 +85442,8 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ break; } default: { - iA = (i64)rA; - iB = (i64)rB; + iA = sqlite3VdbeIntValue(pIn1); + iB = sqlite3VdbeIntValue(pIn2); if( iA==0 ) goto arithmetic_result_is_null; if( iA==-1 ) iA = 1; rB = (double)(iB % iA); @@ -84255,9 +85459,6 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ } pOut->u.r = rB; MemSetTypeFlag(pOut, MEM_Real); - if( ((type1|type2)&MEM_Real)==0 && !bIntint ){ - sqlite3VdbeIntegerAffinity(pOut); - } #endif } break; @@ -84399,8 +85600,8 @@ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if( (pIn1->flags & MEM_Int)==0 ){ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); - VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2); if( (pIn1->flags & MEM_Int)==0 ){ + VdbeBranchTaken(1, 2); if( pOp->p2==0 ){ rc = SQLITE_MISMATCH; goto abort_due_to_error; @@ -84409,6 +85610,7 @@ case OP_MustBeInt: { /* jump, in1 */ } } } + VdbeBranchTaken(0, 2); MemSetTypeFlag(pIn1, MEM_Int); break; } @@ -84425,7 +85627,9 @@ case OP_MustBeInt: { /* jump, in1 */ */ case OP_RealAffinity: { /* in1 */ pIn1 = &aMem[pOp->p1]; - if( pIn1->flags & MEM_Int ){ + if( pIn1->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pIn1->flags & MEM_Int ); + testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pIn1); } break; @@ -84583,15 +85787,15 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ ** OP_Eq or OP_Ne) then take the jump or not depending on whether ** or not both operands are null. */ - assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne ); assert( (flags1 & MEM_Cleared)==0 ); - assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 ); + assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 || CORRUPT_DB ); + testcase( (pOp->p5 & SQLITE_JUMPIFNULL)!=0 ); if( (flags1&flags3&MEM_Null)!=0 && (flags3&MEM_Cleared)==0 ){ res = 0; /* Operands are equal */ }else{ - res = 1; /* Operands are not equal */ + res = ((flags3 & MEM_Null) ? -1 : +1); /* Operands are not equal */ } }else{ /* SQLITE_NULLEQ is clear and at least one operand is NULL, @@ -84617,7 +85821,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ - if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); assert( flags3==pIn3->flags ); /* testcase( flags3!=pIn3->flags ); @@ -84627,7 +85831,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ ** in case our analysis is incorrect, so it is left in. */ flags3 = pIn3->flags; } - if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } @@ -84640,17 +85844,19 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ goto compare_op; } }else if( affinity==SQLITE_AFF_TEXT ){ - if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){ + if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); + testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); assert( pIn1!=pIn3 ); } - if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){ + if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); + testcase( pIn3->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn3, encoding, 1); testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) ); flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask); @@ -84709,7 +85915,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ pOut->u.i = res2; REGISTER_TRACE(pOp->p2, pOut); }else{ - VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); + VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); if( res2 ){ goto jump_to_p2; } @@ -85259,15 +86465,15 @@ case OP_Column: { zEndHdr = zData + aOffset[0]; testcase( zHdr>=zEndHdr ); do{ - if( (t = zHdr[0])<0x80 ){ + if( (pC->aType[i] = t = zHdr[0])<0x80 ){ zHdr++; offset64 += sqlite3VdbeOneByteSerialTypeLen(t); }else{ zHdr += sqlite3GetVarint32(zHdr, &t); + pC->aType[i] = t; offset64 += sqlite3VdbeSerialTypeLen(t); } - pC->aType[i++] = t; - aOffset[i] = (u32)(offset64 & 0xffffffff); + aOffset[++i] = (u32)(offset64 & 0xffffffff); }while( i<=p2 && zHdrp2>0 ); assert( zAffinity[pOp->p2]==0 ); pIn1 = &aMem[pOp->p1]; - do{ + while( 1 /*edit-by-break*/ ){ assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] ); assert( memIsValid(pIn1) ); - applyAffinity(pIn1, *(zAffinity++), encoding); + applyAffinity(pIn1, zAffinity[0], encoding); + if( zAffinity[0]==SQLITE_AFF_REAL && (pIn1->flags & MEM_Int)!=0 ){ + /* When applying REAL affinity, if the result is still MEM_Int, + ** indicate that REAL is actually desired */ + pIn1->flags |= MEM_IntReal; + pIn1->flags &= ~MEM_Int; + } + REGISTER_TRACE((int)(pIn1-aMem), pIn1); + zAffinity++; + if( zAffinity[0]==0 ) break; pIn1++; - }while( zAffinity[0] ); + } break; } @@ -85432,7 +86647,6 @@ case OP_Affinity: { ** If P4 is NULL then all index fields have the affinity BLOB. */ case OP_MakeRecord: { - u8 *zNewRecord; /* A buffer to hold the data for the new record */ Mem *pRec; /* The new record */ u64 nData; /* Number of bytes of data space */ int nHdr; /* Number of bytes of header space */ @@ -85445,9 +86659,9 @@ case OP_MakeRecord: { int nField; /* Number of fields in the record */ char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ - int i; /* Space used in zNewRecord[] header */ - int j; /* Space used in zNewRecord[] content */ u32 len; /* Length of a field */ + u8 *zHdr; /* Where to write next byte of the header */ + u8 *zPayload; /* Where to write next byte of the payload */ /* Assuming the record contains N fields, the record format looks ** like this: @@ -85486,7 +86700,14 @@ case OP_MakeRecord: { if( zAffinity ){ pRec = pData0; do{ - applyAffinity(pRec++, *(zAffinity++), encoding); + applyAffinity(pRec, zAffinity[0], encoding); + if( zAffinity[0]==SQLITE_AFF_REAL && (pRec->flags & MEM_Int) ){ + pRec->flags |= MEM_IntReal; + pRec->flags &= ~(MEM_Int); + } + REGISTER_TRACE((int)(pRec-aMem), pRec); + zAffinity++; + pRec++; assert( zAffinity[0]==0 || pRec<=pLast ); }while( zAffinity[0] ); } @@ -85554,46 +86775,54 @@ case OP_MakeRecord: { if( nVarintdb->aLimit[SQLITE_LIMIT_LENGTH] ){ - goto too_big; - } /* Make sure the output register has a buffer large enough to store ** the new record. The output register (pOp->p3) is not allowed to ** be one of the input registers (because the following call to ** sqlite3VdbeMemClearAndResize() could clobber the value before it is used). */ - if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ - goto no_mem; + if( nByte+nZero<=pOut->szMalloc ){ + /* The output register is already large enough to hold the record. + ** No error checks or buffer enlargement is required */ + pOut->z = pOut->zMalloc; + }else{ + /* Need to make sure that the output is not too big and then enlarge + ** the output register to hold the full result */ + if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){ + goto too_big; + } + if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ + goto no_mem; + } + } + pOut->n = (int)nByte; + pOut->flags = MEM_Blob; + if( nZero ){ + pOut->u.nZero = nZero; + pOut->flags |= MEM_Zero; } - zNewRecord = (u8 *)pOut->z; + UPDATE_MAX_BLOBSIZE(pOut); + zHdr = (u8 *)pOut->z; + zPayload = zHdr + nHdr; /* Write the record */ - i = putVarint32(zNewRecord, nHdr); - j = nHdr; + zHdr += putVarint32(zHdr, nHdr); assert( pData0<=pLast ); pRec = pData0; do{ serial_type = pRec->uTemp; /* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more ** additional varints, one per column. */ - i += putVarint32(&zNewRecord[i], serial_type); /* serial type */ + zHdr += putVarint32(zHdr, serial_type); /* serial type */ /* EVIDENCE-OF: R-64536-51728 The values for each column in the record ** immediately follow the header. */ - j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */ + zPayload += sqlite3VdbeSerialPut(zPayload, pRec, serial_type); /* content */ }while( (++pRec)<=pLast ); - assert( i==nHdr ); - assert( j==nByte ); + assert( nHdr==(int)(zHdr - (u8*)pOut->z) ); + assert( nByte==(int)(zPayload - (u8*)pOut->z) ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); - pOut->n = (int)nByte; - pOut->flags = MEM_Blob; - if( nZero ){ - pOut->u.nZero = nZero; - pOut->flags |= MEM_Zero; - } REGISTER_TRACE(pOp->p3, pOut); - UPDATE_MAX_BLOBSIZE(pOut); break; } @@ -85623,8 +86852,9 @@ case OP_Count: { /* out2 */ /* Opcode: Savepoint P1 * * P4 * ** ** Open, release or rollback the savepoint named by parameter P4, depending -** on the value of P1. To open a new savepoint, P1==0. To release (commit) an -** existing savepoint, P1==1, or to rollback an existing savepoint P1==2. +** on the value of P1. To open a new savepoint set P1==0 (SAVEPOINT_BEGIN). +** To release (commit) an existing savepoint set P1==1 (SAVEPOINT_RELEASE). +** To rollback an existing savepoint set P1==2 (SAVEPOINT_ROLLBACK). */ case OP_Savepoint: { int p1; /* Value of P1 operand */ @@ -85692,6 +86922,7 @@ case OP_Savepoint: { } } }else{ + assert( p1==SAVEPOINT_RELEASE || p1==SAVEPOINT_ROLLBACK ); iSavepoint = 0; /* Find the named savepoint. If there is no such savepoint, then an @@ -85745,6 +86976,7 @@ case OP_Savepoint: { if( rc!=SQLITE_OK ) goto abort_due_to_error; } }else{ + assert( p1==SAVEPOINT_RELEASE ); isSchemaChange = 0; } for(ii=0; iinDb; ii++){ @@ -85781,6 +87013,7 @@ case OP_Savepoint: { db->nSavepoint--; } }else{ + assert( p1==SAVEPOINT_ROLLBACK ); db->nDeferredCons = pSavepoint->nDeferredCons; db->nDeferredImmCons = pSavepoint->nDeferredImmCons; } @@ -86261,7 +87494,9 @@ case OP_OpenDup: { pCx->isEphemeral = 1; pCx->pKeyInfo = pOrig->pKeyInfo; pCx->isTable = pOrig->isTable; - rc = sqlite3BtreeCursor(pOrig->pBtx, MASTER_ROOT, BTREE_WRCSR, + pCx->pgnoRoot = pOrig->pgnoRoot; + pCx->isOrdered = pOrig->isOrdered; + rc = sqlite3BtreeCursor(pOrig->pBtx, pCx->pgnoRoot, BTREE_WRCSR, pCx->pKeyInfo, pCx->uc.pCursor); /* The sqlite3BtreeCursor() routine can only fail for the first cursor ** opened for a database. Since there is already an open cursor when this @@ -86279,6 +87514,9 @@ case OP_OpenDup: { ** the main database is read-only. The ephemeral ** table is deleted automatically when the cursor is closed. ** +** If the cursor P1 is already opened on an ephemeral table, the table +** is cleared (all content is erased). +** ** P2 is the number of columns in the ephemeral table. ** The cursor points to a BTree table if P4==0 and to a BTree index ** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure @@ -86310,41 +87548,55 @@ case OP_OpenEphemeral: { SQLITE_OPEN_TRANSIENT_DB; assert( pOp->p1>=0 ); assert( pOp->p2>=0 ); - pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE); - if( pCx==0 ) goto no_mem; - pCx->nullRow = 1; - pCx->isEphemeral = 1; - rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, - BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); - if( rc==SQLITE_OK ){ - rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1, 0); - } - if( rc==SQLITE_OK ){ - /* If a transient index is required, create it by calling - ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before - ** opening it. If a transient table is required, just use the - ** automatically created table with root-page 1 (an BLOB_INTKEY table). - */ - if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){ - int pgno; - assert( pOp->p4type==P4_KEYINFO ); - rc = sqlite3BtreeCreateTable(pCx->pBtx, &pgno, BTREE_BLOBKEY | pOp->p5); - if( rc==SQLITE_OK ){ - assert( pgno==MASTER_ROOT+1 ); - assert( pKeyInfo->db==db ); - assert( pKeyInfo->enc==ENC(db) ); - rc = sqlite3BtreeCursor(pCx->pBtx, pgno, BTREE_WRCSR, - pKeyInfo, pCx->uc.pCursor); + pCx = p->apCsr[pOp->p1]; + if( pCx ){ + /* If the ephermeral table is already open, erase all existing content + ** so that the table is empty again, rather than creating a new table. */ + assert( pCx->isEphemeral ); + pCx->seqCount = 0; + pCx->cacheStatus = CACHE_STALE; + if( pCx->pBtx ){ + rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0); + } + }else{ + pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE); + if( pCx==0 ) goto no_mem; + pCx->isEphemeral = 1; + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, + BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, + vfsFlags); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1, 0); + } + if( rc==SQLITE_OK ){ + /* If a transient index is required, create it by calling + ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before + ** opening it. If a transient table is required, just use the + ** automatically created table with root-page 1 (an BLOB_INTKEY table). + */ + if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){ + assert( pOp->p4type==P4_KEYINFO ); + rc = sqlite3BtreeCreateTable(pCx->pBtx, (int*)&pCx->pgnoRoot, + BTREE_BLOBKEY | pOp->p5); + if( rc==SQLITE_OK ){ + assert( pCx->pgnoRoot==MASTER_ROOT+1 ); + assert( pKeyInfo->db==db ); + assert( pKeyInfo->enc==ENC(db) ); + rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR, + pKeyInfo, pCx->uc.pCursor); + } + pCx->isTable = 0; + }else{ + pCx->pgnoRoot = MASTER_ROOT; + rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR, + 0, pCx->uc.pCursor); + pCx->isTable = 1; } - pCx->isTable = 0; - }else{ - rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR, - 0, pCx->uc.pCursor); - pCx->isTable = 1; } + pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); } if( rc ) goto abort_due_to_error; - pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); + pCx->nullRow = 1; break; } @@ -86573,6 +87825,8 @@ case OP_SeekGT: { /* jump, in3, group */ pC->seekOp = pOp->opcode; #endif + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; if( pC->isTable ){ /* The BTREE_SEEK_EQ flag is only set on index cursors */ assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 @@ -86582,20 +87836,24 @@ case OP_SeekGT: { /* jump, in3, group */ ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so convert it. */ pIn3 = &aMem[pOp->p3]; - if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3, 0); } iKey = sqlite3VdbeIntValue(pIn3); /* If the P3 value could not be converted into an integer without ** loss of information, then special processing is required... */ - if( (pIn3->flags & MEM_Int)==0 ){ + if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){ if( (pIn3->flags & MEM_Real)==0 ){ - /* If the P3 value cannot be converted into any kind of a number, - ** then the seek is not possible, so jump to P2 */ - VdbeBranchTaken(1,2); goto jump_to_p2; - break; - } + if( (pIn3->flags & MEM_Null) || oc>=OP_SeekGE ){ + VdbeBranchTaken(1,2); goto jump_to_p2; + break; + }else{ + rc = sqlite3BtreeLast(pC->uc.pCursor, &res); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + goto seek_not_found; + } + }else /* If the approximation iKey is larger than the actual real search ** term, substitute >= for > and < for <=. e.g. if the search term @@ -86619,7 +87877,7 @@ case OP_SeekGT: { /* jump, in3, group */ assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; } - } + } rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res); pC->movetoTarget = iKey; /* Used by OP_Delete */ if( rc!=SQLITE_OK ){ @@ -86673,8 +87931,6 @@ case OP_SeekGT: { /* jump, in3, group */ goto seek_not_found; } } - pC->deferredMoveto = 0; - pC->cacheStatus = CACHE_STALE; #ifdef SQLITE_TEST sqlite3_search_count++; #endif @@ -86974,7 +88230,9 @@ case OP_SeekRowid: { /* jump, in3 */ u64 iKey; pIn3 = &aMem[pOp->p3]; - if( (pIn3->flags & MEM_Int)==0 ){ + testcase( pIn3->flags & MEM_Int ); + testcase( pIn3->flags & MEM_IntReal ); + if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){ /* Make sure pIn3->u.i contains a valid integer representation of ** the key value, but do not change the datatype of the register, as ** other parts of the perpared statement might be depending on the @@ -86994,7 +88252,7 @@ case OP_NotExists: /* jump, in3 */ pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG - pC->seekOp = OP_SeekRowid; + if( pOp->opcode==OP_SeekRowid ) pC->seekOp = OP_SeekRowid; #endif assert( pC->isTable ); assert( pC->eCurType==CURTYPE_BTREE ); @@ -87212,14 +88470,7 @@ case OP_NewRowid: { /* out2 */ ** This instruction only works on tables. The equivalent instruction ** for indices is OP_IdxInsert. */ -/* Opcode: InsertInt P1 P2 P3 P4 P5 -** Synopsis: intkey=P3 data=r[P2] -** -** This works exactly like OP_Insert except that the key is the -** integer value P3, not the value of the integer stored in register P3. -*/ -case OP_Insert: -case OP_InsertInt: { +case OP_Insert: { Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ VdbeCursor *pC; /* Cursor to table into which insert is written */ @@ -87240,16 +88491,11 @@ case OP_InsertInt: { REGISTER_TRACE(pOp->p2, pData); sqlite3VdbeIncrWriteCounter(p, pC); - if( pOp->opcode==OP_Insert ){ - pKey = &aMem[pOp->p3]; - assert( pKey->flags & MEM_Int ); - assert( memIsValid(pKey) ); - REGISTER_TRACE(pOp->p3, pKey); - x.nKey = pKey->u.i; - }else{ - assert( pOp->opcode==OP_InsertInt ); - x.nKey = pOp->p3; - } + pKey = &aMem[pOp->p3]; + assert( pKey->flags & MEM_Int ); + assert( memIsValid(pKey) ); + REGISTER_TRACE(pOp->p3, pKey); + x.nKey = pKey->u.i; if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 ); @@ -87361,7 +88607,7 @@ case OP_Delete: { ** OP_Delete will have also set the pC->movetoTarget field to the rowid of ** the row that is being deleted */ i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor); - assert( pC->movetoTarget==iKey ); + assert( CORRUPT_DB || pC->movetoTarget==iKey ); } #endif @@ -87769,7 +89015,7 @@ case OP_Sort: { /* jump */ p->aCounter[SQLITE_STMTSTATUS_SORT]++; /* Fall through into OP_Rewind */ } -/* Opcode: Rewind P1 P2 * * P5 +/* Opcode: Rewind P1 P2 * * * ** ** The next use of the Rowid or Column or Next instruction for P1 ** will refer to the first entry in the database table or index. @@ -87777,10 +89023,6 @@ case OP_Sort: { /* jump */ ** If the table or index is not empty, fall through to the following ** instruction. ** -** If P5 is non-zero and the table is not empty, then the "skip-next" -** flag is set on the cursor so that the next OP_Next instruction -** executed on it is a no-op. -** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. @@ -87791,6 +89033,7 @@ case OP_Rewind: { /* jump */ int res; assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( pOp->p5==0 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) ); @@ -87805,9 +89048,6 @@ case OP_Rewind: { /* jump */ pCrsr = pC->uc.pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); -#ifndef SQLITE_OMIT_WINDOWFUNC - if( pOp->p5 ) sqlite3BtreeSkipNext(pCrsr); -#endif pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } @@ -87902,7 +89142,7 @@ case OP_Next: /* jump */ assert( pOp->opcode!=OP_Next || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found - || pC->seekOp==OP_NullRow); + || pC->seekOp==OP_NullRow|| pC->seekOp==OP_SeekRowid); assert( pOp->opcode!=OP_Prev || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE || pC->seekOp==OP_Last @@ -88420,7 +89660,7 @@ case OP_ParseSchema: { { zMaster = MASTER_NAME; initData.db = db; - initData.iDb = pOp->p1; + initData.iDb = iDb; initData.pzErrMsg = &p->zErrMsg; initData.mInitFlags = 0; zSql = sqlite3MPrintf(db, @@ -88432,9 +89672,16 @@ case OP_ParseSchema: { assert( db->init.busy==0 ); db->init.busy = 1; initData.rc = SQLITE_OK; + initData.nInitRow = 0; assert( !db->mallocFailed ); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); if( rc==SQLITE_OK ) rc = initData.rc; + if( rc==SQLITE_OK && initData.nInitRow==0 ){ + /* The OP_ParseSchema opcode with a non-NULL P4 argument should parse + ** at least one SQL statement. Any less than that indicates that + ** the sqlite_master table is corrupt. */ + rc = SQLITE_CORRUPT_BKPT; + } sqlite3DbFreeNN(db, zSql); db->init.busy = 0; } @@ -88797,10 +90044,20 @@ case OP_Program: { /* jump */ p->nOp = pProgram->nOp; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS p->anExec = 0; +#endif +#ifdef SQLITE_DEBUG + /* Verify that second and subsequent executions of the same trigger do not + ** try to reuse register values from the first use. */ + { + int i; + for(i=0; inMem; i++){ + aMem[i].pScopyFrom = 0; /* Prevent false-positive AboutToChange() errs */ + aMem[i].flags |= MEM_Undefined; /* Cause a fault if this reg is reused */ + } + } #endif pOp = &aOp[-1]; - - break; + goto check_for_interrupt; } /* Opcode: Param P1 P2 * * * @@ -89172,6 +90429,7 @@ case OP_AggFinal: { assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); #ifndef SQLITE_OMIT_WINDOWFUNC if( pOp->p3 ){ + memAboutToChange(p, &aMem[pOp->p3]); rc = sqlite3VdbeMemAggValue(pMem, &aMem[pOp->p3], pOp->p4.pFunc); pMem = &aMem[pOp->p3]; }else @@ -89336,14 +90594,19 @@ case OP_JournalMode: { /* out2 */ #endif /* SQLITE_OMIT_PRAGMA */ #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) -/* Opcode: Vacuum P1 * * * * +/* Opcode: Vacuum P1 P2 * * * ** ** Vacuum the entire database P1. P1 is 0 for "main", and 2 or more ** for an attached database. The "temp" database may not be vacuumed. +** +** If P2 is not zero, then it is a register holding a string which is +** the file into which the result of vacuum should be written. When +** P2 is zero, the vacuum overwrites the original database. */ case OP_Vacuum: { assert( p->readOnly==0 ); - rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1); + rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1, + pOp->p2 ? &aMem[pOp->p2] : 0); if( rc ) goto abort_due_to_error; break; } @@ -89495,6 +90758,7 @@ case OP_VDestroy: { db->nVDestroy++; rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z); db->nVDestroy--; + assert( p->errorAction==OE_Abort && p->usesStmtJournal ); if( rc ) goto abort_due_to_error; break; } @@ -89617,10 +90881,11 @@ case OP_VFilter: { /* jump */ ** ** If the VColumn opcode is being used to fetch the value of ** an unchanging column during an UPDATE operation, then the P5 -** value is 1. Otherwise, P5 is 0. The P5 value is returned -** by sqlite3_vtab_nochange() routine and can be used -** by virtual table implementations to return special "no-change" -** marks which can be more efficient, depending on the virtual table. +** value is OPFLAG_NOCHNG. This will cause the sqlite3_vtab_nochange() +** function to return true inside the xColumn method of the virtual +** table implementation. The P5 column might also contain other +** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are +** unused by OP_VColumn. */ case OP_VColumn: { sqlite3_vtab *pVtab; @@ -89642,7 +90907,8 @@ case OP_VColumn: { assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); sContext.pOut = pDest; - if( pOp->p5 ){ + testcase( (pOp->p5 & OPFLAG_NOCHNG)==0 && pOp->p5!=0 ); + if( pOp->p5 & OPFLAG_NOCHNG ){ sqlite3VdbeMemSetNull(pDest); pDest->flags = MEM_Null|MEM_Zero; pDest->u.nZero = 0; @@ -89736,7 +91002,7 @@ case OP_VRename: { rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8); if( rc ) goto abort_due_to_error; rc = pVtab->pModule->xRename(pVtab, pName->z); - if( isLegacy==0 ) db->flags &= ~SQLITE_LegacyAlter; + if( isLegacy==0 ) db->flags &= ~(u64)SQLITE_LegacyAlter; sqlite3VtabImportErrmsg(p, pVtab); p->expired = 0; if( rc ) goto abort_due_to_error; @@ -90201,7 +91467,16 @@ default: { /* This is really OP_Noop, OP_Explain */ ** release the mutexes on btrees that were acquired at the ** top. */ vdbe_return: - testcase( nVmStep>0 ); +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + while( nVmStep>=nProgressLimit && db->xProgress!=0 ){ + nProgressLimit += db->nProgressOps; + if( db->xProgress(db->pProgressArg) ){ + nProgressLimit = 0xffffffff; + rc = SQLITE_INTERRUPT; + goto abort_due_to_error; + } + } +#endif p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep; sqlite3VdbeLeave(p); assert( rc!=SQLITE_OK || nExtraDelete==0 @@ -91288,7 +92563,7 @@ static int vdbePmaReadBlob( /* Extend the p->aAlloc[] allocation if required. */ if( p->nAllocnAlloc*2); + sqlite3_int64 nNew = MAX(128, 2*(sqlite3_int64)p->nAlloc); while( nByte>nNew ) nNew = nNew*2; aNew = sqlite3Realloc(p->aAlloc, nNew); if( !aNew ) return SQLITE_NOMEM_BKPT; @@ -92579,15 +93854,19 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( if( nMin>pSorter->nMemory ){ u8 *aNew; - int iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory; - int nNew = pSorter->nMemory * 2; + sqlite3_int64 nNew = 2 * (sqlite3_int64)pSorter->nMemory; + int iListOff = -1; + if( pSorter->list.pList ){ + iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory; + } while( nNew < nMin ) nNew = nNew*2; if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize; if( nNew < nMin ) nNew = nMin; - aNew = sqlite3Realloc(pSorter->list.aMemory, nNew); if( !aNew ) return SQLITE_NOMEM_BKPT; - pSorter->list.pList = (SorterRecord*)&aNew[iListOff]; + if( iListOff>=0 ){ + pSorter->list.pList = (SorterRecord*)&aNew[iListOff]; + } pSorter->list.aMemory = aNew; pSorter->nMemory = nNew; } @@ -93963,6 +95242,22 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){ /* #include */ +#if !defined(SQLITE_OMIT_WINDOWFUNC) +/* +** Walk all expressions linked into the list of Window objects passed +** as the second argument. +*/ +static int walkWindowList(Walker *pWalker, Window *pList){ + Window *pWin; + for(pWin=pList; pWin; pWin=pWin->pNextWin){ + if( sqlite3WalkExprList(pWalker, pWin->pOrderBy) ) return WRC_Abort; + if( sqlite3WalkExprList(pWalker, pWin->pPartition) ) return WRC_Abort; + if( sqlite3WalkExpr(pWalker, pWin->pFilter) ) return WRC_Abort; + } + return WRC_Continue; +} +#endif + /* ** Walk an expression tree. Invoke the callback once for each node ** of the expression, while descending. (In other words, the callback @@ -94001,11 +95296,8 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; } #ifndef SQLITE_OMIT_WINDOWFUNC - if( !ExprHasProperty(pExpr, EP_Reduced) && pExpr->pWin ){ - Window *pWin = pExpr->pWin; - if( sqlite3WalkExprList(pWalker, pWin->pPartition) ) return WRC_Abort; - if( sqlite3WalkExprList(pWalker, pWin->pOrderBy) ) return WRC_Abort; - if( sqlite3WalkExpr(pWalker, pWin->pFilter) ) return WRC_Abort; + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + if( walkWindowList(pWalker, pExpr->y.pWin) ) return WRC_Abort; } #endif } @@ -94045,6 +95337,16 @@ SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){ if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort; if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort; +#if !defined(SQLITE_OMIT_WINDOWFUNC) && !defined(SQLITE_OMIT_ALTERTABLE) + { + Parse *pParse = pWalker->pParse; + if( pParse && IN_RENAME_OBJECT ){ + int rc = walkWindowList(pWalker, p->pWinDefn); + assert( rc==WRC_Continue ); + return rc; + } + } +#endif return WRC_Continue; } @@ -94196,7 +95498,6 @@ static void resolveAlias( if( pExpr->op==TK_COLLATE ){ pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); } - ExprSetProperty(pDup, EP_Alias); /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This ** prevents ExprDelete() from deleting the Expr structure itself, @@ -94265,6 +95566,23 @@ SQLITE_PRIVATE int sqlite3MatchSpanName( return 1; } +/* +** Return TRUE if the double-quoted string mis-feature should be supported. +*/ +static int areDoubleQuotedStringsEnabled(sqlite3 *db, NameContext *pTopNC){ + if( db->init.busy ) return 1; /* Always support for legacy schemas */ + if( pTopNC->ncFlags & NC_IsDDL ){ + /* Currently parsing a DDL statement */ + if( sqlite3WritableSchema(db) && (db->flags & SQLITE_DqsDML)!=0 ){ + return 1; + } + return (db->flags & SQLITE_DqsDDL)!=0; + }else{ + /* Currently parsing a DML statement */ + return (db->flags & SQLITE_DqsDML)!=0; + } +} + /* ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up ** that name in the set of source tables in pSrcList and make the pExpr @@ -94275,7 +95593,7 @@ SQLITE_PRIVATE int sqlite3MatchSpanName( ** (even if X is implied). ** pExpr->iTable Set to the cursor number for the table obtained ** from pSrcList. -** pExpr->pTab Points to the Table structure of X.Y (even if +** pExpr->y.pTab Points to the Table structure of X.Y (even if ** X and/or Y are implied.) ** pExpr->iColumn Set to the column number within the table. ** pExpr->op Set to TK_COLUMN. @@ -94319,7 +95637,6 @@ static int lookupName( /* Initialize the node to no-match */ pExpr->iTable = -1; - pExpr->pTab = 0; ExprSetVVAProperty(pExpr, EP_NoReduce); /* Translate the schema name in zDb into a pointer to the corresponding @@ -94381,7 +95698,7 @@ static int lookupName( continue; } if( IN_RENAME_OBJECT && pItem->zAlias ){ - sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->pTab); + sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab); } } if( 0==(cntTab++) ){ @@ -94407,13 +95724,13 @@ static int lookupName( } if( pMatch ){ pExpr->iTable = pMatch->iCursor; - pExpr->pTab = pMatch->pTab; + pExpr->y.pTab = pMatch->pTab; /* RIGHT JOIN not (yet) supported */ assert( (pMatch->fg.jointype & JT_RIGHT)==0 ); if( (pMatch->fg.jointype & JT_LEFT)!=0 ){ ExprSetProperty(pExpr, EP_CanBeNull); } - pSchema = pExpr->pTab->pSchema; + pSchema = pExpr->y.pTab->pSchema; } } /* if( pSrcList ) */ @@ -94470,7 +95787,7 @@ static int lookupName( testcase( iCol==(-1) ); if( IN_RENAME_OBJECT ){ pExpr->iColumn = iCol; - pExpr->pTab = pTab; + pExpr->y.pTab = pTab; eNewExprOp = TK_COLUMN; }else{ pExpr->iTable = pNC->uNC.pUpsert->regData + iCol; @@ -94492,7 +95809,7 @@ static int lookupName( testcase( iCol==32 ); pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<pTab = pTab; + pExpr->y.pTab = pTab; pExpr->iColumn = (i16)iCol; eNewExprOp = TK_TRIGGER; #endif /* SQLITE_OMIT_TRIGGER */ @@ -94553,6 +95870,10 @@ static int lookupName( sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); return WRC_Abort; } + if( (pNC->ncFlags&NC_AllowWin)==0 && ExprHasProperty(pOrig, EP_Win) ){ + sqlite3ErrorMsg(pParse, "misuse of aliased window function %s",zAs); + return WRC_Abort; + } if( sqlite3ExprVectorSize(pOrig)!=1 ){ sqlite3ErrorMsg(pParse, "row value misused"); return WRC_Abort; @@ -94590,9 +95911,30 @@ static int lookupName( */ if( cnt==0 && zTab==0 ){ assert( pExpr->op==TK_ID ); - if( ExprHasProperty(pExpr,EP_DblQuoted) ){ + if( ExprHasProperty(pExpr,EP_DblQuoted) + && areDoubleQuotedStringsEnabled(db, pTopNC) + ){ + /* If a double-quoted identifier does not match any known column name, + ** then treat it as a string. + ** + ** This hack was added in the early days of SQLite in a misguided attempt + ** to be compatible with MySQL 3.x, which used double-quotes for strings. + ** I now sorely regret putting in this hack. The effect of this hack is + ** that misspelled identifier names are silently converted into strings + ** rather than causing an error, to the frustration of countless + ** programmers. To all those frustrated programmers, my apologies. + ** + ** Someday, I hope to get rid of this hack. Unfortunately there is + ** a huge amount of legacy SQL that uses it. So for now, we just + ** issue a warning. + */ + sqlite3_log(SQLITE_WARNING, + "double-quoted string literal: \"%w\"", zCol); +#ifdef SQLITE_ENABLE_NORMALIZE + sqlite3VdbeAddDblquoteStr(db, pParse->pVdbe, zCol); +#endif pExpr->op = TK_STRING; - pExpr->pTab = 0; + pExpr->y.pTab = 0; return WRC_Prune; } if( sqlite3ExprIdToTrueFalse(pExpr) ){ @@ -94670,9 +96012,9 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); if( p ){ struct SrcList_item *pItem = &pSrc->a[iSrc]; - p->pTab = pItem->pTab; + p->y.pTab = pItem->pTab; p->iTable = pItem->iCursor; - if( p->pTab->iPKey==iCol ){ + if( p->y.pTab->iPKey==iCol ){ p->iColumn = -1; }else{ p->iColumn = (ynVar)iCol; @@ -94762,7 +96104,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pItem = pSrcList->a; assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 ); pExpr->op = TK_COLUMN; - pExpr->pTab = pItem->pTab; + pExpr->y.pTab = pItem->pTab; pExpr->iTable = pItem->iCursor; pExpr->iColumn = -1; pExpr->affinity = SQLITE_AFF_INTEGER; @@ -94806,9 +96148,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ zColumn = pRight->u.zToken; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight); - } - if( IN_RENAME_OBJECT ){ - sqlite3RenameTokenRemap(pParse, (void*)&pExpr->pTab, (void*)pLeft); + sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft); } } return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); @@ -94826,6 +96166,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ const char *zId; /* The function name. */ FuncDef *pDef; /* Information about the function */ u8 enc = ENC(pParse->db); /* The database encoding */ + int savedAllowFlags = (pNC->ncFlags & (NC_AllowAgg | NC_AllowWin)); assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); zId = pExpr->u.zToken; @@ -94841,7 +96182,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ }else{ is_agg = pDef->xFinalize!=0; if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ - ExprSetProperty(pExpr, EP_Unlikely|EP_Skip); + ExprSetProperty(pExpr, EP_Unlikely); if( n==2 ){ pExpr->iTable = exprProbability(pList->a[1].pExpr); if( pExpr->iTable<0 ){ @@ -94890,6 +96231,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr|NC_PartIdx); } + if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 + && pParse->nested==0 + && sqlite3Config.bInternalFunctions==0 + ){ + /* Internal-use-only functions are disallowed unless the + ** SQL is being compiled using sqlite3NestedParse() */ + no_such_func = 1; + pDef = 0; + } } if( 0==IN_RENAME_OBJECT ){ @@ -94898,18 +96248,18 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ || (pDef->xValue==0 && pDef->xInverse==0) || (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize) ); - if( pDef && pDef->xValue==0 && pExpr->pWin ){ + if( pDef && pDef->xValue==0 && ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3ErrorMsg(pParse, "%.*s() may not be used as a window function", nId, zId ); pNC->nErr++; }else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) - || (is_agg && (pDef->funcFlags & SQLITE_FUNC_WINDOW) && !pExpr->pWin) - || (is_agg && pExpr->pWin && (pNC->ncFlags & NC_AllowWin)==0) + || (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pExpr->y.pWin) + || (is_agg && pExpr->y.pWin && (pNC->ncFlags & NC_AllowWin)==0) ){ const char *zType; - if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->pWin ){ + if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->y.pWin ){ zType = "window"; }else{ zType = "aggregate"; @@ -94938,8 +96288,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pNC->nErr++; } if( is_agg ){ + /* Window functions may not be arguments of aggregate functions. + ** Or arguments of other window functions. But aggregate functions + ** may be arguments for window functions. */ #ifndef SQLITE_OMIT_WINDOWFUNC - pNC->ncFlags &= ~(pExpr->pWin ? NC_AllowWin : NC_AllowAgg); + pNC->ncFlags &= ~(NC_AllowWin | (!pExpr->y.pWin ? NC_AllowAgg : 0)); #else pNC->ncFlags &= ~NC_AllowAgg; #endif @@ -94948,19 +96301,21 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ sqlite3WalkExprList(pWalker, pList); if( is_agg ){ #ifndef SQLITE_OMIT_WINDOWFUNC - if( pExpr->pWin ){ + if( pExpr->y.pWin ){ Select *pSel = pNC->pWinSelect; - sqlite3WalkExprList(pWalker, pExpr->pWin->pPartition); - sqlite3WalkExprList(pWalker, pExpr->pWin->pOrderBy); - sqlite3WalkExpr(pWalker, pExpr->pWin->pFilter); - sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->pWin, pDef); + if( IN_RENAME_OBJECT==0 ){ + sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->y.pWin, pDef); + } + sqlite3WalkExprList(pWalker, pExpr->y.pWin->pPartition); + sqlite3WalkExprList(pWalker, pExpr->y.pWin->pOrderBy); + sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter); if( 0==pSel->pWin - || 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->pWin) + || 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->y.pWin) ){ - pExpr->pWin->pNextWin = pSel->pWin; - pSel->pWin = pExpr->pWin; + pExpr->y.pWin->pNextWin = pSel->pWin; + pSel->pWin = pExpr->y.pWin; } - pNC->ncFlags |= NC_AllowWin; + pNC->ncFlags |= NC_HasWin; }else #endif /* SQLITE_OMIT_WINDOWFUNC */ { @@ -94978,8 +96333,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); } - pNC->ncFlags |= NC_AllowAgg; } + pNC->ncFlags |= savedAllowFlags; } /* FIX ME: Compute pExpr->affinity based on the expected return ** type of the function @@ -95010,11 +96365,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ } case TK_IS: case TK_ISNOT: { - Expr *pRight; + Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); assert( !ExprHasProperty(pExpr, EP_Reduced) ); /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE", ** and "x IS NOT FALSE". */ - if( (pRight = pExpr->pRight)->op==TK_ID ){ + if( pRight->op==TK_ID ){ int rc = resolveExprStep(pWalker, pRight); if( rc==WRC_Abort ) return WRC_Abort; if( pRight->op==TK_TRUEFALSE ){ @@ -95230,32 +96585,53 @@ static int resolveCompoundOrderBy( }else{ iCol = resolveAsName(pParse, pEList, pE); if( iCol==0 ){ - pDup = sqlite3ExprDup(db, pE, 0); + /* Now test if expression pE matches one of the values returned + ** by pSelect. In the usual case this is done by duplicating the + ** expression, resolving any symbols in it, and then comparing + ** it against each expression returned by the SELECT statement. + ** Once the comparisons are finished, the duplicate expression + ** is deleted. + ** + ** Or, if this is running as part of an ALTER TABLE operation, + ** resolve the symbols in the actual expression, not a duplicate. + ** And, if one of the comparisons is successful, leave the expression + ** as is instead of transforming it to an integer as in the usual + ** case. This allows the code in alter.c to modify column + ** refererences within the ORDER BY expression as required. */ + if( IN_RENAME_OBJECT ){ + pDup = pE; + }else{ + pDup = sqlite3ExprDup(db, pE, 0); + } if( !db->mallocFailed ){ assert(pDup); iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup); } - sqlite3ExprDelete(db, pDup); + if( !IN_RENAME_OBJECT ){ + sqlite3ExprDelete(db, pDup); + } } } if( iCol>0 ){ /* Convert the ORDER BY term into an integer column number iCol, ** taking care to preserve the COLLATE clause if it exists */ - Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); - if( pNew==0 ) return 1; - pNew->flags |= EP_IntValue; - pNew->u.iValue = iCol; - if( pItem->pExpr==pE ){ - pItem->pExpr = pNew; - }else{ - Expr *pParent = pItem->pExpr; - assert( pParent->op==TK_COLLATE ); - while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft; - assert( pParent->pLeft==pE ); - pParent->pLeft = pNew; + if( !IN_RENAME_OBJECT ){ + Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); + if( pNew==0 ) return 1; + pNew->flags |= EP_IntValue; + pNew->u.iValue = iCol; + if( pItem->pExpr==pE ){ + pItem->pExpr = pNew; + }else{ + Expr *pParent = pItem->pExpr; + assert( pParent->op==TK_COLLATE ); + while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft; + assert( pParent->pLeft==pE ); + pParent->pLeft = pNew; + } + sqlite3ExprDelete(db, pE); + pItem->u.x.iOrderByCol = (u16)iCol; } - sqlite3ExprDelete(db, pE); - pItem->u.x.iOrderByCol = (u16)iCol; pItem->done = 1; }else{ moreToDo = 1; @@ -95314,6 +96690,38 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy( return 0; } +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** Walker callback for resolveRemoveWindows(). +*/ +static int resolveRemoveWindowsCb(Walker *pWalker, Expr *pExpr){ + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + Window **pp; + for(pp=&pWalker->u.pSelect->pWin; *pp; pp=&(*pp)->pNextWin){ + if( *pp==pExpr->y.pWin ){ + *pp = (*pp)->pNextWin; + break; + } + } + } + return WRC_Continue; +} + +/* +** Remove any Window objects owned by the expression pExpr from the +** Select.pWin list of Select object pSelect. +*/ +static void resolveRemoveWindows(Select *pSelect, Expr *pExpr){ + Walker sWalker; + memset(&sWalker, 0, sizeof(Walker)); + sWalker.xExprCallback = resolveRemoveWindowsCb; + sWalker.u.pSelect = pSelect; + sqlite3WalkExpr(&sWalker, pExpr); +} +#else +# define resolveRemoveWindows(x,y) +#endif + /* ** pOrderBy is an ORDER BY or GROUP BY clause in SELECT statement pSelect. ** The Name context of the SELECT statement is pNC. zType is either @@ -95380,19 +96788,10 @@ static int resolveOrderGroupBy( } for(j=0; jpEList->nExpr; j++){ if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ -#ifndef SQLITE_OMIT_WINDOWFUNC - if( pE->pWin ){ - /* Since this window function is being changed into a reference - ** to the same window function the result set, remove the instance - ** of this window function from the Select.pWin list. */ - Window **pp; - for(pp=&pSelect->pWin; *pp; pp=&(*pp)->pNextWin){ - if( *pp==pE->pWin ){ - *pp = (*pp)->pNextWin; - } - } - } -#endif + /* Since this expresion is being changed into a reference + ** to an identical expression in the result set, remove all Window + ** objects belonging to the expression from the Select.pWin list. */ + resolveRemoveWindows(pSelect, pE); pItem->u.x.iOrderByCol = j+1; } } @@ -95472,7 +96871,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ */ for(i=0; ipSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; - if( pItem->pSelect ){ + if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ NameContext *pNC; /* Used to iterate name contexts */ int nRef = 0; /* Refcount for pOuterNC and outer contexts */ const char *zSavedContext = pParse->zAuthContext; @@ -95604,6 +97003,19 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ } } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( IN_RENAME_OBJECT ){ + Window *pWin; + for(pWin=p->pWinDefn; pWin; pWin=pWin->pNextWin){ + if( sqlite3ResolveExprListNames(&sNC, pWin->pOrderBy) + || sqlite3ResolveExprListNames(&sNC, pWin->pPartition) + ){ + return WRC_Abort; + } + } + } +#endif + /* If this is part of a compound SELECT, check that it has the right ** number of expressions in the select list. */ if( p->pNext && p->pEList->nExpr!=p->pNext->pEList->nExpr ){ @@ -95679,12 +97091,12 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( NameContext *pNC, /* Namespace to resolve expressions in. */ Expr *pExpr /* The expression to be analyzed. */ ){ - u16 savedHasAgg; + int savedHasAgg; Walker w; if( pExpr==0 ) return SQLITE_OK; - savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg); - pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg); + savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin); + pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin); w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; @@ -95700,9 +97112,11 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight -= pExpr->nHeight; #endif - if( pNC->ncFlags & NC_HasAgg ){ - ExprSetProperty(pExpr, EP_Agg); - } + assert( EP_Agg==NC_HasAgg ); + assert( EP_Win==NC_HasWin ); + testcase( pNC->ncFlags & NC_HasAgg ); + testcase( pNC->ncFlags & NC_HasWin ); + ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) ); pNC->ncFlags |= savedHasAgg; return pNC->nErr>0 || w.pParse->nErr>0; } @@ -95754,38 +97168,47 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames( } /* -** Resolve names in expressions that can only reference a single table: +** Resolve names in expressions that can only reference a single table +** or which cannot reference any tables at all. Examples: ** -** * CHECK constraints -** * WHERE clauses on partial indices +** (1) CHECK constraints +** (2) WHERE clauses on partial indices +** (3) Expressions in indexes on expressions +** (4) Expression arguments to VACUUM INTO. ** -** The Expr.iTable value for Expr.op==TK_COLUMN nodes of the expression -** is set to -1 and the Expr.iColumn value is set to the column number. +** In all cases except (4), the Expr.iTable value for Expr.op==TK_COLUMN +** nodes of the expression is set to -1 and the Expr.iColumn value is +** set to the column number. In case (4), TK_COLUMN nodes cause an error. ** ** Any errors cause an error message to be set in pParse. */ -SQLITE_PRIVATE void sqlite3ResolveSelfReference( +SQLITE_PRIVATE int sqlite3ResolveSelfReference( Parse *pParse, /* Parsing context */ - Table *pTab, /* The table being referenced */ - int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr */ + Table *pTab, /* The table being referenced, or NULL */ + int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr, or 0 */ Expr *pExpr, /* Expression to resolve. May be NULL. */ ExprList *pList /* Expression list to resolve. May be NULL. */ ){ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ + int rc; - assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr ); + assert( type==0 || pTab!=0 ); + assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr || pTab==0 ); memset(&sNC, 0, sizeof(sNC)); memset(&sSrc, 0, sizeof(sSrc)); - sSrc.nSrc = 1; - sSrc.a[0].zName = pTab->zName; - sSrc.a[0].pTab = pTab; - sSrc.a[0].iCursor = -1; + if( pTab ){ + sSrc.nSrc = 1; + sSrc.a[0].zName = pTab->zName; + sSrc.a[0].pTab = pTab; + sSrc.a[0].iCursor = -1; + } sNC.pParse = pParse; sNC.pSrcList = &sSrc; - sNC.ncFlags = type; - if( sqlite3ResolveExprNames(&sNC, pExpr) ) return; - if( pList ) sqlite3ResolveExprListNames(&sNC, pList); + sNC.ncFlags = type | NC_IsDDL; + if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc; + if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList); + return rc; } /************** End of resolve.c *********************************************/ @@ -95836,8 +97259,12 @@ SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){ */ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ int op; - pExpr = sqlite3ExprSkipCollate(pExpr); if( pExpr->flags & EP_Generic ) return 0; + while( ExprHasProperty(pExpr, EP_Skip) ){ + assert( pExpr->op==TK_COLLATE ); + pExpr = pExpr->pLeft; + assert( pExpr!=0 ); + } op = pExpr->op; if( op==TK_SELECT ){ assert( pExpr->flags&EP_xIsSelect ); @@ -95850,8 +97277,8 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ return sqlite3AffinityType(pExpr->u.zToken, 0); } #endif - if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->pTab ){ - return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn); + if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->y.pTab ){ + return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); } if( op==TK_SELECT_COLUMN ){ assert( pExpr->pLeft->flags&EP_xIsSelect ); @@ -95898,7 +97325,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, con ** or likelihood() function at the root of an expression. */ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){ - while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){ + while( pExpr && ExprHasProperty(pExpr, EP_Skip|EP_Unlikely) ){ if( ExprHasProperty(pExpr, EP_Unlikely) ){ assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); assert( pExpr->x.pList->nExpr>0 ); @@ -95933,15 +97360,15 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ while( p ){ int op = p->op; if( p->flags & EP_Generic ) break; - if( (op==TK_AGG_COLUMN || op==TK_COLUMN - || op==TK_REGISTER || op==TK_TRIGGER) - && p->pTab!=0 + if( op==TK_REGISTER ) op = p->op2; + if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER) + && p->y.pTab!=0 ){ - /* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally + /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally ** a TK_COLUMN but was previously evaluated and cached in a register */ int j = p->iColumn; if( j>=0 ){ - const char *zColl = p->pTab->aCol[j].zColl; + const char *zColl = p->y.pTab->aCol[j].zColl; pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); } break; @@ -95950,7 +97377,7 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ p = p->pLeft; continue; } - if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){ + if( op==TK_COLLATE ){ pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken); break; } @@ -96257,6 +97684,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField( }else{ if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr; pRet = sqlite3ExprDup(pParse->db, pVector, 0); + sqlite3RenameTokenRemap(pParse, pRet, pVector); } return pRet; } @@ -96273,7 +97701,7 @@ static int exprCodeSubselect(Parse *pParse, Expr *pExpr){ int reg = 0; #ifndef SQLITE_OMIT_SUBQUERY if( pExpr->op==TK_SELECT ){ - reg = sqlite3CodeSubselect(pParse, pExpr, 0, 0); + reg = sqlite3CodeSubselect(pParse, pExpr); } #endif return reg; @@ -96345,7 +97773,7 @@ static void codeVectorCompare( int regLeft = 0; int regRight = 0; u8 opx = op; - int addrDone = sqlite3VdbeMakeLabel(v); + int addrDone = sqlite3VdbeMakeLabel(pParse); if( nLeft!=sqlite3ExprVectorSize(pRight) ){ sqlite3ErrorMsg(pParse, "row value misused"); @@ -96564,7 +97992,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( pNew->iAgg = -1; if( pToken ){ if( nExtra==0 ){ - pNew->flags |= EP_IntValue|EP_Leaf; + pNew->flags |= EP_IntValue|EP_Leaf|(iValue?EP_IsTrue:EP_IsFalse); pNew->u.iValue = iValue; }else{ pNew->u.zToken = (char*)&pNew[1]; @@ -96572,8 +98000,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n); pNew->u.zToken[pToken->n] = 0; if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){ - if( pNew->u.zToken[0]=='"' ) pNew->flags |= EP_DblQuoted; - sqlite3Dequote(pNew->u.zToken); + sqlite3DequoteExpr(pNew); } } } @@ -96642,20 +98069,16 @@ SQLITE_PRIVATE Expr *sqlite3PExpr( Expr *pRight /* Right operand */ ){ Expr *p; - if( op==TK_AND && pParse->nErr==0 ){ - /* Take advantage of short-circuit false optimization for AND */ - p = sqlite3ExprAnd(pParse->db, pLeft, pRight); - }else{ - p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)); - if( p ){ - memset(p, 0, sizeof(Expr)); - p->op = op & TKFLG_MASK; - p->iAgg = -1; - } + p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)); + if( p ){ + memset(p, 0, sizeof(Expr)); + p->op = op & 0xff; + p->iAgg = -1; sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight); - } - if( p ) { sqlite3ExprCheckHeight(pParse, p->nHeight); + }else{ + sqlite3ExprDelete(pParse->db, pLeft); + sqlite3ExprDelete(pParse->db, pRight); } return p; } @@ -96676,33 +98099,6 @@ SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pS } -/* -** If the expression is always either TRUE or FALSE (respectively), -** then return 1. If one cannot determine the truth value of the -** expression at compile-time return 0. -** -** This is an optimization. If is OK to return 0 here even if -** the expression really is always false or false (a false negative). -** But it is a bug to return 1 if the expression might have different -** boolean values in different circumstances (a false positive.) -** -** Note that if the expression is part of conditional for a -** LEFT JOIN, then we cannot determine at compile-time whether or not -** is it true or false, so always return 0. -*/ -static int exprAlwaysTrue(Expr *p){ - int v = 0; - if( ExprHasProperty(p, EP_FromJoin) ) return 0; - if( !sqlite3ExprIsInteger(p, &v) ) return 0; - return v!=0; -} -static int exprAlwaysFalse(Expr *p){ - int v = 0; - if( ExprHasProperty(p, EP_FromJoin) ) return 0; - if( !sqlite3ExprIsInteger(p, &v) ) return 0; - return v==0; -} - /* ** Join two expressions using an AND operator. If either expression is ** NULL, then just return the other expression. @@ -96711,19 +98107,18 @@ static int exprAlwaysFalse(Expr *p){ ** of returning an AND expression, just return a constant expression with ** a value of false. */ -SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){ - if( pLeft==0 ){ +SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ + sqlite3 *db = pParse->db; + if( pLeft==0 ){ return pRight; }else if( pRight==0 ){ return pLeft; - }else if( exprAlwaysFalse(pLeft) || exprAlwaysFalse(pRight) ){ - sqlite3ExprDelete(db, pLeft); - sqlite3ExprDelete(db, pRight); + }else if( ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight) ){ + sqlite3ExprUnmapAndDelete(pParse, pLeft); + sqlite3ExprUnmapAndDelete(pParse, pRight); return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0); }else{ - Expr *pNew = sqlite3ExprAlloc(db, TK_AND, 0, 0); - sqlite3ExprAttachSubtrees(db, pNew, pLeft, pRight); - return pNew; + return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); } } @@ -96844,6 +98239,10 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p!=0 ); /* Sanity check: Assert that the IntValue is non-negative if it exists */ assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 ); + + assert( !ExprHasProperty(p, EP_WinFunc) || p->y.pWin!=0 || db->mallocFailed ); + assert( p->op!=TK_FUNCTION || ExprHasProperty(p, EP_TokenOnly|EP_Reduced) + || p->y.pWin==0 || ExprHasProperty(p, EP_WinFunc) ); #ifdef SQLITE_DEBUG if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->pLeft==0 ); @@ -96862,8 +98261,9 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ }else{ sqlite3ExprListDelete(db, p->x.pList); } - if( !ExprHasProperty(p, EP_Reduced) ){ - sqlite3WindowDelete(db, p->pWin); + if( ExprHasProperty(p, EP_WinFunc) ){ + assert( p->op==TK_FUNCTION ); + sqlite3WindowDelete(db, p->y.pWin); } } if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); @@ -96875,6 +98275,18 @@ SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3ExprDeleteNN(db, p); } +/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the +** expression. +*/ +SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse *pParse, Expr *p){ + if( p ){ + if( IN_RENAME_OBJECT ){ + sqlite3RenameExprUnmap(pParse, p); + } + sqlite3ExprDeleteNN(pParse->db, p); + } +} + /* ** Return the number of bytes allocated for the expression structure ** passed as the first argument. This is always one of EXPR_FULLSIZE, @@ -96886,6 +98298,16 @@ static int exprStructSize(Expr *p){ return EXPR_FULLSIZE; } +/* +** Copy the complete content of an Expr node, taking care not to read +** past the end of the structure for a reduced-size version of the source +** Expr. +*/ +static void exprNodeCopy(Expr *pDest, Expr *pSrc){ + memset(pDest, 0, sizeof(Expr)); + memcpy(pDest, pSrc, exprStructSize(pSrc)); +} + /* ** The dupedExpr*Size() routines each return the number of bytes required ** to store a copy of an expression or expression tree. They differ in @@ -96927,7 +98349,7 @@ static int dupedExprStructSize(Expr *p, int flags){ assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 ); if( 0==flags || p->op==TK_SELECT_COLUMN #ifndef SQLITE_OMIT_WINDOWFUNC - || p->pWin + || ExprHasProperty(p, EP_WinFunc) #endif ){ nSize = EXPR_FULLSIZE; @@ -96954,7 +98376,7 @@ static int dupedExprStructSize(Expr *p, int flags){ static int dupedExprNodeSize(Expr *p, int flags){ int nByte = dupedExprStructSize(p, flags) & 0xfff; if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ - nByte += sqlite3Strlen30(p->u.zToken)+1; + nByte += sqlite3Strlen30NN(p->u.zToken)+1; } return ROUND8(nByte); } @@ -97057,22 +98479,24 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ } /* Fill in pNew->pLeft and pNew->pRight. */ - zAlloc += dupedExprNodeSize(p, dupFlags); - if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){ + if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){ + zAlloc += dupedExprNodeSize(p, dupFlags); if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){ pNew->pLeft = p->pLeft ? exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0; pNew->pRight = p->pRight ? exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0; } - }else{ #ifndef SQLITE_OMIT_WINDOWFUNC - if( ExprHasProperty(p, EP_Reduced|EP_TokenOnly) ){ - pNew->pWin = 0; - }else{ - pNew->pWin = sqlite3WindowDup(db, pNew, p->pWin); + if( ExprHasProperty(p, EP_WinFunc) ){ + pNew->y.pWin = sqlite3WindowDup(db, pNew, p->y.pWin); + assert( ExprHasProperty(pNew, EP_WinFunc) ); } #endif /* SQLITE_OMIT_WINDOWFUNC */ + if( pzBuffer ){ + *pzBuffer = zAlloc; + } + }else{ if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ if( pNew->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; @@ -97084,9 +98508,6 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ pNew->pRight = sqlite3ExprDup(db, p->pRight, 0); } } - if( pzBuffer ){ - *pzBuffer = zAlloc; - } } return pNew; } @@ -97100,7 +98521,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ static With *withDup(sqlite3 *db, With *p){ With *pRet = 0; if( p ){ - int nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); + sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); pRet = sqlite3DbMallocZero(db, nByte); if( pRet ){ int i; @@ -97118,6 +98539,36 @@ static With *withDup(sqlite3 *db, With *p){ # define withDup(x,y) 0 #endif +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** The gatherSelectWindows() procedure and its helper routine +** gatherSelectWindowsCallback() are used to scan all the expressions +** an a newly duplicated SELECT statement and gather all of the Window +** objects found there, assembling them onto the linked list at Select->pWin. +*/ +static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_FUNCTION && pExpr->y.pWin!=0 ){ + assert( ExprHasProperty(pExpr, EP_WinFunc) ); + pExpr->y.pWin->pNextWin = pWalker->u.pSelect->pWin; + pWalker->u.pSelect->pWin = pExpr->y.pWin; + } + return WRC_Continue; +} +static int gatherSelectWindowsSelectCallback(Walker *pWalker, Select *p){ + return p==pWalker->u.pSelect ? WRC_Continue : WRC_Prune; +} +static void gatherSelectWindows(Select *p){ + Walker w; + w.xExprCallback = gatherSelectWindowsCallback; + w.xSelectCallback = gatherSelectWindowsSelectCallback; + w.xSelectCallback2 = 0; + w.pParse = 0; + w.u.pSelect = p; + sqlite3WalkSelect(&w, p); +} +#endif + + /* ** The following group of routines make deep copies of expressions, ** expression lists, ID lists, and select statements. The copies can @@ -97285,6 +98736,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){ #ifndef SQLITE_OMIT_WINDOWFUNC pNew->pWin = 0; pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn); + if( p->pWin ) gatherSelectWindows(pNew); #endif pNew->selId = p->selId; *pp = pNew; @@ -97334,7 +98786,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend( }else if( (pList->nExpr & (pList->nExpr-1))==0 ){ ExprList *pNew; pNew = sqlite3DbRealloc(db, pList, - sizeof(*pList)+(2*pList->nExpr - 1)*sizeof(pList->a[0])); + sizeof(*pList)+(2*(sqlite3_int64)pList->nExpr-1)*sizeof(pList->a[0])); if( pNew==0 ){ goto no_mem; } @@ -97417,7 +98869,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector( } vector_append_error: - sqlite3ExprDelete(db, pExpr); + sqlite3ExprUnmapAndDelete(pParse, pExpr); sqlite3IdListDelete(db, pColumns); return pList; } @@ -97560,10 +99012,12 @@ SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){ */ SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){ assert( pExpr->op==TK_ID || pExpr->op==TK_STRING ); - if( sqlite3StrICmp(pExpr->u.zToken, "true")==0 - || sqlite3StrICmp(pExpr->u.zToken, "false")==0 + if( !ExprHasProperty(pExpr, EP_Quoted) + && (sqlite3StrICmp(pExpr->u.zToken, "true")==0 + || sqlite3StrICmp(pExpr->u.zToken, "false")==0) ){ pExpr->op = TK_TRUEFALSE; + ExprSetProperty(pExpr, pExpr->u.zToken[4]==0 ? EP_IsTrue : EP_IsFalse); return 1; } return 0; @@ -97574,12 +99028,40 @@ SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){ ** and 0 if it is FALSE. */ SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr *pExpr){ + pExpr = sqlite3ExprSkipCollate((Expr*)pExpr); assert( pExpr->op==TK_TRUEFALSE ); assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0 || sqlite3StrICmp(pExpr->u.zToken,"false")==0 ); return pExpr->u.zToken[4]==0; } +/* +** If pExpr is an AND or OR expression, try to simplify it by eliminating +** terms that are always true or false. Return the simplified expression. +** Or return the original expression if no simplification is possible. +** +** Examples: +** +** (x<10) AND true => (x<10) +** (x<10) AND false => false +** (x<10) AND (y=22 OR false) => (x<10) AND (y=22) +** (x<10) AND (y=22 OR true) => (x<10) +** (y=22) OR true => true +*/ +SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){ + assert( pExpr!=0 ); + if( pExpr->op==TK_AND || pExpr->op==TK_OR ){ + Expr *pRight = sqlite3ExprSimplifiedAndOr(pExpr->pRight); + Expr *pLeft = sqlite3ExprSimplifiedAndOr(pExpr->pLeft); + if( ExprAlwaysTrue(pLeft) || ExprAlwaysFalse(pRight) ){ + pExpr = pExpr->op==TK_AND ? pRight : pLeft; + }else if( ExprAlwaysTrue(pRight) || ExprAlwaysFalse(pLeft) ){ + pExpr = pExpr->op==TK_AND ? pLeft : pRight; + } + } + return pExpr; +} + /* ** These routines are Walker callbacks used to check expressions to @@ -97824,7 +99306,7 @@ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){ */ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){ int rc = 0; - if( p==0 ) return 0; /* Can only happen following on OOM */ + if( NEVER(p==0) ) return 0; /* Used to only happen following on OOM */ /* If an expression is an integer literal that fits in a signed 32-bit ** integer, then the EP_IntValue flag will have already been set */ @@ -97870,7 +99352,9 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){ */ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ u8 op; - while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; } + while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ + p = p->pLeft; + } op = p->op; if( op==TK_REGISTER ) op = p->op2; switch( op ){ @@ -97881,8 +99365,8 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ return 0; case TK_COLUMN: return ExprHasProperty(p, EP_CanBeNull) || - p->pTab==0 || /* Reference to column of index on expression */ - (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0); + p->y.pTab==0 || /* Reference to column of index on expression */ + (p->iColumn>=0 && p->y.pTab->aCol[p->iColumn].notNull==0); default: return 1; } @@ -98106,7 +99590,8 @@ SQLITE_PRIVATE int sqlite3FindInIndex( Expr *pX, /* The right-hand side (RHS) of the IN operator */ u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */ int *prRhsHasNull, /* Register holding NULL status. See notes */ - int *aiMap /* Mapping from Index fields to RHS fields */ + int *aiMap, /* Mapping from Index fields to RHS fields */ + int *piTab /* OUT: index to use */ ){ Select *p; /* SELECT to the right of IN operator */ int eType = 0; /* Type of RHS table. IN_INDEX_* */ @@ -98201,6 +99686,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( Bitmask colUsed; /* Columns of the index used */ Bitmask mCol; /* Mask for the current column */ if( pIdx->nColumnpPartIdxWhere!=0 ) continue; /* Maximum nColumn is BMS-2, not BMS-1, so that we can compute ** BITMASK(nExpr) without overflowing */ testcase( pIdx->nColumn==BMS-2 ); @@ -98291,16 +99777,15 @@ SQLITE_PRIVATE int sqlite3FindInIndex( eType = IN_INDEX_EPH; if( inFlags & IN_INDEX_LOOP ){ pParse->nQueryLoop = 0; - if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ - eType = IN_INDEX_ROWID; - } }else if( prRhsHasNull ){ *prRhsHasNull = rMayHaveNull = ++pParse->nMem; } - sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID); + assert( pX->op==TK_IN ); + sqlite3CodeRhsOfIN(pParse, pX, iTab); + if( rMayHaveNull ){ + sqlite3SetHasNullFlag(v, iTab, rMayHaveNull); + } pParse->nQueryLoop = savedNQueryLoop; - }else{ - pX->iTable = iTab; } if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){ @@ -98308,6 +99793,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( n = sqlite3ExprVectorSize(pX->pLeft); for(i=0; i IN (?, ?, ?)", where is a reference -** to some integer key column of a table B-Tree. In this case, use an -** intkey B-Tree to store the set of IN(...) values instead of the usual -** (slower) variable length keys B-Tree. -** -** If rMayHaveNull is non-zero, that means that the operation is an IN -** (not a SELECT or EXISTS) and that the RHS might contains NULLs. -** All this routine does is initialize the register given by rMayHaveNull -** to NULL. Calling routines will take care of changing this register -** value to non-NULL if the RHS is NULL-free. -** -** For a SELECT or EXISTS operator, return the register that holds the -** result. For a multi-column SELECT, the result is stored in a contiguous -** array of registers and the return value is the register of the left-most -** result column. Return 0 for IN operators or if an error occurs. -*/ -#ifndef SQLITE_OMIT_SUBQUERY -SQLITE_PRIVATE int sqlite3CodeSubselect( +** The pExpr parameter is the IN operator. The cursor number for the +** constructed ephermeral table is returned. The first time the ephemeral +** table is computed, the cursor number is also stored in pExpr->iTable, +** however the cursor number returned might not be the same, as it might +** have been duplicated using OP_OpenDup. +** +** If the LHS expression ("x" in the examples) is a column value, or +** the SELECT statement returns a column value, then the affinity of that +** column is used to build the index keys. If both 'x' and the +** SELECT... statement are columns, then numeric affinity is used +** if either column has NUMERIC or INTEGER affinity. If neither +** 'x' nor the SELECT... statement are columns, then numeric affinity +** is used. +*/ +SQLITE_PRIVATE void sqlite3CodeRhsOfIN( Parse *pParse, /* Parsing context */ - Expr *pExpr, /* The IN, SELECT, or EXISTS operator */ - int rHasNullFlag, /* Register that records whether NULLs exist in RHS */ - int isRowid /* If true, LHS of IN operator is a rowid */ + Expr *pExpr, /* The IN operator */ + int iTab /* Use this cursor number */ ){ - int jmpIfDynamic = -1; /* One-time test address */ - int rReg = 0; /* Register storing resulting */ - Vdbe *v = sqlite3GetVdbe(pParse); - if( NEVER(v==0) ) return 0; + int addrOnce = 0; /* Address of the OP_Once instruction at top */ + int addr; /* Address of OP_OpenEphemeral instruction */ + Expr *pLeft; /* the LHS of the IN operator */ + KeyInfo *pKeyInfo = 0; /* Key information */ + int nVal; /* Size of vector pLeft */ + Vdbe *v; /* The prepared statement under construction */ - /* The evaluation of the IN/EXISTS/SELECT must be repeated every time it + v = pParse->pVdbe; + assert( v!=0 ); + + /* The evaluation of the IN must be repeated every time it ** is encountered if any of the following is true: ** ** * The right-hand side is a correlated subquery ** * The right-hand side is an expression list containing variables ** * We are inside a trigger ** - ** If all of the above are false, then we can run this code just once - ** save the results, and reuse the same result on subsequent invocations. + ** If all of the above are false, then we can compute the RHS just once + ** and reuse it many names. */ - if( !ExprHasProperty(pExpr, EP_VarSelect) ){ - jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); - } + if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){ + /* Reuse of the RHS is allowed */ + /* If this routine has already been coded, but the previous code + ** might not have been invoked yet, so invoke it now as a subroutine. + */ + if( ExprHasProperty(pExpr, EP_Subrtn) ){ + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d", + pExpr->x.pSelect->selId)); + } + sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, + pExpr->y.sub.iAddr); + sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable); + sqlite3VdbeJumpHere(v, addrOnce); + return; + } - switch( pExpr->op ){ - case TK_IN: { - int addr; /* Address of OP_OpenEphemeral instruction */ - Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */ - KeyInfo *pKeyInfo = 0; /* Key information */ - int nVal; /* Size of vector pLeft */ - - nVal = sqlite3ExprVectorSize(pLeft); - assert( !isRowid || nVal==1 ); + /* Begin coding the subroutine */ + ExprSetProperty(pExpr, EP_Subrtn); + pExpr->y.sub.regReturn = ++pParse->nMem; + pExpr->y.sub.iAddr = + sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1; + VdbeComment((v, "return address")); - /* Whether this is an 'x IN(SELECT...)' or an 'x IN()' - ** expression it is handled the same way. An ephemeral table is - ** filled with index keys representing the results from the - ** SELECT or the . - ** - ** If the 'x' expression is a column value, or the SELECT... - ** statement returns a column value, then the affinity of that - ** column is used to build the index keys. If both 'x' and the - ** SELECT... statement are columns, then numeric affinity is used - ** if either column has NUMERIC or INTEGER affinity. If neither - ** 'x' nor the SELECT... statement are columns, then numeric affinity - ** is used. - */ - pExpr->iTable = pParse->nTab++; - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, - pExpr->iTable, (isRowid?0:nVal)); - pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1); + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + } - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - /* Case 1: expr IN (SELECT ...) - ** - ** Generate code to write the results of the select into the temporary - ** table allocated and opened above. - */ - Select *pSelect = pExpr->x.pSelect; - ExprList *pEList = pSelect->pEList; - - ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY", - jmpIfDynamic>=0?"":"CORRELATED " - )); - assert( !isRowid ); - /* If the LHS and RHS of the IN operator do not match, that - ** error will have been caught long before we reach this point. */ - if( ALWAYS(pEList->nExpr==nVal) ){ - SelectDest dest; - int i; - sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); - dest.zAffSdst = exprINAffinity(pParse, pExpr); - pSelect->iLimit = 0; - testcase( pSelect->selFlags & SF_Distinct ); - testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ - if( sqlite3Select(pParse, pSelect, &dest) ){ - sqlite3DbFree(pParse->db, dest.zAffSdst); - sqlite3KeyInfoUnref(pKeyInfo); - return 0; - } - sqlite3DbFree(pParse->db, dest.zAffSdst); - assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ - assert( pEList!=0 ); - assert( pEList->nExpr>0 ); - assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); - for(i=0; iaColl[i] = sqlite3BinaryCompareCollSeq( - pParse, p, pEList->a[i].pExpr - ); - } - } - }else if( ALWAYS(pExpr->x.pList!=0) ){ - /* Case 2: expr IN (exprlist) - ** - ** For each expression, build an index key from the evaluation and - ** store it in the temporary table. If is a column, then use - ** that columns affinity when building index keys. If is not - ** a column, use numeric affinity. - */ - char affinity; /* Affinity of the LHS of the IN */ - int i; - ExprList *pList = pExpr->x.pList; - struct ExprList_item *pItem; - int r1, r2, r3; - affinity = sqlite3ExprAffinity(pLeft); - if( !affinity ){ - affinity = SQLITE_AFF_BLOB; - } - if( pKeyInfo ){ - assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); - pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - } + /* Check to see if this is a vector IN operator */ + pLeft = pExpr->pLeft; + nVal = sqlite3ExprVectorSize(pLeft); - /* Loop through each expression in . */ - r1 = sqlite3GetTempReg(pParse); - r2 = sqlite3GetTempReg(pParse); - if( isRowid ) sqlite3VdbeAddOp4(v, OP_Blob, 0, r2, 0, "", P4_STATIC); - for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ - Expr *pE2 = pItem->pExpr; - int iValToIns; - - /* If the expression is not constant then we will need to - ** disable the test that was generated above that makes sure - ** this code only executes once. Because for a non-constant - ** expression we need to rerun this code each time. - */ - if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){ - sqlite3VdbeChangeToNoop(v, jmpIfDynamic); - jmpIfDynamic = -1; - } + /* Construct the ephemeral table that will contain the content of + ** RHS of the IN operator. + */ + pExpr->iTable = iTab; + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, nVal); +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + VdbeComment((v, "Result of SELECT %u", pExpr->x.pSelect->selId)); + }else{ + VdbeComment((v, "RHS of IN operator")); + } +#endif + pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1); - /* Evaluate the expression and insert it into the temp table */ - if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){ - sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns); - }else{ - r3 = sqlite3ExprCodeTarget(pParse, pE2, r1); - if( isRowid ){ - sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, - sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3); - }else{ - sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); - sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pExpr->iTable, r2, r3, 1); - } - } - } - sqlite3ReleaseTempReg(pParse, r1); - sqlite3ReleaseTempReg(pParse, r2); + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + /* Case 1: expr IN (SELECT ...) + ** + ** Generate code to write the results of the select into the temporary + ** table allocated and opened above. + */ + Select *pSelect = pExpr->x.pSelect; + ExprList *pEList = pSelect->pEList; + + ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY %d", + addrOnce?"":"CORRELATED ", pSelect->selId + )); + /* If the LHS and RHS of the IN operator do not match, that + ** error will have been caught long before we reach this point. */ + if( ALWAYS(pEList->nExpr==nVal) ){ + SelectDest dest; + int i; + sqlite3SelectDestInit(&dest, SRT_Set, iTab); + dest.zAffSdst = exprINAffinity(pParse, pExpr); + pSelect->iLimit = 0; + testcase( pSelect->selFlags & SF_Distinct ); + testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ + if( sqlite3Select(pParse, pSelect, &dest) ){ + sqlite3DbFree(pParse->db, dest.zAffSdst); + sqlite3KeyInfoUnref(pKeyInfo); + return; } - if( pKeyInfo ){ - sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); + sqlite3DbFree(pParse->db, dest.zAffSdst); + assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ + assert( pEList!=0 ); + assert( pEList->nExpr>0 ); + assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); + for(i=0; iaColl[i] = sqlite3BinaryCompareCollSeq( + pParse, p, pEList->a[i].pExpr + ); } - break; + } + }else if( ALWAYS(pExpr->x.pList!=0) ){ + /* Case 2: expr IN (exprlist) + ** + ** For each expression, build an index key from the evaluation and + ** store it in the temporary table. If is a column, then use + ** that columns affinity when building index keys. If is not + ** a column, use numeric affinity. + */ + char affinity; /* Affinity of the LHS of the IN */ + int i; + ExprList *pList = pExpr->x.pList; + struct ExprList_item *pItem; + int r1, r2, r3; + affinity = sqlite3ExprAffinity(pLeft); + if( !affinity ){ + affinity = SQLITE_AFF_BLOB; + } + if( pKeyInfo ){ + assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); + pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); } - case TK_EXISTS: - case TK_SELECT: - default: { - /* Case 3: (SELECT ... FROM ...) - ** or: EXISTS(SELECT ... FROM ...) - ** - ** For a SELECT, generate code to put the values for all columns of - ** the first row into an array of registers and return the index of - ** the first register. - ** - ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists) - ** into a register and return that register number. - ** - ** In both cases, the query is augmented with "LIMIT 1". Any - ** preexisting limit is discarded in place of the new LIMIT 1. + /* Loop through each expression in . */ + r1 = sqlite3GetTempReg(pParse); + r2 = sqlite3GetTempReg(pParse); + for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ + Expr *pE2 = pItem->pExpr; + + /* If the expression is not constant then we will need to + ** disable the test that was generated above that makes sure + ** this code only executes once. Because for a non-constant + ** expression we need to rerun this code each time. */ - Select *pSel; /* SELECT statement to encode */ - SelectDest dest; /* How to deal with SELECT result */ - int nReg; /* Registers to allocate */ - Expr *pLimit; /* New limit expression */ - - testcase( pExpr->op==TK_EXISTS ); - testcase( pExpr->op==TK_SELECT ); - assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); - assert( ExprHasProperty(pExpr, EP_xIsSelect) ); - - pSel = pExpr->x.pSelect; - ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY", - jmpIfDynamic>=0?"":"CORRELATED ")); - nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1; - sqlite3SelectDestInit(&dest, 0, pParse->nMem+1); - pParse->nMem += nReg; - if( pExpr->op==TK_SELECT ){ - dest.eDest = SRT_Mem; - dest.iSdst = dest.iSDParm; - dest.nSdst = nReg; - sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1); - VdbeComment((v, "Init subquery result")); - }else{ - dest.eDest = SRT_Exists; - sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm); - VdbeComment((v, "Init EXISTS result")); - } - pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[1], 0); - if( pSel->pLimit ){ - sqlite3ExprDelete(pParse->db, pSel->pLimit->pLeft); - pSel->pLimit->pLeft = pLimit; - }else{ - pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0); + if( addrOnce && !sqlite3ExprIsConstant(pE2) ){ + sqlite3VdbeChangeToNoop(v, addrOnce); + ExprClearProperty(pExpr, EP_Subrtn); + addrOnce = 0; } - pSel->iLimit = 0; - if( sqlite3Select(pParse, pSel, &dest) ){ - return 0; - } - rReg = dest.iSDParm; - ExprSetVVAProperty(pExpr, EP_NoReduce); - break; + + /* Evaluate the expression and insert it into the temp table */ + r3 = sqlite3ExprCodeTarget(pParse, pE2, r1); + sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r3, 1); } + sqlite3ReleaseTempReg(pParse, r1); + sqlite3ReleaseTempReg(pParse, r2); + } + if( pKeyInfo ){ + sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); + } + if( addrOnce ){ + sqlite3VdbeJumpHere(v, addrOnce); + /* Subroutine return */ + sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn); + sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1); } +} +#endif /* SQLITE_OMIT_SUBQUERY */ - if( rHasNullFlag ){ - sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag); +/* +** Generate code for scalar subqueries used as a subquery expression +** or EXISTS operator: +** +** (SELECT a FROM b) -- subquery +** EXISTS (SELECT a FROM b) -- EXISTS subquery +** +** The pExpr parameter is the SELECT or EXISTS operator to be coded. +** +** The register that holds the result. For a multi-column SELECT, +** the result is stored in a contiguous array of registers and the +** return value is the register of the left-most result column. +** Return 0 if an error occurs. +*/ +#ifndef SQLITE_OMIT_SUBQUERY +SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ + int addrOnce = 0; /* Address of OP_Once at top of subroutine */ + int rReg = 0; /* Register storing resulting */ + Select *pSel; /* SELECT statement to encode */ + SelectDest dest; /* How to deal with SELECT result */ + int nReg; /* Registers to allocate */ + Expr *pLimit; /* New limit expression */ + + Vdbe *v = pParse->pVdbe; + assert( v!=0 ); + testcase( pExpr->op==TK_EXISTS ); + testcase( pExpr->op==TK_SELECT ); + assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); + assert( ExprHasProperty(pExpr, EP_xIsSelect) ); + pSel = pExpr->x.pSelect; + + /* The evaluation of the EXISTS/SELECT must be repeated every time it + ** is encountered if any of the following is true: + ** + ** * The right-hand side is a correlated subquery + ** * The right-hand side is an expression list containing variables + ** * We are inside a trigger + ** + ** If all of the above are false, then we can run this code just once + ** save the results, and reuse the same result on subsequent invocations. + */ + if( !ExprHasProperty(pExpr, EP_VarSelect) ){ + /* If this routine has already been coded, then invoke it as a + ** subroutine. */ + if( ExprHasProperty(pExpr, EP_Subrtn) ){ + ExplainQueryPlan((pParse, 0, "REUSE SUBQUERY %d", pSel->selId)); + sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, + pExpr->y.sub.iAddr); + return pExpr->iTable; + } + + /* Begin coding the subroutine */ + ExprSetProperty(pExpr, EP_Subrtn); + pExpr->y.sub.regReturn = ++pParse->nMem; + pExpr->y.sub.iAddr = + sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1; + VdbeComment((v, "return address")); + + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } + + /* For a SELECT, generate code to put the values for all columns of + ** the first row into an array of registers and return the index of + ** the first register. + ** + ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists) + ** into a register and return that register number. + ** + ** In both cases, the query is augmented with "LIMIT 1". Any + ** preexisting limit is discarded in place of the new LIMIT 1. + */ + ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY %d", + addrOnce?"":"CORRELATED ", pSel->selId)); + nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1; + sqlite3SelectDestInit(&dest, 0, pParse->nMem+1); + pParse->nMem += nReg; + if( pExpr->op==TK_SELECT ){ + dest.eDest = SRT_Mem; + dest.iSdst = dest.iSDParm; + dest.nSdst = nReg; + sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1); + VdbeComment((v, "Init subquery result")); + }else{ + dest.eDest = SRT_Exists; + sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm); + VdbeComment((v, "Init EXISTS result")); + } + pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[1], 0); + if( pSel->pLimit ){ + sqlite3ExprDelete(pParse->db, pSel->pLimit->pLeft); + pSel->pLimit->pLeft = pLimit; + }else{ + pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0); + } + pSel->iLimit = 0; + if( sqlite3Select(pParse, pSel, &dest) ){ + return 0; + } + pExpr->iTable = rReg = dest.iSDParm; + ExprSetVVAProperty(pExpr, EP_NoReduce); + if( addrOnce ){ + sqlite3VdbeJumpHere(v, addrOnce); - if( jmpIfDynamic>=0 ){ - sqlite3VdbeJumpHere(v, jmpIfDynamic); + /* Subroutine return */ + sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn); + sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1); } return rReg; @@ -98711,6 +100241,7 @@ static void sqlite3ExprCodeIN( int addrTruthOp; /* Address of opcode that determines the IN is true */ int destNotNull; /* Jump here if a comparison is not true in step 6 */ int addrTop; /* Top of the step-6 loop */ + int iTab = 0; /* Index to use */ pLeft = pExpr->pLeft; if( sqlite3ExprCheckIN(pParse, pExpr) ) return; @@ -98722,7 +100253,7 @@ static void sqlite3ExprCodeIN( if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error; /* Attempt to compute the RHS. After this step, if anything other than - ** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable + ** IN_INDEX_NOOP is returned, the table opened with cursor iTab ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned, ** the RHS has not yet been coded. */ v = pParse->pVdbe; @@ -98730,7 +100261,8 @@ static void sqlite3ExprCodeIN( VdbeNoopComment((v, "begin IN expr")); eType = sqlite3FindInIndex(pParse, pExpr, IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK, - destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap); + destIfFalse==destIfNull ? 0 : &rRhsHasNull, + aiMap, &iTab); assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC @@ -98776,7 +100308,7 @@ static void sqlite3ExprCodeIN( if( eType==IN_INDEX_NOOP ){ ExprList *pList = pExpr->x.pList; CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - int labelOk = sqlite3VdbeMakeLabel(v); + int labelOk = sqlite3VdbeMakeLabel(pParse); int r2, regToFree; int regCkNull = 0; int ii; @@ -98820,7 +100352,7 @@ static void sqlite3ExprCodeIN( if( destIfNull==destIfFalse ){ destStep2 = destIfFalse; }else{ - destStep2 = destStep6 = sqlite3VdbeMakeLabel(v); + destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse); } for(i=0; ipLeft, i); @@ -98838,19 +100370,19 @@ static void sqlite3ExprCodeIN( /* In this case, the RHS is the ROWID of table b-tree and so we also ** know that the RHS is non-NULL. Hence, we combine steps 3 and 4 ** into a single opcode. */ - sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, rLhs); + sqlite3VdbeAddOp3(v, OP_SeekRowid, iTab, destIfFalse, rLhs); VdbeCoverage(v); addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */ }else{ sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); if( destIfFalse==destIfNull ){ /* Combine Step 3 and Step 5 into a single opcode */ - sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, + sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse, rLhs, nVector); VdbeCoverage(v); goto sqlite3ExprCodeIN_finished; } /* Ordinary Step 3, for the case where FALSE and NULL are distinct */ - addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, + addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, iTab, 0, rLhs, nVector); VdbeCoverage(v); } @@ -98875,10 +100407,10 @@ static void sqlite3ExprCodeIN( ** of the RHS. */ if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6); - addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); + addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, destIfFalse); VdbeCoverage(v); if( nVector>1 ){ - destNotNull = sqlite3VdbeMakeLabel(v); + destNotNull = sqlite3VdbeMakeLabel(pParse); }else{ /* For nVector==1, combine steps 6 and 7 by immediately returning ** FALSE if the first comparison is not NULL */ @@ -98890,7 +100422,7 @@ static void sqlite3ExprCodeIN( int r3 = sqlite3GetTempReg(pParse); p = sqlite3VectorFieldSubexpr(pLeft, i); pColl = sqlite3ExprCollSeq(pParse, p); - sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, i, r3); + sqlite3VdbeAddOp3(v, OP_Column, iTab, i, r3); sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3, (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); @@ -98899,7 +100431,7 @@ static void sqlite3ExprCodeIN( sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); if( nVector>1 ){ sqlite3VdbeResolveLabel(v, destNotNull); - sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrTop+1); + sqlite3VdbeAddOp2(v, OP_Next, iTab, addrTop+1); VdbeCoverage(v); /* Step 7: If we reach this point, we know that the result must @@ -99070,7 +100602,8 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n ** register iReg. The caller must ensure that iReg already contains ** the correct value for the expression. */ -static void exprToRegister(Expr *p, int iReg){ +static void exprToRegister(Expr *pExpr, int iReg){ + Expr *p = sqlite3ExprSkipCollate(pExpr); p->op2 = p->op; p->op = TK_REGISTER; p->iTable = iReg; @@ -99098,7 +100631,7 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){ #if SQLITE_OMIT_SUBQUERY iResult = 0; #else - iResult = sqlite3CodeSubselect(pParse, p, 0, 0); + iResult = sqlite3CodeSubselect(pParse, p); #endif }else{ int i; @@ -99170,7 +100703,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** constant. */ int iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target); - int aff = sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn); + int aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); if( aff!=SQLITE_AFF_BLOB ){ static const char zAff[] = "B\000C\000D\000E"; assert( SQLITE_AFF_BLOB=='A' ); @@ -99194,7 +100727,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) iTab = pParse->iSelfTab - 1; } } - return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, + return sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab, pExpr->iColumn, iTab, target, pExpr->op2); } @@ -99408,8 +100941,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) CollSeq *pColl = 0; /* A collating sequence */ #ifndef SQLITE_OMIT_WINDOWFUNC - if( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) && pExpr->pWin ){ - return pExpr->pWin->regResult; + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + return pExpr->y.pWin->regResult; } #endif @@ -99443,7 +100976,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** arguments past the first non-NULL argument. */ if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){ - int endCoalesce = sqlite3VdbeMakeLabel(v); + int endCoalesce = sqlite3VdbeMakeLabel(pParse); assert( nFarg>=2 ); sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); for(i=1; ix.pSelect->pEList->nExpr)!=1 ){ sqlite3SubselectError(pParse, nCol, 1); }else{ - return sqlite3CodeSubselect(pParse, pExpr, 0, 0); + return sqlite3CodeSubselect(pParse, pExpr); } break; } case TK_SELECT_COLUMN: { int n; if( pExpr->pLeft->iTable==0 ){ - pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft, 0, 0); + pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft); } assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT ); if( pExpr->iTable @@ -99591,8 +101124,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) return pExpr->pLeft->iTable + pExpr->iColumn; } case TK_IN: { - int destIfFalse = sqlite3VdbeMakeLabel(v); - int destIfNull = sqlite3VdbeMakeLabel(v); + int destIfFalse = sqlite3VdbeMakeLabel(pParse); + int destIfNull = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, target); sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); @@ -99652,7 +101185,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** p1==1 -> old.a p1==4 -> new.a ** p1==2 -> old.b p1==5 -> new.b */ - Table *pTab = pExpr->pTab; + Table *pTab = pExpr->y.pTab; int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn; assert( pExpr->iTable==0 || pExpr->iTable==1 ); @@ -99663,7 +101196,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) sqlite3VdbeAddOp2(v, OP_Param, p1, target); VdbeComment((v, "r[%d]=%s.%s", target, (pExpr->iTable ? "new" : "old"), - (pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName) + (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[pExpr->iColumn].zName) )); #ifndef SQLITE_OMIT_FLOATING_POINT @@ -99732,9 +101265,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) pEList = pExpr->x.pList; aListelem = pEList->a; nExpr = pEList->nExpr; - endLabel = sqlite3VdbeMakeLabel(v); + endLabel = sqlite3VdbeMakeLabel(pParse); if( (pX = pExpr->pLeft)!=0 ){ - tempX = *pX; + exprNodeCopy(&tempX, pX); testcase( pX->op==TK_COLUMN ); exprToRegister(&tempX, exprCodeVector(pParse, &tempX, ®Free1)); testcase( regFree1==0 ); @@ -99755,7 +101288,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) }else{ pTest = aListelem[i].pExpr; } - nextCase = sqlite3VdbeMakeLabel(v); + nextCase = sqlite3VdbeMakeLabel(pParse); testcase( pTest->op==TK_COLUMN ); sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL); testcase( aListelem[i+1].pExpr->op==TK_COLUMN ); @@ -100055,13 +101588,12 @@ static void exprCodeBetween( Expr exprX; /* The x subexpression */ int regFree1 = 0; /* Temporary use register */ - memset(&compLeft, 0, sizeof(Expr)); memset(&compRight, 0, sizeof(Expr)); memset(&exprAnd, 0, sizeof(Expr)); assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); - exprX = *pExpr->pLeft; + exprNodeCopy(&exprX, pExpr->pLeft); exprAnd.op = TK_AND; exprAnd.pLeft = &compLeft; exprAnd.pRight = &compRight; @@ -100123,18 +101655,23 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int if( NEVER(pExpr==0) ) return; /* No way this can happen */ op = pExpr->op; switch( op ){ - case TK_AND: { - int d2 = sqlite3VdbeMakeLabel(v); - testcase( jumpIfNull==0 ); - sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); - sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3VdbeResolveLabel(v, d2); - break; - } + case TK_AND: case TK_OR: { - testcase( jumpIfNull==0 ); - sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); - sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); + if( pAlt!=pExpr ){ + sqlite3ExprIfTrue(pParse, pAlt, dest, jumpIfNull); + }else if( op==TK_AND ){ + int d2 = sqlite3VdbeMakeLabel(pParse); + testcase( jumpIfNull==0 ); + sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, + jumpIfNull^SQLITE_JUMPIFNULL); + sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + sqlite3VdbeResolveLabel(v, d2); + }else{ + testcase( jumpIfNull==0 ); + sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); + sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + } break; } case TK_NOT: { @@ -100210,7 +101747,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int } #ifndef SQLITE_OMIT_SUBQUERY case TK_IN: { - int destIfFalse = sqlite3VdbeMakeLabel(v); + int destIfFalse = sqlite3VdbeMakeLabel(pParse); int destIfNull = jumpIfNull ? dest : destIfFalse; sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); sqlite3VdbeGoto(v, dest); @@ -100220,9 +101757,9 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int #endif default: { default_expr: - if( exprAlwaysTrue(pExpr) ){ + if( ExprAlwaysTrue(pExpr) ){ sqlite3VdbeGoto(v, dest); - }else if( exprAlwaysFalse(pExpr) ){ + }else if( ExprAlwaysFalse(pExpr) ){ /* No-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); @@ -100290,18 +101827,23 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int assert( pExpr->op!=TK_GE || op==OP_Lt ); switch( pExpr->op ){ - case TK_AND: { - testcase( jumpIfNull==0 ); - sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); - sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); - break; - } + case TK_AND: case TK_OR: { - int d2 = sqlite3VdbeMakeLabel(v); - testcase( jumpIfNull==0 ); - sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); - sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3VdbeResolveLabel(v, d2); + Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); + if( pAlt!=pExpr ){ + sqlite3ExprIfFalse(pParse, pAlt, dest, jumpIfNull); + }else if( pExpr->op==TK_AND ){ + testcase( jumpIfNull==0 ); + sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); + sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + }else{ + int d2 = sqlite3VdbeMakeLabel(pParse); + testcase( jumpIfNull==0 ); + sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, + jumpIfNull^SQLITE_JUMPIFNULL); + sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + sqlite3VdbeResolveLabel(v, d2); + } break; } case TK_NOT: { @@ -100381,7 +101923,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int if( jumpIfNull ){ sqlite3ExprCodeIN(pParse, pExpr, dest, dest); }else{ - int destIfNull = sqlite3VdbeMakeLabel(v); + int destIfNull = sqlite3VdbeMakeLabel(pParse); sqlite3ExprCodeIN(pParse, pExpr, dest, destIfNull); sqlite3VdbeResolveLabel(v, destIfNull); } @@ -100390,9 +101932,9 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int #endif default: { default_expr: - if( exprAlwaysFalse(pExpr) ){ + if( ExprAlwaysFalse(pExpr) ){ sqlite3VdbeGoto(v, dest); - }else if( exprAlwaysTrue(pExpr) ){ + }else if( ExprAlwaysTrue(pExpr) ){ /* no-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); @@ -100502,7 +102044,7 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTa } return 2; } - if( pA->op!=pB->op ){ + if( pA->op!=pB->op || pA->op==TK_RAISE ){ if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){ return 1; } @@ -100514,40 +102056,44 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTa if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){ if( pA->op==TK_FUNCTION ){ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; +#ifndef SQLITE_OMIT_WINDOWFUNC + /* Justification for the assert(): + ** window functions have p->op==TK_FUNCTION but aggregate functions + ** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate + ** function and a window function should have failed before reaching + ** this point. And, it is not possible to have a window function and + ** a scalar function with the same name and number of arguments. So + ** if we reach this point, either A and B both window functions or + ** neither are a window functions. */ + assert( ExprHasProperty(pA,EP_WinFunc)==ExprHasProperty(pB,EP_WinFunc) ); + if( ExprHasProperty(pA,EP_WinFunc) ){ + if( sqlite3WindowCompare(pParse,pA->y.pWin,pB->y.pWin)!=0 ) return 2; + } +#endif + }else if( pA->op==TK_NULL ){ + return 0; }else if( pA->op==TK_COLLATE ){ if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; - }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ + }else if( ALWAYS(pB->u.zToken!=0) && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } } if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; - if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ + if( (combinedFlags & EP_TokenOnly)==0 ){ if( combinedFlags & EP_xIsSelect ) return 2; if( (combinedFlags & EP_FixedCol)==0 && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2; if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; - assert( (combinedFlags & EP_Reduced)==0 ); - if( pA->op!=TK_STRING && pA->op!=TK_TRUEFALSE ){ + if( pA->op!=TK_STRING + && pA->op!=TK_TRUEFALSE + && (combinedFlags & EP_Reduced)==0 + ){ if( pA->iColumn!=pB->iColumn ) return 2; + if( pA->op2!=pB->op2 ) return 2; if( pA->iTable!=pB->iTable && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2; } -#ifndef SQLITE_OMIT_WINDOWFUNC - /* Justification for the assert(): - ** window functions have p->op==TK_FUNCTION but aggregate functions - ** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate - ** function and a window function should have failed before reaching - ** this point. And, it is not possible to have a window function and - ** a scalar function with the same name and number of arguments. So - ** if we reach this point, either A and B both window functions or - ** neither are a window functions. */ - assert( (pA->pWin==0)==(pB->pWin==0) ); - - if( pA->pWin!=0 ){ - if( sqlite3WindowCompare(pParse,pA->pWin,pB->pWin)!=0 ) return 2; - } -#endif } return 0; } @@ -100592,6 +102138,76 @@ SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ iTab); } +/* +** Return non-zero if Expr p can only be true if pNN is not NULL. +*/ +static int exprImpliesNotNull( + Parse *pParse, /* Parsing context */ + Expr *p, /* The expression to be checked */ + Expr *pNN, /* The expression that is NOT NULL */ + int iTab, /* Table being evaluated */ + int seenNot /* True if p is an operand of NOT */ +){ + assert( p ); + assert( pNN ); + if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ) return 1; + switch( p->op ){ + case TK_IN: { + if( seenNot && ExprHasProperty(p, EP_xIsSelect) ) return 0; + assert( ExprHasProperty(p,EP_xIsSelect) + || (p->x.pList!=0 && p->x.pList->nExpr>0) ); + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_BETWEEN: { + ExprList *pList = p->x.pList; + assert( pList!=0 ); + assert( pList->nExpr==2 ); + if( seenNot ) return 0; + if( exprImpliesNotNull(pParse, pList->a[0].pExpr, pNN, iTab, seenNot) + || exprImpliesNotNull(pParse, pList->a[1].pExpr, pNN, iTab, seenNot) + ){ + return 1; + } + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_EQ: + case TK_NE: + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_PLUS: + case TK_MINUS: + case TK_STAR: + case TK_REM: + case TK_BITAND: + case TK_BITOR: + case TK_SLASH: + case TK_LSHIFT: + case TK_RSHIFT: + case TK_CONCAT: { + if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1; + /* Fall thru into the next case */ + } + case TK_SPAN: + case TK_COLLATE: + case TK_BITNOT: + case TK_UPLUS: + case TK_UMINUS: { + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_TRUTH: { + if( seenNot ) return 0; + if( p->op2!=TK_IS ) return 0; + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_NOT: { + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); + } + } + return 0; +} + /* ** Return true if we can prove the pE2 will always be true if pE1 is ** true. Return false if we cannot complete the proof or if pE2 might @@ -100627,10 +102243,10 @@ SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, i ){ return 1; } - if( pE2->op==TK_NOTNULL && pE1->op!=TK_ISNULL && pE1->op!=TK_IS ){ - Expr *pX = sqlite3ExprSkipCollate(pE1->pLeft); - testcase( pX!=pE1->pLeft ); - if( sqlite3ExprCompare(pParse, pX, pE2->pLeft, iTab)==0 ) return 1; + if( pE2->op==TK_NOTNULL + && exprImpliesNotNull(pParse, pE1, pE2->pLeft, iTab, 0) + ){ + return 1; } return 0; } @@ -100652,6 +102268,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ case TK_ISNOT: case TK_NOT: case TK_ISNULL: + case TK_NOTNULL: case TK_IS: case TK_OR: case TK_CASE: @@ -100660,6 +102277,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_ISNOT ); testcase( pExpr->op==TK_NOT ); testcase( pExpr->op==TK_ISNULL ); + testcase( pExpr->op==TK_NOTNULL ); testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_OR ); testcase( pExpr->op==TK_CASE ); @@ -100688,8 +102306,8 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_LE ); testcase( pExpr->op==TK_GT ); testcase( pExpr->op==TK_GE ); - if( (pExpr->pLeft->op==TK_COLUMN && IsVirtual(pExpr->pLeft->pTab)) - || (pExpr->pRight->op==TK_COLUMN && IsVirtual(pExpr->pRight->pTab)) + if( (pExpr->pLeft->op==TK_COLUMN && IsVirtual(pExpr->pLeft->y.pTab)) + || (pExpr->pRight->op==TK_COLUMN && IsVirtual(pExpr->pRight->y.pTab)) ){ return WRC_Prune; } @@ -100722,6 +102340,17 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ */ SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){ Walker w; + p = sqlite3ExprSkipCollate(p); + while( p ){ + if( p->op==TK_NOTNULL ){ + p = p->pLeft; + }else if( p->op==TK_AND ){ + if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1; + p = p->pRight; + }else{ + break; + } + } w.xExprCallback = impliesNotNullRow; w.xSelectCallback = 0; w.xSelectCallback2 = 0; @@ -100920,7 +102549,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 ){ pCol = &pAggInfo->aCol[k]; - pCol->pTab = pExpr->pTab; + pCol->pTab = pExpr->y.pTab; pCol->iTable = pExpr->iTable; pCol->iColumn = pExpr->iColumn; pCol->iMem = ++pParse->nMem; @@ -101033,6 +102662,7 @@ SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ w.xSelectCallback2 = analyzeAggregatesInSelectEnd; w.walkerDepth = 0; w.u.pNC = pNC; + w.pParse = 0; assert( pNC->pSrcList!=0 ); sqlite3WalkExpr(&w, pExpr); } @@ -101164,9 +102794,16 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){ ** ** Or, if zName is not a system table, zero is returned. */ -static int isSystemTable(Parse *pParse, const char *zName){ - if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ - sqlite3ErrorMsg(pParse, "table %s may not be altered", zName); +static int isAlterableTable(Parse *pParse, Table *pTab){ + if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) +#ifndef SQLITE_OMIT_VIRTUALTABLE + || ( (pTab->tabFlags & TF_Shadow) + && (pParse->db->flags & SQLITE_Defensive) + && pParse->db->nVdbeExec==0 + ) +#endif + ){ + sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName); return 1; } return 0; @@ -101183,7 +102820,7 @@ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){ sqlite3NestedParse(pParse, "SELECT 1 " "FROM \"%w\".%s " - "WHERE name NOT LIKE 'sqlite_%%'" + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ", zDb, MASTER_NAME, @@ -101194,7 +102831,7 @@ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){ sqlite3NestedParse(pParse, "SELECT 1 " "FROM temp.%s " - "WHERE name NOT LIKE 'sqlite_%%'" + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ", MASTER_NAME, zDb @@ -101262,7 +102899,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( /* Make sure it is not a system table being altered, or a reserved name ** that the table is being renamed to. */ - if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){ + if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){ goto exit_rename_table; } if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto @@ -101295,15 +102932,15 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( } #endif - /* Begin a transaction for database iDb. - ** Then modify the schema cookie (since the ALTER TABLE modifies the - ** schema). Open a statement transaction if the table is a virtual - ** table. - */ + /* Begin a transaction for database iDb. Then modify the schema cookie + ** (since the ALTER TABLE modifies the schema). Call sqlite3MayAbort(), + ** as the scalar functions (e.g. sqlite_rename_table()) invoked by the + ** nested SQL may raise an exception. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } + sqlite3MayAbort(pParse); /* figure out how many UTF-8 characters are in zName */ zTabName = pTab->zName; @@ -101315,7 +102952,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( "UPDATE \"%w\".%s SET " "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) " "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)" - "AND name NOT LIKE 'sqlite_%%'" + "AND name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" , zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName ); @@ -101326,7 +102963,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( "tbl_name = %Q, " "name = CASE " "WHEN type='table' THEN %Q " - "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " + "WHEN name LIKE 'sqliteX_autoindex%%' ESCAPE 'X' " + " AND type='index' THEN " "'sqlite_autoindex_' || %Q || substr(name,%d+18) " "ELSE name END " "WHERE tbl_name=%Q COLLATE nocase AND " @@ -101372,7 +103010,6 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( int i = ++pParse->nMem; sqlite3VdbeLoadString(v, i, zName); sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); - sqlite3MayAbort(pParse); } #endif @@ -101560,7 +103197,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ sqlite3ErrorMsg(pParse, "Cannot add a column to a view"); goto exit_begin_add_column; } - if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){ + if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){ goto exit_begin_add_column; } @@ -101662,7 +103299,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn( if( !pTab ) goto exit_rename_column; /* Cannot alter a system table */ - if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column; + if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column; if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column; /* Which schema holds the table to be altered */ @@ -101693,6 +103330,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn( ** uses the sqlite_rename_column() SQL function to compute the new ** CREATE statement text for the sqlite_master table. */ + sqlite3MayAbort(pParse); zNew = sqlite3NameFromToken(db, pNew); if( !zNew ) goto exit_rename_column; assert( pNew->n>0 ); @@ -101700,7 +103338,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn( sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) " - "WHERE name NOT LIKE 'sqlite_%%' AND (type != 'index' OR tbl_name = %Q)" + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' " + " AND (type != 'index' OR tbl_name = %Q)" " AND sql NOT LIKE 'create virtual%%'", zDb, MASTER_NAME, zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1, @@ -101803,10 +103442,16 @@ static void renameTokenCheckAll(Parse *pParse, void *pPtr){ #endif /* -** Add a new RenameToken object mapping parse tree element pPtr into -** token *pToken to the Parse object currently under construction. +** Remember that the parser tree element pPtr was created using +** the token pToken. ** -** Return a copy of pPtr. +** In other words, construct a new RenameToken object and add it +** to the list of RenameToken objects currently being built up +** in pParse->pRename. +** +** The pPtr argument is returned so that this routine can be used +** with tail recursion in tokenExpr() routine, for a small performance +** improvement. */ SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){ RenameToken *pNew; @@ -101848,6 +103493,29 @@ static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){ return WRC_Continue; } +/* +** Walker callback used by sqlite3RenameExprUnmap(). +*/ +static int renameUnmapSelectCb(Walker *pWalker, Select *p){ + Parse *pParse = pWalker->pParse; + int i; + if( ALWAYS(p->pEList) ){ + ExprList *pList = p->pEList; + for(i=0; inExpr; i++){ + if( pList->a[i].zName ){ + sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zName); + } + } + } + if( ALWAYS(p->pSrc) ){ /* Every Select as a SrcList, even if it is empty */ + SrcList *pSrc = p->pSrc; + for(i=0; inSrc; i++){ + sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName); + } + } + return WRC_Continue; +} + /* ** Remove all nodes that are part of expression pExpr from the rename list. */ @@ -101856,6 +103524,7 @@ SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){ memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = pParse; sWalker.xExprCallback = renameUnmapExprCb; + sWalker.xSelectCallback = renameUnmapSelectCb; sqlite3WalkExpr(&sWalker, pExpr); } @@ -101910,14 +103579,31 @@ static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){ } } +/* +** Iterate through the Select objects that are part of WITH clauses attached +** to select statement pSelect. +*/ +static void renameWalkWith(Walker *pWalker, Select *pSelect){ + if( pSelect->pWith ){ + int i; + for(i=0; ipWith->nCte; i++){ + Select *p = pSelect->pWith->a[i].pSelect; + NameContext sNC; + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pWalker->pParse; + sqlite3SelectPrep(sNC.pParse, p, &sNC); + sqlite3WalkSelect(pWalker, p); + } + } +} + /* ** This is a Walker select callback. It does nothing. It is only required ** because without a dummy callback, sqlite3WalkExpr() and similar do not ** descend into sub-select statements. */ static int renameColumnSelectCb(Walker *pWalker, Select *p){ - UNUSED_PARAMETER(pWalker); - UNUSED_PARAMETER(p); + renameWalkWith(pWalker, p); return WRC_Continue; } @@ -101939,7 +103625,7 @@ static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); }else if( pExpr->op==TK_COLUMN && pExpr->iColumn==p->iCol - && p->pTab==pExpr->pTab + && p->pTab==pExpr->y.pTab ){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); } @@ -102067,7 +103753,6 @@ static int renameParseSql( rc = sqlite3RunParser(p, zSql, &zErr); assert( p->zErrMsg==0 ); assert( rc!=SQLITE_OK || zErr==0 ); - assert( (0!=p->pNewTable) + (0!=p->pNewIndex) + (0!=p->pNewTrigger)<2 ); p->zErrMsg = zErr; if( db->mallocFailed ) rc = SQLITE_NOMEM; if( rc==SQLITE_OK @@ -102197,9 +103882,14 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){ db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName ); pParse->eTriggerOp = pNew->op; + /* ALWAYS() because if the table of the trigger does not exist, the + ** error would have been hit before this point */ + if( ALWAYS(pParse->pTriggerTab) ){ + rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab); + } /* Resolve symbols in WHEN clause */ - if( pNew->pWhen ){ + if( rc==SQLITE_OK && pNew->pWhen ){ rc = sqlite3ResolveExprNames(&sNC, pNew->pWhen); } @@ -102245,6 +103935,7 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){ } sNC.ncFlags = 0; } + sNC.pSrcList = 0; } } } @@ -102282,11 +103973,15 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){ */ static void renameParseCleanup(Parse *pParse){ sqlite3 *db = pParse->db; + Index *pIdx; if( pParse->pVdbe ){ sqlite3VdbeFinalize(pParse->pVdbe); } sqlite3DeleteTable(db, pParse->pNewTable); - if( pParse->pNewIndex ) sqlite3FreeIndex(db, pParse->pNewIndex); + while( (pIdx = pParse->pNewIndex)!=0 ){ + pParse->pNewIndex = pIdx->pNext; + sqlite3FreeIndex(db, pIdx); + } sqlite3DeleteTrigger(db, pParse->pNewTrigger); sqlite3DbFree(db, pParse->zErrMsg); renameTokenFree(db, pParse->pRename); @@ -102313,15 +104008,8 @@ static void renameParseCleanup(Parse *pParse){ ** into zNew. The name should be quoted if bQuote is true. ** ** This function is used internally by the ALTER TABLE RENAME COLUMN command. -** Though accessible to application code, it is not intended for use by -** applications. The existance of this function, and the way it works, -** is subject to change without notice. -** -** If any of the parameters are out-of-bounds, then simply return NULL. -** An out-of-bounds parameter can only occur when the application calls -** this function directly. The parameters will always be well-formed when -** this routine is invoked by the bytecode for a legitimate ALTER TABLE -** statement. +** It is only accessible to SQL created using sqlite3NestedParse(). It is +** not reachable from ordinary SQL passed into sqlite3_prepare(). */ static void renameColumnFunc( sqlite3_context *context, @@ -102404,6 +104092,9 @@ static void renameColumnFunc( for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){ sqlite3WalkExprList(&sWalker, pIdx->aColExpr); } + for(pIdx=sParse.pNewIndex; pIdx; pIdx=pIdx->pNext){ + sqlite3WalkExprList(&sWalker, pIdx->aColExpr); + } } for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){ @@ -102477,8 +104168,8 @@ static void renameColumnFunc( */ static int renameTableExprCb(Walker *pWalker, Expr *pExpr){ RenameCtx *p = pWalker->u.pRename; - if( pExpr->op==TK_COLUMN && p->pTab==pExpr->pTab ){ - renameTokenFind(pWalker->pParse, p, (void*)&pExpr->pTab); + if( pExpr->op==TK_COLUMN && p->pTab==pExpr->y.pTab ){ + renameTokenFind(pWalker->pParse, p, (void*)&pExpr->y.pTab); } return WRC_Continue; } @@ -102490,12 +104181,17 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){ int i; RenameCtx *p = pWalker->u.pRename; SrcList *pSrc = pSelect->pSrc; + if( pSrc==0 ){ + assert( pWalker->pParse->db->mallocFailed ); + return WRC_Abort; + } for(i=0; inSrc; i++){ struct SrcList_item *pItem = &pSrc->a[i]; if( pItem->pTab==p->pTab ){ renameTokenFind(pWalker->pParse, p, pItem->zName); } } + renameWalkWith(pWalker, pSelect); return WRC_Continue; } @@ -102575,7 +104271,7 @@ static void renameTableFunc( }else{ /* Modify any FK definitions to point to the new table. */ #ifndef SQLITE_OMIT_FOREIGN_KEY - if( db->flags & SQLITE_ForeignKeys ){ + if( isLegacy==0 || (db->flags & SQLITE_ForeignKeys) ){ FKey *pFKey; for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){ @@ -102729,9 +104425,9 @@ static void renameTableTest( */ SQLITE_PRIVATE void sqlite3AlterFunctions(void){ static FuncDef aAlterTableFuncs[] = { - FUNCTION(sqlite_rename_column, 9, 0, 0, renameColumnFunc), - FUNCTION(sqlite_rename_table, 7, 0, 0, renameTableFunc), - FUNCTION(sqlite_rename_test, 5, 0, 0, renameTableTest), + INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc), + INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc), + INTERNAL_FUNCTION(sqlite_rename_test, 5, renameTableTest), }; sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); } @@ -103897,7 +105593,7 @@ static void analyzeOneTable( addrNextRow = sqlite3VdbeCurrentAddr(v); if( nColTest>0 ){ - int endDistinctTest = sqlite3VdbeMakeLabel(v); + int endDistinctTest = sqlite3VdbeMakeLabel(pParse); int *aGotoChng; /* Array of jump instruction addresses */ aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest); if( aGotoChng==0 ) continue; @@ -104780,7 +106476,7 @@ static void attachFunc( if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt); pNew->pBt = 0; pNew->pSchema = 0; - rc = sqlite3BtreeOpen(pVfs, "x", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB); + rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB); }else{ /* This is a real ATTACH ** @@ -104835,8 +106531,8 @@ static void attachFunc( assert( pVfs ); flags |= SQLITE_OPEN_MAIN_DB; rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags); - sqlite3_free( zPath ); db->nDb++; + pNew->zDbSName = sqlite3DbStrDup(db, zName); } db->noSharedCache = 0; if( rc==SQLITE_CONSTRAINT ){ @@ -104864,7 +106560,6 @@ static void attachFunc( sqlite3BtreeLeave(pNew->pBt); } pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; - if( !REOPEN_AS_MEMDB(db) ) pNew->zDbSName = sqlite3DbStrDup(db, zName); if( rc==SQLITE_OK && pNew->zDbSName==0 ){ rc = SQLITE_NOMEM_BKPT; } @@ -104892,15 +106587,19 @@ static void attachFunc( break; case SQLITE_NULL: - /* No key specified. Use the key from the main database */ - sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); - if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){ - rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); + /* No key specified. Use the key from URI filename, or if none, + ** use the key from the main database. */ + if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){ + sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); + if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){ + rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); + } } break; } } #endif + sqlite3_free( zPath ); /* If the file was opened successfully, read the schema for the new database. ** If this fails, or if opening the file failed, then close the file and @@ -104911,12 +106610,14 @@ static void attachFunc( sqlite3BtreeEnterAll(db); db->init.iDb = 0; db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); - rc = sqlite3Init(db, &zErrDyn); + if( !REOPEN_AS_MEMDB(db) ){ + rc = sqlite3Init(db, &zErrDyn); + } sqlite3BtreeLeaveAll(db); assert( zErrDyn==0 || rc!=SQLITE_OK ); } #ifdef SQLITE_USER_AUTHENTICATION - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){ u8 newAuth = 0; rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); if( newAuthauth.authLevel ){ @@ -105460,6 +107161,7 @@ SQLITE_PRIVATE void sqlite3AuthRead( int iCol; /* Index of column in table */ assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); + assert( !IN_RENAME_OBJECT || db->xAuth==0 ); if( db->xAuth==0 ) return; iDb = sqlite3SchemaToIndex(pParse->db, pSchema); if( iDb<0 ){ @@ -105516,6 +107218,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck( /* Don't do any authorization checks if the database is initialising ** or if the parser is being invoked from within sqlite3_declare_vtab. */ + assert( !IN_RENAME_OBJECT || db->xAuth==0 ); if( db->init.busy || IN_SPECIAL_PARSE ){ return SQLITE_OK; } @@ -105810,7 +107513,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ if( v && pParse->nErr==0 && !db->mallocFailed ){ /* A minimum of one cursor is required if autoincrement is used * See ticket [a696379c1f08866] */ - if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1; + assert( pParse->pAinc==0 || pParse->nTab>0 ); sqlite3VdbeMakeReady(v, pParse); pParse->rc = SQLITE_DONE; }else{ @@ -105843,7 +107546,12 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ zSql = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); if( zSql==0 ){ - return; /* A malloc must have failed */ + /* This can result either from an OOM or because the formatted string + ** exceeds SQLITE_LIMIT_LENGTH. In the latter case, we need to set + ** an error */ + if( !db->mallocFailed ) pParse->rc = SQLITE_TOOBIG; + pParse->nErr++; + return; } pParse->nested++; memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ); @@ -105937,12 +107645,11 @@ SQLITE_PRIVATE Table *sqlite3LocateTable( p = sqlite3FindTable(db, zName, zDbase); if( p==0 ){ - const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; #ifndef SQLITE_OMIT_VIRTUALTABLE - if( sqlite3FindDbName(db, zDbase)<1 ){ - /* If zName is the not the name of a table in the schema created using - ** CREATE, then check to see if it is the name of an virtual table that - ** can be an eponymous virtual table. */ + /* If zName is the not the name of a table in the schema created using + ** CREATE, then check to see if it is the name of an virtual table that + ** can be an eponymous virtual table. */ + if( pParse->disableVtab==0 ){ Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ pMod = sqlite3PragmaVtabRegister(db, zName); @@ -105952,13 +107659,18 @@ SQLITE_PRIVATE Table *sqlite3LocateTable( } } #endif - if( (flags & LOCATE_NOERR)==0 ){ - if( zDbase ){ - sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); - }else{ - sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); - } - pParse->checkSchema = 1; + if( flags & LOCATE_NOERR ) return 0; + pParse->checkSchema = 1; + }else if( IsVirtual(p) && pParse->disableVtab ){ + p = 0; + } + + if( p==0 ){ + const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; + if( zDbase ){ + sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); + }else{ + sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } } @@ -106129,17 +107841,22 @@ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){ int i; sqlite3BtreeEnterAll(db); - assert( db->nSchemaLock==0 ); for(i=0; inDb; i++){ Db *pDb = &db->aDb[i]; if( pDb->pSchema ){ - sqlite3SchemaClear(pDb->pSchema); + if( db->nSchemaLock==0 ){ + sqlite3SchemaClear(pDb->pSchema); + }else{ + DbSetProperty(db, i, DB_ResetWanted); + } } } db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk); sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); - sqlite3CollapseDatabaseArray(db); + if( db->nSchemaLock==0 ){ + sqlite3CollapseDatabaseArray(db); + } } /* @@ -106187,10 +107904,14 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ #ifdef SQLITE_DEBUG /* Record the number of outstanding lookaside allocations in schema Tables - ** prior to doing any free() operations. Since schema Tables do not use - ** lookaside, this number should not change. */ + ** prior to doing any free() operations. Since schema Tables do not use + ** lookaside, this number should not change. + ** + ** If malloc has already failed, it may be that it failed while allocating + ** a Table object that was going to be marked ephemeral. So do not check + ** that no lookaside memory is used in this case either. */ int nLookaside = 0; - if( db && (pTable->tabFlags & TF_Ephemeral)==0 ){ + if( db && !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){ nLookaside = sqlite3LookasideUsed(db, 0); } #endif @@ -106374,6 +108095,20 @@ SQLITE_PRIVATE int sqlite3TwoPartName( return iDb; } +/* +** True if PRAGMA writable_schema is ON +*/ +SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3 *db){ + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==0 ); + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== + SQLITE_WriteSchema ); + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== + SQLITE_Defensive ); + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== + (SQLITE_WriteSchema|SQLITE_Defensive) ); + return (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==SQLITE_WriteSchema; +} + /* ** This routine is used to check if the UTF-8 string zName is a legal ** unqualified name for a new schema object (table, index, view or @@ -106383,7 +108118,7 @@ SQLITE_PRIVATE int sqlite3TwoPartName( */ SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *pParse, const char *zName){ if( !pParse->db->init.busy && pParse->nested==0 - && (pParse->db->flags & SQLITE_WriteSchema)==0 + && sqlite3WritableSchema(pParse->db)==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName); return SQLITE_ERROR; @@ -106884,7 +108619,7 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue( ** accept it. This routine does the necessary conversion. It converts ** the expression given in its argument from a TK_STRING into a TK_ID ** if the expression is just a TK_STRING with an optional COLLATE clause. -** If the epxression is anything other than TK_STRING, the expression is +** If the expression is anything other than TK_STRING, the expression is ** unchanged. */ static void sqlite3StringToId(Expr *p){ @@ -106960,7 +108695,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( && sortOrder!=SQLITE_SO_DESC ){ if( IN_RENAME_OBJECT && pList ){ - sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pList->a[0].pExpr); + Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[0].pExpr); + sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr); } pTab->iPKey = iCol; pTab->keyConf = (u8)onError; @@ -107280,10 +109016,51 @@ static void estimateIndexWidth(Index *pIdx){ pIdx->szIdxRow = sqlite3LogEst(wIndex*4); } -/* Return true if value x is found any of the first nCol entries of aiCol[] +/* Return true if column number x is any of the first nCol entries of aiCol[]. +** This is used to determine if the column number x appears in any of the +** first nCol entries of an index. */ static int hasColumn(const i16 *aiCol, int nCol, int x){ - while( nCol-- > 0 ) if( x==*(aiCol++) ) return 1; + while( nCol-- > 0 ){ + assert( aiCol[0]>=0 ); + if( x==*(aiCol++) ){ + return 1; + } + } + return 0; +} + +/* +** Return true if any of the first nKey entries of index pIdx exactly +** match the iCol-th entry of pPk. pPk is always a WITHOUT ROWID +** PRIMARY KEY index. pIdx is an index on the same table. pIdx may +** or may not be the same index as pPk. +** +** The first nKey entries of pIdx are guaranteed to be ordinary columns, +** not a rowid or expression. +** +** This routine differs from hasColumn() in that both the column and the +** collating sequence must match for this routine, but for hasColumn() only +** the column name must match. +*/ +static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){ + int i, j; + assert( nKey<=pIdx->nColumn ); + assert( iColnColumn,pPk->nKeyCol) ); + assert( pPk->idxType==SQLITE_IDXTYPE_PRIMARYKEY ); + assert( pPk->pTable->tabFlags & TF_WithoutRowid ); + assert( pPk->pTable==pIdx->pTable ); + testcase( pPk==pIdx ); + j = pPk->aiColumn[iCol]; + assert( j!=XN_ROWID && j!=XN_EXPR ); + for(i=0; iaiColumn[i]>=0 || j>=0 ); + if( pIdx->aiColumn[i]==j + && sqlite3StrICmp(pIdx->azColl[i], pPk->azColl[iCol])==0 + ){ + return 1; + } + } return 0; } @@ -107372,15 +109149,19 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ) return; + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey); + } pList->a[0].sortOrder = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); + pTab->iPKey = -1; sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, SQLITE_IDXTYPE_PRIMARYKEY); if( db->mallocFailed || pParse->nErr ) return; pPk = sqlite3PrimaryKeyIndex(pTab); - pTab->iPKey = -1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); + assert( pPk!=0 ); /* ** Remove all redundant columns from the PRIMARY KEY. For example, change @@ -107388,9 +109169,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ ** code assumes the PRIMARY KEY contains no repeated columns. */ for(i=j=1; inKeyCol; i++){ - if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){ + if( isDupColumn(pPk, j, pPk, i) ){ pPk->nColumn--; }else{ + testcase( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ); pPk->aiColumn[j++] = pPk->aiColumn[i]; } } @@ -107420,7 +109202,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ int n; if( IsPrimaryKeyIndex(pIdx) ) continue; for(i=n=0; iaiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++; + if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){ + testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); + n++; + } } if( n==0 ){ /* This index is a superset of the primary key */ @@ -107429,9 +109214,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ } if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return; for(i=0, j=pIdx->nKeyCol; iaiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ){ + if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){ + testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); pIdx->aiColumn[j] = pPk->aiColumn[i]; pIdx->azColl[j] = pPk->azColl[i]; + if( pPk->aSortOrder[i] ){ + /* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */ + pIdx->bAscKeyBug = 1; + } j++; } } @@ -107459,6 +109249,36 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ recomputeColumnsNotIndexed(pPk); } +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Return true if zName is a shadow table name in the current database +** connection. +** +** zName is temporarily modified while this routine is running, but is +** restored to its original value prior to this routine returning. +*/ +static int isShadowTableName(sqlite3 *db, char *zName){ + char *zTail; /* Pointer to the last "_" in zName */ + Table *pTab; /* Table that zName is a shadow of */ + Module *pMod; /* Module for the virtual table */ + + zTail = strrchr(zName, '_'); + if( zTail==0 ) return 0; + *zTail = 0; + pTab = sqlite3FindTable(db, zName, 0); + *zTail = '_'; + if( pTab==0 ) return 0; + if( !IsVirtual(pTab) ) return 0; + pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]); + if( pMod==0 ) return 0; + if( pMod->pModule->iVersion<3 ) return 0; + if( pMod->pModule->xShadowName==0 ) return 0; + return pMod->pModule->xShadowName(zTail+1); +} +#else +# define isShadowTableName(x,y) 0 +#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ + /* ** This routine is called to report the final ")" that terminates ** a CREATE TABLE statement. @@ -107498,6 +109318,10 @@ SQLITE_PRIVATE void sqlite3EndTable( p = pParse->pNewTable; if( p==0 ) return; + if( pSelect==0 && isShadowTableName(db, p->zName) ){ + p->tabFlags |= TF_Shadow; + } + /* If the db->init.busy is 1 it means we are reading the SQL off the ** "sqlite_master" or "sqlite_temp_master" table on the disk. ** So do not write to the disk again. Extract the root page number @@ -107516,6 +109340,11 @@ SQLITE_PRIVATE void sqlite3EndTable( if( p->tnum==1 ) p->tabFlags |= TF_Readonly; } + assert( (p->tabFlags & TF_HasPrimaryKey)==0 + || p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 ); + assert( (p->tabFlags & TF_HasPrimaryKey)!=0 + || (p->iPKey<0 && sqlite3PrimaryKeyIndex(p)==0) ); + /* Special processing for WITHOUT ROWID Tables */ if( tabOpts & TF_WithoutRowid ){ if( (p->tabFlags & TF_Autoincrement) ){ @@ -108005,7 +109834,7 @@ SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iT static void destroyRootPage(Parse *pParse, int iTable, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); int r1 = sqlite3GetTempReg(pParse); - assert( iTable>1 ); + if( iTable<2 ) sqlite3ErrorMsg(pParse, "corrupt schema"); sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); sqlite3MayAbort(pParse); #ifndef SQLITE_OMIT_AUTOVACUUM @@ -108164,6 +109993,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in */ if( IsVirtual(pTab) ){ sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0); + sqlite3MayAbort(pParse); } sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); sqlite3ChangeCookie(pParse, iDb); @@ -108510,10 +110340,27 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); sqlite3VdbeJumpHere(v, j2); }else{ + /* Most CREATE INDEX and REINDEX statements that are not UNIQUE can not + ** abort. The exception is if one of the indexed expressions contains a + ** user function that throws an exception when it is evaluated. But the + ** overhead of adding a statement journal to a CREATE INDEX statement is + ** very small (since most of the pages written do not contain content that + ** needs to be restored if the statement aborts), so we call + ** sqlite3MayAbort() for all CREATE INDEX statements. */ + sqlite3MayAbort(pParse); addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); - sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); + if( !pIndex->bAscKeyBug ){ + /* This OP_SeekEnd opcode makes index insert for a REINDEX go much + ** faster by avoiding unnecessary seeks. But the optimization does + ** not work for UNIQUE constraint indexes on WITHOUT ROWID tables + ** with DESC primary keys, since those indexes have there keys in + ** a different order from the main table. + ** See ticket: https://www.sqlite.org/src/info/bba7b69f9849b5bf + */ + sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); + } sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); @@ -108668,13 +110515,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex( assert( pParse->nErr==0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 + && pTblName!=0 #if SQLITE_USER_AUTHENTICATION && sqlite3UserAuthTable(pTab->zName)==0 #endif #ifdef SQLITE_ALLOW_SQLITE_MASTER_INDEX && sqlite3StrICmp(&pTab->zName[7],"master")!=0 #endif - && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; @@ -108778,6 +110625,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex( sqlite3ExprListSetSortOrder(pList, sortOrder); }else{ sqlite3ExprListCheckLength(pParse, pList, "index"); + if( pParse->nErr ) goto exit_create_index; } /* Figure out how many bytes of space are required to store explicitly @@ -108796,6 +110644,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex( */ nName = sqlite3Strlen30(zName); nExtraCol = pPk ? pPk->nKeyCol : 1; + assert( pList->nExpr + nExtraCol <= 32767 /* Fits in i16 */ ); pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol, nName + nExtra + 1, &zExtra); if( db->mallocFailed ){ @@ -108903,9 +110752,10 @@ SQLITE_PRIVATE void sqlite3CreateIndex( for(j=0; jnKeyCol; j++){ int x = pPk->aiColumn[j]; assert( x>=0 ); - if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){ + if( isDupColumn(pIndex, pIndex->nKeyCol, pPk, j) ){ pIndex->nColumn--; }else{ + testcase( hasColumn(pIndex->aiColumn,pIndex->nKeyCol,x) ); pIndex->aiColumn[i] = x; pIndex->azColl[i] = pPk->azColl[j]; pIndex->aSortOrder[i] = pPk->aSortOrder[j]; @@ -108992,6 +110842,11 @@ SQLITE_PRIVATE void sqlite3CreateIndex( } } if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; + if( IN_RENAME_OBJECT ){ + pIndex->pNext = pParse->pNewIndex; + pParse->pNewIndex = pIndex; + pIndex = 0; + } goto exit_create_index; } } @@ -109007,6 +110862,14 @@ SQLITE_PRIVATE void sqlite3CreateIndex( Index *p; assert( !IN_SPECIAL_PARSE ); assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); + if( pTblName!=0 ){ + pIndex->tnum = db->init.newTnum; + if( sqlite3IndexHasDuplicateRootPage(pIndex) ){ + sqlite3ErrorMsg(pParse, "invalid rootpage"); + pParse->rc = SQLITE_CORRUPT_BKPT; + goto exit_create_index; + } + } p = sqlite3HashInsert(&pIndex->pSchema->idxHash, pIndex->zName, pIndex); if( p ){ @@ -109015,9 +110878,6 @@ SQLITE_PRIVATE void sqlite3CreateIndex( goto exit_create_index; } db->mDbFlags |= DBFLAG_SchemaChange; - if( pTblName!=0 ){ - pIndex->tnum = db->init.newTnum; - } } /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the @@ -109269,9 +111129,9 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate( int *pIdx /* Write the index of a new slot here */ ){ char *z; - int n = *pnEntry; + sqlite3_int64 n = *pIdx = *pnEntry; if( (n & (n-1))==0 ){ - int sz = (n==0) ? 1 : 2*n; + sqlite3_int64 sz = (n==0) ? 1 : 2*n; void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry); if( pNew==0 ){ *pIdx = -1; @@ -109281,7 +111141,6 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate( } z = (char*)pArray; memset(&z[n * szEntry], 0, szEntry); - *pIdx = n; ++*pnEntry; return pArray; } @@ -109343,6 +111202,18 @@ SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){ return -1; } +/* +** Maximum size of a SrcList object. +** The SrcList object is used to represent the FROM clause of a +** SELECT statement, and the query planner cannot deal with more +** than 64 tables in a join. So any value larger than 64 here +** is sufficient for most uses. Smaller values, like say 10, are +** appropriate for small and memory-limited applications. +*/ +#ifndef SQLITE_MAX_SRCLIST +# define SQLITE_MAX_SRCLIST 200 +#endif + /* ** Expand the space allocated for the given SrcList object by ** creating nExtra new slots beginning at iStart. iStart is zero based. @@ -109359,11 +111230,12 @@ SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){ ** the iStart value would be 0. The result then would ** be: nil, nil, nil, A, B. ** -** If a memory allocation fails the SrcList is unchanged. The -** db->mallocFailed flag will be set to true. +** If a memory allocation fails or the SrcList becomes too large, leave +** the original SrcList unchanged, return NULL, and leave an error message +** in pParse. */ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( - sqlite3 *db, /* Database connection to notify of OOM errors */ + Parse *pParse, /* Parsing context into which errors are reported */ SrcList *pSrc, /* The SrcList to be enlarged */ int nExtra, /* Number of new slots to add to pSrc->a[] */ int iStart /* Index in pSrc->a[] of first new slot */ @@ -109379,17 +111251,23 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( /* Allocate additional space if needed */ if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){ SrcList *pNew; - int nAlloc = pSrc->nSrc*2+nExtra; - int nGot; + sqlite3_int64 nAlloc = 2*(sqlite3_int64)pSrc->nSrc+nExtra; + sqlite3 *db = pParse->db; + + if( pSrc->nSrc+nExtra>=SQLITE_MAX_SRCLIST ){ + sqlite3ErrorMsg(pParse, "too many FROM clause terms, max: %d", + SQLITE_MAX_SRCLIST); + return 0; + } + if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST; pNew = sqlite3DbRealloc(db, pSrc, sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) ); if( pNew==0 ){ assert( db->mallocFailed ); - return pSrc; + return 0; } pSrc = pNew; - nGot = (sqlite3DbMallocSize(db, pNew) - sizeof(*pSrc))/sizeof(pSrc->a[0])+1; - pSrc->nAlloc = nGot; + pSrc->nAlloc = nAlloc; } /* Move existing slots that come after the newly inserted slots @@ -109414,7 +111292,8 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( ** Append a new table name to the given SrcList. Create a new SrcList if ** need be. A new entry is created in the SrcList even if pTable is NULL. ** -** A SrcList is returned, or NULL if there is an OOM error. The returned +** A SrcList is returned, or NULL if there is an OOM error or if the +** SrcList grows to large. The returned ** SrcList might be the same as the SrcList that was input or it might be ** a new one. If an OOM error does occurs, then the prior value of pList ** that is input to this routine is automatically freed. @@ -109445,27 +111324,32 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( ** before being added to the SrcList. */ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( - sqlite3 *db, /* Connection to notify of malloc failures */ + Parse *pParse, /* Parsing context, in which errors are reported */ SrcList *pList, /* Append to this SrcList. NULL creates a new SrcList */ Token *pTable, /* Table to append */ Token *pDatabase /* Database of the table */ ){ struct SrcList_item *pItem; + sqlite3 *db; assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */ - assert( db!=0 ); + assert( pParse!=0 ); + assert( pParse->db!=0 ); + db = pParse->db; if( pList==0 ){ - pList = sqlite3DbMallocRawNN(db, sizeof(SrcList) ); + pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) ); if( pList==0 ) return 0; pList->nAlloc = 1; pList->nSrc = 1; memset(&pList->a[0], 0, sizeof(pList->a[0])); pList->a[0].iCursor = -1; }else{ - pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc); - } - if( db->mallocFailed ){ - sqlite3SrcListDelete(db, pList); - return 0; + SrcList *pNew = sqlite3SrcListEnlarge(pParse, pList, 1, pList->nSrc); + if( pNew==0 ){ + sqlite3SrcListDelete(db, pList); + return 0; + }else{ + pList = pNew; + } } pItem = &pList->a[pList->nSrc-1]; if( pDatabase && pDatabase->z==0 ){ @@ -109554,7 +111438,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( ); goto append_from_error; } - p = sqlite3SrcListAppend(db, p, pTable, pDatabase); + p = sqlite3SrcListAppend(pParse, p, pTable, pDatabase); if( p==0 ){ goto append_from_error; } @@ -109874,7 +111758,8 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint( StrAccum errMsg; Table *pTab = pIdx->pTable; - sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); + sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, + pParse->db->aLimit[SQLITE_LIMIT_LENGTH]); if( pIdx->aColExpr ){ sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName); }else{ @@ -109943,13 +111828,15 @@ static int collationMatch(const char *zColl, Index *pIndex){ */ #ifndef SQLITE_OMIT_REINDEX static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ - Index *pIndex; /* An index associated with pTab */ + if( !IsVirtual(pTab) ){ + Index *pIndex; /* An index associated with pTab */ - for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ - if( zColl==0 || collationMatch(zColl, pIndex) ){ - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3RefillIndex(pParse, pIndex, -1); + for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ + if( zColl==0 || collationMatch(zColl, pIndex) ){ + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3RefillIndex(pParse, pIndex, -1); + } } } } @@ -110121,7 +112008,7 @@ SQLITE_PRIVATE With *sqlite3WithAdd( } if( pWith ){ - int nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); + sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); pNew = sqlite3DbRealloc(db, pWith, nByte); }else{ pNew = sqlite3DbMallocZero(db, sizeof(*pWith)); @@ -110448,7 +112335,7 @@ static int matchQuality( ** Search a FuncDefHash for a function with the given name. Return ** a pointer to the matching FuncDef if found, or 0 if there is no match. */ -static FuncDef *functionSearch( +SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch( int h, /* Hash of the name */ const char *zFunc /* Name of function */ ){ @@ -110473,9 +112360,9 @@ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs( FuncDef *pOther; const char *zName = aDef[i].zName; int nName = sqlite3Strlen30(zName); - int h = (zName[0] + nName) % SQLITE_FUNC_HASH_SZ; + int h = SQLITE_FUNC_HASH(zName[0], nName); assert( zName[0]>='a' && zName[0]<='z' ); - pOther = functionSearch(h, zName); + pOther = sqlite3FunctionSearch(h, zName); if( pOther ){ assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] ); aDef[i].pNext = pOther->pNext; @@ -110552,8 +112439,8 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( */ if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){ bestScore = 0; - h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ; - p = functionSearch(h, zName); + h = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zName[0]], nName); + p = sqlite3FunctionSearch(h, zName); while( p ){ int score = matchQuality(p, nArg, enc); if( score>bestScore ){ @@ -110700,32 +112587,49 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ return pTab; } +/* Return true if table pTab is read-only. +** +** A table is read-only if any of the following are true: +** +** 1) It is a virtual table and no implementation of the xUpdate method +** has been provided +** +** 2) It is a system table (i.e. sqlite_master), this call is not +** part of a nested parse and writable_schema pragma has not +** been specified +** +** 3) The table is a shadow table, the database connection is in +** defensive mode, and the current sqlite3_prepare() +** is for a top-level SQL statement. +*/ +static int tabIsReadOnly(Parse *pParse, Table *pTab){ + sqlite3 *db; + if( IsVirtual(pTab) ){ + return sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0; + } + if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0; + db = pParse->db; + if( (pTab->tabFlags & TF_Readonly)!=0 ){ + return sqlite3WritableSchema(db)==0 && pParse->nested==0; + } + assert( pTab->tabFlags & TF_Shadow ); + return (db->flags & SQLITE_Defensive)!=0 +#ifndef SQLITE_OMIT_VIRTUALTABLE + && db->pVtabCtx==0 +#endif + && db->nVdbeExec==0; +} + /* ** Check to make sure the given table is writable. If it is not ** writable, generate an error message and return 1. If it is ** writable return 0; */ SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ - /* A table is not writable under the following circumstances: - ** - ** 1) It is a virtual table and no implementation of the xUpdate method - ** has been provided, or - ** 2) It is a system table (i.e. sqlite_master), this call is not - ** part of a nested parse and writable_schema pragma has not - ** been specified. - ** - ** In either case leave an error message in pParse and return non-zero. - */ - if( ( IsVirtual(pTab) - && sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ) - || ( (pTab->tabFlags & TF_Readonly)!=0 - && (pParse->db->flags & SQLITE_WriteSchema)==0 - && pParse->nested==0 ) - ){ + if( tabIsReadOnly(pParse, pTab) ){ sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); return 1; } - #ifndef SQLITE_OMIT_VIEW if( !viewOk && pTab->pSelect ){ sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); @@ -110756,7 +112660,7 @@ SQLITE_PRIVATE void sqlite3MaterializeView( sqlite3 *db = pParse->db; int iDb = sqlite3SchemaToIndex(db, pView->pSchema); pWhere = sqlite3ExprDup(db, pWhere, 0); - pFrom = sqlite3SrcListAppend(db, 0, 0, 0); + pFrom = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pFrom ){ assert( pFrom->nSrc==1 ); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); @@ -111156,7 +113060,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( /* If this DELETE cannot use the ONEPASS strategy, this is the ** end of the WHERE loop */ if( eOnePass!=ONEPASS_OFF ){ - addrBypass = sqlite3VdbeMakeLabel(v); + addrBypass = sqlite3VdbeMakeLabel(pParse); }else{ sqlite3WhereEnd(pWInfo); } @@ -111345,7 +113249,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete( /* Seek cursor iCur to the row to delete. If this row no longer exists ** (this can happen if a trigger program has already deleted it), do ** not attempt to delete it or fire any DELETE triggers. */ - iLabel = sqlite3VdbeMakeLabel(v); + iLabel = sqlite3VdbeMakeLabel(pParse); opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound; if( eMode==ONEPASS_OFF ){ sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk); @@ -111551,7 +113455,7 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ - *piPartIdxLabel = sqlite3VdbeMakeLabel(v); + *piPartIdxLabel = sqlite3VdbeMakeLabel(pParse); pParse->iSelfTab = iDataCur + 1; sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); @@ -111622,6 +113526,7 @@ SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ /* #include "sqliteInt.h" */ /* #include */ /* #include */ +/* #include */ /* #include "vdbeInt.h" */ /* @@ -111807,6 +113712,7 @@ static void instrFunc( int typeHaystack, typeNeedle; int N = 1; int isText; + unsigned char firstChar; UNUSED_PARAMETER(argc); typeHaystack = sqlite3_value_type(argv[0]); @@ -111825,7 +113731,10 @@ static void instrFunc( isText = 1; } if( zNeedle==0 || (nHaystack && zHaystack==0) ) return; - while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){ + firstChar = zNeedle[0]; + while( nNeedle<=nHaystack + && (zHaystack[0]!=firstChar || memcmp(zHaystack, zNeedle, nNeedle)!=0) + ){ N++; do{ nHaystack--; @@ -111988,10 +113897,10 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ ** handle the rounding directly, ** otherwise use printf. */ - if( n==0 && r>=0 && r+4503599627370496.0 ){ + /* The value has no fractional part so there is nothing to round */ + }else if( n==0 ){ + r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5))); }else{ zBuf = sqlite3_mprintf("%.*f",n,r); if( zBuf==0 ){ @@ -112116,11 +114025,11 @@ static void randomBlob( int argc, sqlite3_value **argv ){ - int n; + sqlite3_int64 n; unsigned char *p; assert( argc==1 ); UNUSED_PARAMETER(argc); - n = sqlite3_value_int(argv[0]); + n = sqlite3_value_int64(argv[0]); if( n<1 ){ n = 1; } @@ -112445,8 +114354,6 @@ static void likeFunc( return; } #endif - zB = sqlite3_value_text(argv[0]); - zA = sqlite3_value_text(argv[1]); /* Limit the length of the LIKE or GLOB pattern to avoid problems ** of deep recursion and N*N behavior in patternCompare(). @@ -112458,8 +114365,6 @@ static void likeFunc( sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); return; } - assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */ - if( argc==3 ){ /* The escape character string must consist of a single UTF-8 character. ** Otherwise, return an error. @@ -112475,6 +114380,8 @@ static void likeFunc( }else{ escape = pInfo->matchSet; } + zB = sqlite3_value_text(argv[0]); + zA = sqlite3_value_text(argv[1]); if( zA && zB ){ #ifdef SQLITE_TEST sqlite3_like_count++; @@ -113400,35 +115307,24 @@ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ } /* -** Set the LIKEOPT flag on the 2-argument function with the given name. -*/ -static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){ - FuncDef *pDef; - pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0); - if( ALWAYS(pDef) ){ - pDef->funcFlags |= flagVal; - } -} - -/* -** Register the built-in LIKE and GLOB functions. The caseSensitive +** Re-register the built-in LIKE functions. The caseSensitive ** parameter determines whether or not the LIKE operator is case -** sensitive. GLOB is always case sensitive. +** sensitive. */ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ struct compareInfo *pInfo; + int flags; if( caseSensitive ){ pInfo = (struct compareInfo*)&likeInfoAlt; + flags = SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE; }else{ pInfo = (struct compareInfo*)&likeInfoNorm; + flags = SQLITE_FUNC_LIKE; } sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); - sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8, - (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0, 0, 0); - setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE); - setLikeOptFlag(db, "like", - caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE); + sqlite3FindFunction(db, "like", 2, SQLITE_UTF8, 0)->funcFlags |= flags; + sqlite3FindFunction(db, "like", 3, SQLITE_UTF8, 0)->funcFlags |= flags; } /* @@ -113956,7 +115852,7 @@ static void fkLookupParent( int i; /* Iterator variable */ Vdbe *v = sqlite3GetVdbe(pParse); /* Vdbe to add code to */ int iCur = pParse->nTab - 1; /* Cursor number to use */ - int iOk = sqlite3VdbeMakeLabel(v); /* jump here if parent key found */ + int iOk = sqlite3VdbeMakeLabel(pParse); /* jump here if parent key found */ sqlite3VdbeVerifyAbortable(v, (!pFKey->isDeferred @@ -114129,7 +116025,7 @@ static Expr *exprTableColumn( ){ Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0); if( pExpr ){ - pExpr->pTab = pTab; + pExpr->y.pTab = pTab; pExpr->iTable = iCursor; pExpr->iColumn = iCol; } @@ -114218,7 +116114,7 @@ static void fkScanChildren( zCol = pFKey->pFrom->aCol[iCol].zName; pRight = sqlite3Expr(db, TK_ID, zCol); pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); - pWhere = sqlite3ExprAnd(db, pWhere, pEq); + pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); } /* If the child table is the same as the parent table, then add terms @@ -114229,8 +116125,11 @@ static void fkScanChildren( ** NOT( $current_a==a AND $current_b==b AND ... ) ** ** The first form is used for rowid tables. The second form is used - ** for WITHOUT ROWID tables. In the second form, the primary key is - ** (a,b,...) + ** for WITHOUT ROWID tables. In the second form, the *parent* key is + ** (a,b,...). Either the parent or primary key could be used to + ** uniquely identify the current row, but the parent key is more convenient + ** as the required values have already been loaded into registers + ** by the caller. */ if( pTab==pFKey->pFrom && nIncr>0 ){ Expr *pNe; /* Expression (pLeft != pRight) */ @@ -114242,19 +116141,18 @@ static void fkScanChildren( pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight); }else{ Expr *pEq, *pAll = 0; - Index *pPk = sqlite3PrimaryKeyIndex(pTab); assert( pIdx!=0 ); - for(i=0; inKeyCol; i++){ + for(i=0; inKeyCol; i++){ i16 iCol = pIdx->aiColumn[i]; assert( iCol>=0 ); pLeft = exprTableRegister(pParse, pTab, regData, iCol); - pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol); - pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); - pAll = sqlite3ExprAnd(db, pAll, pEq); + pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zName); + pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight); + pAll = sqlite3ExprAnd(pParse, pAll, pEq); } pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0); } - pWhere = sqlite3ExprAnd(db, pWhere, pNe); + pWhere = sqlite3ExprAnd(pParse, pWhere, pNe); } /* Resolve the references in the WHERE clause. */ @@ -114354,7 +116252,7 @@ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTa if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break; } if( !p ) return; - iSkip = sqlite3VdbeMakeLabel(v); + iSkip = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); VdbeCoverage(v); } @@ -114639,7 +116537,7 @@ SQLITE_PRIVATE void sqlite3FkCheck( /* Create a SrcList structure containing the child table. We need the ** child table as a SrcList for sqlite3WhereBegin() */ - pSrc = sqlite3SrcListAppend(db, 0, 0, 0); + pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pSrc ){ struct SrcList_item *pItem = pSrc->a; pItem->pTab = pFKey->pFrom; @@ -114860,7 +116758,7 @@ static Trigger *fkActionTrigger( sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0) ); - pWhere = sqlite3ExprAnd(db, pWhere, pEq); + pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); /* For ON UPDATE, construct the next term of the WHEN clause. ** The final WHEN clause will be like this: @@ -114876,7 +116774,7 @@ static Trigger *fkActionTrigger( sqlite3ExprAlloc(db, TK_ID, &tNew, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)) ); - pWhen = sqlite3ExprAnd(db, pWhen, pEq); + pWhen = sqlite3ExprAnd(pParse, pWhen, pEq); } if( action!=OE_Restrict && (action!=OE_Cascade || pChanges) ){ @@ -114916,7 +116814,7 @@ static Trigger *fkActionTrigger( } pSelect = sqlite3SelectNew(pParse, sqlite3ExprListAppend(pParse, 0, pRaise), - sqlite3SrcListAppend(db, 0, &tFrom, 0), + sqlite3SrcListAppend(pParse, 0, &tFrom, 0), pWhere, 0, 0, 0, 0, 0 ); @@ -115205,7 +117103,8 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ }while( i>=0 && zColAff[i]==SQLITE_AFF_BLOB ); pTab->zColAff = zColAff; } - i = sqlite3Strlen30(zColAff); + assert( zColAff!=0 ); + i = sqlite3Strlen30NN(zColAff); if( i ){ if( iReg ){ sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i); @@ -115377,6 +117276,7 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){ aOp[7].p2 = memId+2; aOp[7].p1 = memId; aOp[10].p2 = memId; + if( pParse->nTab==0 ) pParse->nTab = 1; } } @@ -115871,7 +117771,7 @@ SQLITE_PRIVATE void sqlite3Insert( int nIdx; nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0, &iDataCur, &iIdxCur); - aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1)); + aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+2)); if( aRegIdx==0 ){ goto insert_cleanup; } @@ -115880,9 +117780,15 @@ SQLITE_PRIVATE void sqlite3Insert( aRegIdx[i] = ++pParse->nMem; pParse->nMem += pIdx->nColumn; } + aRegIdx[i] = ++pParse->nMem; /* Register to store the table record */ } #ifndef SQLITE_OMIT_UPSERT if( pUpsert ){ + if( IsVirtual(pTab) ){ + sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"", + pTab->zName); + goto insert_cleanup; + } pTabList->a[0].iCursor = iDataCur; pUpsert->pUpsertSrc = pTabList; pUpsert->regData = regData; @@ -115923,7 +117829,7 @@ SQLITE_PRIVATE void sqlite3Insert( /* Run the BEFORE and INSTEAD OF triggers, if there are any */ - endOfLoop = sqlite3VdbeMakeLabel(v); + endOfLoop = sqlite3VdbeMakeLabel(pParse); if( tmask & TRIGGER_BEFORE ){ int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1); @@ -116005,16 +117911,12 @@ SQLITE_PRIVATE void sqlite3Insert( }else if( pSelect ){ sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid); }else{ - VdbeOp *pOp; - sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid); - pOp = sqlite3VdbeGetOp(v, -1); - assert( pOp!=0 ); - if( pOp->opcode==OP_Null && !IsVirtual(pTab) ){ + Expr *pIpk = pList->a[ipkColumn].pExpr; + if( pIpk->op==TK_NULL && !IsVirtual(pTab) ){ + sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); appendFlag = 1; - pOp->opcode = OP_NewRowid; - pOp->p1 = iDataCur; - pOp->p2 = regRowid; - pOp->p3 = regAutoinc; + }else{ + sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid); } } /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid @@ -116185,14 +118087,15 @@ SQLITE_PRIVATE void sqlite3Insert( #endif /* -** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged() +** Meanings of bits in of pWalker->eCode for +** sqlite3ExprReferencesUpdatedColumn() */ #define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */ #define CKCNSTRNT_ROWID 0x02 /* CHECK constraint references the ROWID */ -/* This is the Walker callback from checkConstraintUnchanged(). Set -** bit 0x01 of pWalker->eCode if -** pWalker->eCode to 0 if this expression node references any of the +/* This is the Walker callback from sqlite3ExprReferencesUpdatedColumn(). +* Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this +** expression node references any of the ** columns that are being modifed by an UPDATE statement. */ static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){ @@ -116214,12 +118117,21 @@ static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){ ** only columns that are modified by the UPDATE are those for which ** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true. ** -** Return true if CHECK constraint pExpr does not use any of the +** Return true if CHECK constraint pExpr uses any of the ** changing columns (or the rowid if it is changing). In other words, -** return true if this CHECK constraint can be skipped when validating +** return true if this CHECK constraint must be validated for ** the new row in the UPDATE statement. +** +** 2018-09-15: pExpr might also be an expression for an index-on-expressions. +** The operation of this routine is the same - return true if an only if +** the expression uses one or more of columns identified by the second and +** third arguments. */ -static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){ +SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn( + Expr *pExpr, /* The expression to be checked */ + int *aiChng, /* aiChng[x]>=0 if column x changed by the UPDATE */ + int chngRowid /* True if UPDATE changes the rowid */ +){ Walker w; memset(&w, 0, sizeof(w)); w.eCode = 0; @@ -116234,7 +118146,7 @@ static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){ testcase( w.eCode==CKCNSTRNT_COLUMN ); testcase( w.eCode==CKCNSTRNT_ROWID ); testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) ); - return !w.eCode; + return w.eCode!=0; } /* @@ -116272,6 +118184,14 @@ static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){ ** the same as the order of indices on the linked list of indices ** at pTab->pIndex. ** +** (2019-05-07) The generated code also creates a new record for the +** main table, if pTab is a rowid table, and stores that record in the +** register identified by aRegIdx[nIdx] - in other words in the first +** entry of aRegIdx[] past the last index. It is important that the +** record be generated during constraint checks to avoid affinity changes +** to the register content that occur after constraint checks but before +** the new record is inserted. +** ** The caller must have already opened writeable cursors on the main ** table and all applicable indices (that is to say, all indices for which ** aRegIdx[] is not zero). iDataCur is the cursor for the main table when @@ -116399,7 +118319,20 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( } assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); + addr1 = 0; switch( onError ){ + case OE_Replace: { + assert( onError==OE_Replace ); + addr1 = sqlite3VdbeMakeLabel(pParse); + sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1); + VdbeCoverage(v); + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i); + sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1); + VdbeCoverage(v); + onError = OE_Abort; + /* Fall through into the OE_Abort case to generate code that runs + ** if both the input and the default value are NULL */ + } case OE_Abort: sqlite3MayAbort(pParse); /* Fall through */ @@ -116412,21 +118345,15 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); VdbeCoverage(v); + if( addr1 ) sqlite3VdbeResolveLabel(v, addr1); break; } - case OE_Ignore: { + default: { + assert( onError==OE_Ignore ); sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest); VdbeCoverage(v); break; } - default: { - assert( onError==OE_Replace ); - addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i); - VdbeCoverage(v); - sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i); - sqlite3VdbeJumpHere(v, addr1); - break; - } } } @@ -116440,8 +118367,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( for(i=0; inExpr; i++){ int allOk; Expr *pExpr = pCheck->a[i].pExpr; - if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue; - allOk = sqlite3VdbeMakeLabel(v); + if( aiChng + && !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng) + ){ + /* The check constraints do not reference any of the columns being + ** updated so there is no point it verifying the check constraint */ + continue; + } + allOk = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeVerifyAbortable(v, onError); sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL); if( onError==OE_Ignore ){ @@ -116449,7 +118382,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( }else{ char *zName = pCheck->a[i].zName; if( zName==0 ) zName = pTab->zName; - if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ + if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK, onError, zName, P4_TRANSIENT, P5_ConstraintCheck); @@ -116508,7 +118441,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** exist in the table. */ if( pkChng && pPk==0 ){ - int addrRowidOk = sqlite3VdbeMakeLabel(v); + int addrRowidOk = sqlite3VdbeMakeLabel(pParse); /* Figure out what action to take in case of a rowid collision */ onError = pTab->keyConf; @@ -116658,7 +118591,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( VdbeComment((v, "Skip upsert subroutine")); sqlite3VdbeJumpHere(v, upsertJump); }else{ - addrUniqueOk = sqlite3VdbeMakeLabel(v); + addrUniqueOk = sqlite3VdbeMakeLabel(pParse); } if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){ sqlite3TableAffinity(v, pTab, regNewData+1); @@ -116702,7 +118635,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); VdbeComment((v, "for %s", pIdx->zName)); #ifdef SQLITE_ENABLE_NULL_TRIM - if( pIdx->idxType==2 ) sqlite3SetMakeRecordP5(v, pIdx->pTable); + if( pIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ + sqlite3SetMakeRecordP5(v, pIdx->pTable); + } #endif /* In an UPDATE operation, if this index is the PRIMARY KEY index @@ -116741,7 +118676,11 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** (3) There are no secondary indexes on the table ** (4) No delete triggers need to be fired if there is a conflict ** (5) No FK constraint counters need to be updated if a conflict occurs. - */ + ** + ** This is not possible for ENABLE_PREUPDATE_HOOK builds, as the row + ** must be explicitly deleted in order to ensure any pre-update hook + ** is invoked. */ +#ifndef SQLITE_ENABLE_PREUPDATE_HOOK if( (ix==0 && pIdx->pNext==0) /* Condition 3 */ && pPk==pIdx /* Condition 2 */ && onError==OE_Replace /* Condition 1 */ @@ -116753,6 +118692,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; } +#endif /* ifndef SQLITE_ENABLE_PREUPDATE_HOOK */ /* Check to see if the new index entry will be unique */ sqlite3VdbeVerifyAbortable(v, onError); @@ -116866,11 +118806,21 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( /* If the IPK constraint is a REPLACE, run it last */ if( ipkTop ){ - sqlite3VdbeGoto(v, ipkTop+1); + sqlite3VdbeGoto(v, ipkTop); VdbeComment((v, "Do IPK REPLACE")); sqlite3VdbeJumpHere(v, ipkBottom); } + /* Generate the table record */ + if( HasRowid(pTab) ){ + int regRec = aRegIdx[ix]; + sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, pTab->nCol, regRec); + sqlite3SetMakeRecordP5(v, pTab); + if( !bAffinityDone ){ + sqlite3TableAffinity(v, pTab, 0); + } + } + *pbMayReplace = seenReplace; VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace)); } @@ -116920,10 +118870,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( Vdbe *v; /* Prepared statements under construction */ Index *pIdx; /* An index being inserted or updated */ u8 pik_flags; /* flag values passed to the btree insert */ - int regData; /* Content registers (after the rowid) */ - int regRec; /* Register holding assembled record for the table */ int i; /* Loop counter */ - u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */ assert( update_flags==0 || update_flags==OPFLAG_ISUPDATE @@ -116935,7 +118882,6 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( assert( pTab->pSelect==0 ); /* This table is not a VIEW */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( aRegIdx[i]==0 ) continue; - bAffinityDone = 1; if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); @@ -116947,10 +118893,13 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( pik_flags |= (update_flags & OPFLAG_SAVEPOSITION); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK if( update_flags==0 ){ - sqlite3VdbeAddOp4(v, OP_InsertInt, - iIdxCur+i, aRegIdx[i], 0, (char*)pTab, P4_TABLE + int r = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_Integer, 0, r); + sqlite3VdbeAddOp4(v, OP_Insert, + iIdxCur+i, aRegIdx[i], r, (char*)pTab, P4_TABLE ); sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP); + sqlite3ReleaseTempReg(pParse, r); } #endif } @@ -116960,13 +118909,6 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( sqlite3VdbeChangeP5(v, pik_flags); } if( !HasRowid(pTab) ) return; - regData = regNewData + 1; - regRec = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); - sqlite3SetMakeRecordP5(v, pTab); - if( !bAffinityDone ){ - sqlite3TableAffinity(v, pTab, 0); - } if( pParse->nested ){ pik_flags = 0; }else{ @@ -116979,7 +118921,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( if( useSeekResult ){ pik_flags |= OPFLAG_USESEEKRESULT; } - sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData); + sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, aRegIdx[i], regNewData); if( !pParse->nested ){ sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } @@ -117236,7 +119178,8 @@ static int xferOptimization( if( pSrc==0 ){ return 0; /* FROM clause does not contain a real table */ } - if( pSrc==pDest ){ + if( pSrc->tnum==pDest->tnum && pSrc->pSchema==pDest->pSchema ){ + testcase( pSrc!=pDest ); /* Possible due to bad sqlite_master.rootpage */ return 0; /* tab1 and tab2 may not be the same table */ } if( HasRowid(pDest)!=HasRowid(pSrc) ){ @@ -117297,6 +119240,13 @@ static int xferOptimization( if( pSrcIdx==0 ){ return 0; /* pDestIdx has no corresponding index in pSrc */ } + if( pSrcIdx->tnum==pDestIdx->tnum && pSrc->pSchema==pDest->pSchema + && sqlite3FaultSim(411)==SQLITE_OK ){ + /* The sqlite3FaultSim() call allows this corruption test to be + ** bypassed during testing, in order to exercise other corruption tests + ** further downstream. */ + return 0; /* Corrupt schema - two indexes on the same btree */ + } } #ifndef SQLITE_OMIT_CHECK if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ @@ -117374,7 +119324,7 @@ static int xferOptimization( sqlite3RowidConstraint(pParse, onError, pDest); sqlite3VdbeJumpHere(v, addr2); autoIncStep(pParse, regAutoinc, regRowid); - }else if( pDest->pIndex==0 ){ + }else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){ addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); }else{ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); @@ -117437,7 +119387,7 @@ static int xferOptimization( sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); } } - if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){ + if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ idxInsFlags |= OPFLAG_NCHANGE; } sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData); @@ -117512,7 +119462,7 @@ SQLITE_API int sqlite3_exec( sqlite3_mutex_enter(db->mutex); sqlite3Error(db, SQLITE_OK); while( rc==SQLITE_OK && zSql[0] ){ - int nCol; + int nCol = 0; char **azVals = 0; pStmt = 0; @@ -117526,9 +119476,7 @@ SQLITE_API int sqlite3_exec( zSql = zLeftover; continue; } - callbackIsInit = 0; - nCol = sqlite3_column_count(pStmt); while( 1 ){ int i; @@ -117539,6 +119487,7 @@ SQLITE_API int sqlite3_exec( (SQLITE_DONE==rc && !callbackIsInit && db->flags&SQLITE_NullCallback)) ){ if( !callbackIsInit ){ + nCol = sqlite3_column_count(pStmt); azCols = sqlite3DbMallocRaw(db, (2*nCol+1)*sizeof(const char*)); if( azCols==0 ){ goto exec_out; @@ -117941,12 +119890,18 @@ struct sqlite3_api_routines { int (*str_errcode)(sqlite3_str*); int (*str_length)(sqlite3_str*); char *(*str_value)(sqlite3_str*); + /* Version 3.25.0 and later */ int (*create_window_function)(sqlite3*,const char*,int,int,void*, void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInv)(sqlite3_context*,int,sqlite3_value**), void(*xDestroy)(void*)); + /* Version 3.26.0 and later */ + const char *(*normalized_sql)(sqlite3_stmt*); + /* Version 3.28.0 and later */ + int (*stmt_isexplain)(sqlite3_stmt*); + int (*value_frombind)(sqlite3_value*); }; /* @@ -118234,6 +120189,11 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_str_value sqlite3_api->str_value /* Version 3.25.0 and later */ #define sqlite3_create_window_function sqlite3_api->create_window_function +/* Version 3.26.0 and later */ +#define sqlite3_normalized_sql sqlite3_api->normalized_sql +/* Version 3.28.0 and later */ +#define sqlite3_stmt_isexplain sqlite3_api->isexplain +#define sqlite3_value_frombind sqlite3_api->frombind #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -118322,6 +120282,7 @@ typedef int (*sqlite3_loadext_entry)( # define sqlite3_declare_vtab 0 # define sqlite3_vtab_config 0 # define sqlite3_vtab_on_conflict 0 +# define sqlite3_vtab_collation 0 #endif #ifdef SQLITE_OMIT_SHARED_CACHE @@ -118689,7 +120650,16 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_str_length, sqlite3_str_value, /* Version 3.25.0 and later */ - sqlite3_create_window_function + sqlite3_create_window_function, + /* Version 3.26.0 and later */ +#ifdef SQLITE_ENABLE_NORMALIZE + sqlite3_normalized_sql, +#else + 0, +#endif + /* Version 3.28.0 and later */ + sqlite3_stmt_isexplain, + sqlite3_value_frombind }; /* @@ -118881,7 +120851,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){ if( onoff ){ db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc; }else{ - db->flags &= ~(SQLITE_LoadExtension|SQLITE_LoadExtFunc); + db->flags &= ~(u64)(SQLITE_LoadExtension|SQLITE_LoadExtFunc); } sqlite3_mutex_leave(db->mutex); return SQLITE_OK; @@ -119137,12 +121107,9 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ #define PragTyp_WAL_AUTOCHECKPOINT 38 #define PragTyp_WAL_CHECKPOINT 39 #define PragTyp_ACTIVATE_EXTENSIONS 40 -#define PragTyp_HEXKEY 41 -#define PragTyp_KEY 42 -#define PragTyp_REKEY 43 -#define PragTyp_LOCK_STATUS 44 -#define PragTyp_PARSER_TRACE 45 -#define PragTyp_STATS 46 +#define PragTyp_KEY 41 +#define PragTyp_LOCK_STATUS 42 +#define PragTyp_STATS 43 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ @@ -119159,58 +121126,57 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ ** result column is different from the name of the pragma */ static const char *const pragCName[] = { - /* 0 */ "cache_size", /* Used by: default_cache_size */ - /* 1 */ "cid", /* Used by: table_info */ - /* 2 */ "name", - /* 3 */ "type", - /* 4 */ "notnull", - /* 5 */ "dflt_value", - /* 6 */ "pk", - /* 7 */ "tbl", /* Used by: stats */ - /* 8 */ "idx", - /* 9 */ "wdth", - /* 10 */ "hght", - /* 11 */ "flgs", - /* 12 */ "seqno", /* Used by: index_info */ - /* 13 */ "cid", - /* 14 */ "name", + /* 0 */ "id", /* Used by: foreign_key_list */ + /* 1 */ "seq", + /* 2 */ "table", + /* 3 */ "from", + /* 4 */ "to", + /* 5 */ "on_update", + /* 6 */ "on_delete", + /* 7 */ "match", + /* 8 */ "cid", /* Used by: table_xinfo */ + /* 9 */ "name", + /* 10 */ "type", + /* 11 */ "notnull", + /* 12 */ "dflt_value", + /* 13 */ "pk", + /* 14 */ "hidden", + /* table_info reuses 8 */ /* 15 */ "seqno", /* Used by: index_xinfo */ /* 16 */ "cid", /* 17 */ "name", /* 18 */ "desc", /* 19 */ "coll", /* 20 */ "key", - /* 21 */ "seq", /* Used by: index_list */ - /* 22 */ "name", - /* 23 */ "unique", - /* 24 */ "origin", - /* 25 */ "partial", - /* 26 */ "seq", /* Used by: database_list */ + /* 21 */ "tbl", /* Used by: stats */ + /* 22 */ "idx", + /* 23 */ "wdth", + /* 24 */ "hght", + /* 25 */ "flgs", + /* 26 */ "seq", /* Used by: index_list */ /* 27 */ "name", - /* 28 */ "file", - /* 29 */ "name", /* Used by: function_list */ - /* 30 */ "builtin", - /* 31 */ "name", /* Used by: module_list pragma_list */ - /* 32 */ "seq", /* Used by: collation_list */ - /* 33 */ "name", - /* 34 */ "id", /* Used by: foreign_key_list */ - /* 35 */ "seq", - /* 36 */ "table", - /* 37 */ "from", - /* 38 */ "to", - /* 39 */ "on_update", - /* 40 */ "on_delete", - /* 41 */ "match", - /* 42 */ "table", /* Used by: foreign_key_check */ - /* 43 */ "rowid", - /* 44 */ "parent", - /* 45 */ "fkid", - /* 46 */ "busy", /* Used by: wal_checkpoint */ - /* 47 */ "log", - /* 48 */ "checkpointed", - /* 49 */ "timeout", /* Used by: busy_timeout */ - /* 50 */ "database", /* Used by: lock_status */ - /* 51 */ "status", + /* 28 */ "unique", + /* 29 */ "origin", + /* 30 */ "partial", + /* 31 */ "table", /* Used by: foreign_key_check */ + /* 32 */ "rowid", + /* 33 */ "parent", + /* 34 */ "fkid", + /* index_info reuses 15 */ + /* 35 */ "seq", /* Used by: database_list */ + /* 36 */ "name", + /* 37 */ "file", + /* 38 */ "busy", /* Used by: wal_checkpoint */ + /* 39 */ "log", + /* 40 */ "checkpointed", + /* 41 */ "name", /* Used by: function_list */ + /* 42 */ "builtin", + /* collation_list reuses 26 */ + /* 43 */ "database", /* Used by: lock_status */ + /* 44 */ "status", + /* 45 */ "cache_size", /* Used by: default_cache_size */ + /* module_list pragma_list reuses 9 */ + /* 46 */ "timeout", /* Used by: busy_timeout */ }; /* Definitions of all built-in pragmas */ @@ -119220,7 +121186,7 @@ typedef struct PragmaName { u8 mPragFlg; /* Zero or more PragFlg_XXX values */ u8 iPragCName; /* Start of column names in pragCName[] */ u8 nPragCName; /* Num of col names. 0 means use pragma name */ - u32 iArg; /* Extra argument */ + u64 iArg; /* Extra argument */ } PragmaName; static const PragmaName aPragmaName[] = { #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) @@ -119256,7 +121222,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 49, 1, + /* ColNames: */ 46, 1, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "cache_size", @@ -119272,11 +121238,13 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif +#if !defined(SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA) {/* zName: */ "case_sensitive_like", /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, /* ePragFlg: */ PragFlg_NoColumns, /* ColNames: */ 0, 0, /* iArg: */ 0 }, +#endif {/* zName: */ "cell_size_check", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, @@ -119293,7 +121261,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 32, 2, + /* ColNames: */ 26, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) @@ -119328,14 +121296,14 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, - /* ColNames: */ 26, 3, + /* ColNames: */ 35, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) {/* zName: */ "default_cache_size", /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, - /* ColNames: */ 0, 1, + /* ColNames: */ 45, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -119365,14 +121333,14 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "foreign_key_check", /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, - /* ColNames: */ 42, 4, + /* ColNames: */ 31, 4, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) {/* zName: */ "foreign_key_list", /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 34, 8, + /* ColNames: */ 0, 8, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -119408,21 +121376,21 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "function_list", /* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 29, 2, + /* ColNames: */ 41, 2, /* iArg: */ 0 }, #endif #endif #if defined(SQLITE_HAS_CODEC) {/* zName: */ "hexkey", - /* ePragTyp: */ PragTyp_HEXKEY, + /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, - /* iArg: */ 0 }, + /* iArg: */ 2 }, {/* zName: */ "hexrekey", - /* ePragTyp: */ PragTyp_HEXKEY, + /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, - /* iArg: */ 0 }, + /* iArg: */ 3 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_CHECK) @@ -119444,12 +121412,12 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 12, 3, + /* ColNames: */ 15, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 21, 5, + /* ColNames: */ 26, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, @@ -119506,7 +121474,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "lock_status", /* ePragTyp: */ PragTyp_LOCK_STATUS, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 50, 2, + /* ColNames: */ 43, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -119532,7 +121500,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "module_list", /* ePragTyp: */ PragTyp_MODULE_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 31, 1, + /* ColNames: */ 9, 1, /* iArg: */ 0 }, #endif #endif @@ -119554,18 +121522,20 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif -#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_PARSER_TRACE) +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if defined(SQLITE_DEBUG) {/* zName: */ "parser_trace", - /* ePragTyp: */ PragTyp_PARSER_TRACE, - /* ePragFlg: */ 0, + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, - /* iArg: */ 0 }, + /* iArg: */ SQLITE_ParserTrace }, +#endif #endif #if defined(SQLITE_INTROSPECTION_PRAGMAS) {/* zName: */ "pragma_list", /* ePragTyp: */ PragTyp_PRAGMA_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 31, 1, + /* ColNames: */ 9, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -119596,10 +121566,10 @@ static const PragmaName aPragmaName[] = { #endif #if defined(SQLITE_HAS_CODEC) {/* zName: */ "rekey", - /* ePragTyp: */ PragTyp_REKEY, + /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, - /* iArg: */ 0 }, + /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "reverse_unordered_selects", @@ -119652,7 +121622,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, - /* ColNames: */ 7, 5, + /* ColNames: */ 21, 5, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -119666,8 +121636,13 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "table_info", /* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 1, 6, + /* ColNames: */ 8, 6, /* iArg: */ 0 }, + {/* zName: */ "table_xinfo", + /* ePragTyp: */ PragTyp_TABLE_INFO, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 8, 7, + /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "temp_store", @@ -119680,6 +121655,18 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, +#endif +#if defined(SQLITE_HAS_CODEC) + {/* zName: */ "textkey", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 4 }, + {/* zName: */ "textrekey", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 5 }, #endif {/* zName: */ "threads", /* ePragTyp: */ PragTyp_THREADS, @@ -119731,7 +121718,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 46, 3, + /* ColNames: */ 38, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -119739,10 +121726,10 @@ static const PragmaName aPragmaName[] = { /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, - /* iArg: */ SQLITE_WriteSchema }, + /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError }, #endif }; -/* Number of pragmas: 61 on by default, 78 total. */ +/* Number of pragmas: 62 on by default, 81 total. */ /************** End of pragma.h **********************************************/ /************** Continuing where we left off in pragma.c *********************/ @@ -120361,6 +122348,11 @@ SQLITE_PRIVATE void sqlite3Pragma( ** then do a query */ eMode = PAGER_JOURNALMODE_QUERY; } + if( eMode==PAGER_JOURNALMODE_OFF && (db->flags & SQLITE_Defensive)!=0 ){ + /* Do not allow journal-mode "OFF" in defensive since the database + ** can become corrupted using ordinary SQL when the journal is off */ + eMode = PAGER_JOURNALMODE_QUERY; + } } if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){ /* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */ @@ -120533,7 +122525,7 @@ SQLITE_PRIVATE void sqlite3Pragma( if( sqlite3GetBoolean(zRight, size!=0) ){ db->flags |= SQLITE_CacheSpill; }else{ - db->flags &= ~SQLITE_CacheSpill; + db->flags &= ~(u64)SQLITE_CacheSpill; } setAllPagerFlags(db); } @@ -120754,7 +122746,7 @@ SQLITE_PRIVATE void sqlite3Pragma( setPragmaResultColumnNames(v, pPragma); returnSingleInt(v, (db->flags & pPragma->iArg)!=0 ); }else{ - int mask = pPragma->iArg; /* Mask of bits to set or clear. */ + u64 mask = pPragma->iArg; /* Mask of bits to set or clear. */ if( db->autoCommit==0 ){ /* Foreign key support may not be enabled or disabled while not ** in auto-commit mode. */ @@ -120803,15 +122795,17 @@ SQLITE_PRIVATE void sqlite3Pragma( Table *pTab; pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab ){ + int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int i, k; int nHidden = 0; Column *pCol; Index *pPk = sqlite3PrimaryKeyIndex(pTab); - pParse->nMem = 6; - sqlite3CodeVerifySchema(pParse, iDb); + pParse->nMem = 7; + sqlite3CodeVerifySchema(pParse, iTabDb); sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ - if( IsHiddenColumn(pCol) ){ + int isHidden = IsHiddenColumn(pCol); + if( isHidden && pPragma->iArg==0 ){ nHidden++; continue; } @@ -120823,13 +122817,14 @@ SQLITE_PRIVATE void sqlite3Pragma( for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){} } assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN ); - sqlite3VdbeMultiLoad(v, 1, "issisi", + sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi", i-nHidden, pCol->zName, sqlite3ColumnType(pCol,""), pCol->notNull ? 1 : 0, pCol->pDflt ? pCol->pDflt->u.zToken : 0, - k); + k, + isHidden); } } } @@ -120867,6 +122862,7 @@ SQLITE_PRIVATE void sqlite3Pragma( Table *pTab; pIdx = sqlite3FindIndex(db, zRight, zDb); if( pIdx ){ + int iIdxDb = sqlite3SchemaToIndex(db, pIdx->pSchema); int i; int mx; if( pPragma->iArg ){ @@ -120879,7 +122875,7 @@ SQLITE_PRIVATE void sqlite3Pragma( pParse->nMem = 3; } pTab = pIdx->pTable; - sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchema(pParse, iIdxDb); assert( pParse->nMem<=pPragma->nPragCName ); for(i=0; iaiColumn[i]; @@ -120903,8 +122899,9 @@ SQLITE_PRIVATE void sqlite3Pragma( int i; pTab = sqlite3FindTable(db, zRight, zDb); if( pTab ){ + int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); pParse->nMem = 5; - sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchema(pParse, iTabDb); for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ const char *azOrigin[] = { "c", "u", "pk" }; sqlite3VdbeMultiLoad(v, 1, "isisi", @@ -120951,6 +122948,7 @@ SQLITE_PRIVATE void sqlite3Pragma( pParse->nMem = 2; for(i=0; iu.pHash ){ + if( p->funcFlags & SQLITE_FUNC_INTERNAL ) continue; sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1); } } @@ -120992,9 +122990,10 @@ SQLITE_PRIVATE void sqlite3Pragma( if( pTab ){ pFK = pTab->pFKey; if( pFK ){ + int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int i = 0; pParse->nMem = 8; - sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchema(pParse, iTabDb); while(pFK){ int j; for(j=0; jnCol; j++){ @@ -121039,9 +123038,9 @@ SQLITE_PRIVATE void sqlite3Pragma( pParse->nMem += 4; regKey = ++pParse->nMem; regRow = ++pParse->nMem; - sqlite3CodeVerifySchema(pParse, iDb); k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); while( k ){ + int iTabDb; if( zRight ){ pTab = sqlite3LocateTable(pParse, 0, zRight, zDb); k = 0; @@ -121050,21 +123049,23 @@ SQLITE_PRIVATE void sqlite3Pragma( k = sqliteHashNext(k); } if( pTab==0 || pTab->pFKey==0 ) continue; - sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); + iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); + sqlite3CodeVerifySchema(pParse, iTabDb); + sqlite3TableLock(pParse, iTabDb, pTab->tnum, 0, pTab->zName); if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; - sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); + sqlite3OpenTable(pParse, 0, iTabDb, pTab, OP_OpenRead); sqlite3VdbeLoadString(v, regResult, pTab->zName); for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); if( pParent==0 ) continue; pIdx = 0; - sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName); + sqlite3TableLock(pParse, iTabDb, pParent->tnum, 0, pParent->zName); x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0); if( x==0 ){ if( pIdx==0 ){ - sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead); + sqlite3OpenTable(pParse, i, iTabDb, pParent, OP_OpenRead); }else{ - sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb); + sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iTabDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); } }else{ @@ -121084,7 +123085,7 @@ SQLITE_PRIVATE void sqlite3Pragma( x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols); assert( x==0 ); } - addrOk = sqlite3VdbeMakeLabel(v); + addrOk = sqlite3VdbeMakeLabel(pParse); /* Generate code to read the child key values into registers ** regRow..regRow+n. If any of the child key values are NULL, this @@ -121129,19 +123130,7 @@ SQLITE_PRIVATE void sqlite3Pragma( #endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ -#ifndef NDEBUG - case PragTyp_PARSER_TRACE: { - if( zRight ){ - if( sqlite3GetBoolean(zRight, 0) ){ - sqlite3ParserTrace(stdout, "parser: "); - }else{ - sqlite3ParserTrace(0, 0); - } - } - } - break; -#endif - +#ifndef SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA /* Reinstall the LIKE and GLOB functions. The variant of LIKE ** used will be case sensitive or not depending on the RHS. */ @@ -121151,6 +123140,7 @@ SQLITE_PRIVATE void sqlite3Pragma( } } break; +#endif /* SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA */ #ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX # define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100 @@ -121304,8 +123294,8 @@ SQLITE_PRIVATE void sqlite3Pragma( if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0); if( db->mallocFailed==0 ){ - int addrCkFault = sqlite3VdbeMakeLabel(v); - int addrCkOk = sqlite3VdbeMakeLabel(v); + int addrCkFault = sqlite3VdbeMakeLabel(pParse); + int addrCkOk = sqlite3VdbeMakeLabel(pParse); char *zErr; int k; pParse->iSelfTab = iDataCur + 1; @@ -121328,7 +123318,7 @@ SQLITE_PRIVATE void sqlite3Pragma( /* Validate index entries for the current row */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2, jmp3, jmp4, jmp5; - int ckUniq = sqlite3VdbeMakeLabel(v); + int ckUniq = sqlite3VdbeMakeLabel(pParse); if( pPk==pIdx ) continue; r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, pPrior, r1); @@ -121349,7 +123339,7 @@ SQLITE_PRIVATE void sqlite3Pragma( ** current key. The entry is unique if (1) any column is NULL ** or (2) the next entry has a different key */ if( IsUniqueIndex(pIdx) ){ - int uniqOk = sqlite3VdbeMakeLabel(v); + int uniqOk = sqlite3VdbeMakeLabel(pParse); int jmp6; int kk; for(kk=0; kknKeyCol; kk++){ @@ -121833,27 +123823,41 @@ SQLITE_PRIVATE void sqlite3Pragma( #endif #ifdef SQLITE_HAS_CODEC + /* Pragma iArg + ** ---------- ------ + ** key 0 + ** rekey 1 + ** hexkey 2 + ** hexrekey 3 + ** textkey 4 + ** textrekey 5 + */ case PragTyp_KEY: { - if( zRight ) sqlite3_key_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); - break; - } - case PragTyp_REKEY: { - if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); - break; - } - case PragTyp_HEXKEY: { if( zRight ){ - u8 iByte; - int i; - char zKey[40]; - for(i=0, iByte=0; iiArg==2 || pPragma->iArg==3 ){ + u8 iByte; + int i; + for(i=0, iByte=0; iiArg<4 ? sqlite3Strlen30(zRight) : -1; } - if( (zLeft[3] & 0xf)==0xb ){ - sqlite3_key_v2(db, zDb, zKey, i/2); + if( (pPragma->iArg & 1)==0 ){ + rc = sqlite3_key_v2(db, zDb, zKey, n); }else{ - sqlite3_rekey_v2(db, zDb, zKey, i/2); + rc = sqlite3_rekey_v2(db, zDb, zKey, n); + } + if( rc==SQLITE_OK && n!=0 ){ + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "ok", SQLITE_STATIC); + returnSingleText(v, "ok"); } } break; @@ -122180,7 +124184,8 @@ static const sqlite3_module pragmaVtabModule = { 0, /* xRename - rename the table */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; /* @@ -122250,6 +124255,19 @@ static void corruptSchema( } } +/* +** Check to see if any sibling index (another index on the same table) +** of pIndex has the same root page number, and if it does, return true. +** This would indicate a corrupt schema. +*/ +SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index *pIndex){ + Index *p; + for(p=pIndex->pTable->pIndex; p; p=p->pNext){ + if( p->tnum==pIndex->tnum && p!=pIndex ) return 1; + } + return 0; +} + /* ** This is the callback routine for the code that initializes the ** database. See sqlite3Init() below for additional information. @@ -122271,6 +124289,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char UNUSED_PARAMETER2(NotUsed, argc); assert( sqlite3_mutex_held(db->mutex) ); DbClearProperty(db, iDb, DB_Empty); + pData->nInitRow++; if( db->mallocFailed ){ corruptSchema(pData, argv[0], 0); return 1; @@ -122324,15 +124343,12 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char */ Index *pIndex; pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName); - if( pIndex==0 ){ - /* This can occur if there exists an index on a TEMP table which - ** has the same name as another index on a permanent index. Since - ** the permanent table is hidden by the TEMP table, we can also - ** safely ignore the index on the permanent table. - */ - /* Do Nothing */; - }else if( sqlite3GetInt32(argv[1], &pIndex->tnum)==0 ){ - corruptSchema(pData, argv[0], "invalid rootpage"); + if( pIndex==0 + || sqlite3GetInt32(argv[1],&pIndex->tnum)==0 + || pIndex->tnum<2 + || sqlite3IndexHasDuplicateRootPage(pIndex) + ){ + corruptSchema(pData, argv[0], pIndex?"invalid rootpage":"orphan index"); } } return 0; @@ -122382,6 +124398,7 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl initData.rc = SQLITE_OK; initData.pzErrMsg = pzErrMsg; initData.mInitFlags = mFlags; + initData.nInitRow = 0; sqlite3InitCallback(&initData, 3, (char **)azArg, 0); if( initData.rc ){ rc = initData.rc; @@ -122499,7 +124516,7 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl ** indices that the user might have created. */ if( iDb==0 && meta[BTREE_FILE_FORMAT-1]>=4 ){ - db->flags &= ~SQLITE_LegacyFileFmt; + db->flags &= ~(u64)SQLITE_LegacyFileFmt; } /* Read the schema information out of the schema tables @@ -122533,8 +124550,8 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl rc = SQLITE_NOMEM_BKPT; sqlite3ResetAllSchemasOfConnection(db); } - if( rc==SQLITE_OK || (db->flags&SQLITE_WriteSchema)){ - /* Black magic: If the SQLITE_WriteSchema flag is set, then consider + if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){ + /* Black magic: If the SQLITE_NoSchemaError flag is set, then consider ** the schema loaded, even if errors occurred. In this situation the ** current sqlite3_prepare() operation will fail, but the following one ** will attempt to compile the supplied statement against whatever subset @@ -122751,6 +124768,7 @@ static int sqlite3Prepare( sParse.disableLookaside++; db->lookaside.bDisable++; } + sParse.disableVtab = (prepFlags & SQLITE_PREPARE_NO_VTAB)!=0; /* Check to verify that it is possible to get a read lock on all ** database schemas. The inability to get a read lock indicates that @@ -122915,6 +124933,7 @@ static int sqlite3LockAndPrepare( return rc; } + /* ** Rerun the compilation of a statement after a schema change. ** @@ -123479,7 +125498,7 @@ static void addWhereTerm( ExprSetVVAProperty(pEq, EP_NoReduce); pEq->iRightJoinTable = (i16)pE2->iTable; } - *ppWhere = sqlite3ExprAnd(db, *ppWhere, pEq); + *ppWhere = sqlite3ExprAnd(pParse, *ppWhere, pEq); } /* @@ -123613,7 +125632,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ */ if( pRight->pOn ){ if( isOuter ) setJoinExpr(pRight->pOn, pRight->iCursor); - p->pWhere = sqlite3ExprAnd(pParse->db, p->pWhere, pRight->pOn); + p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->pOn); pRight->pOn = 0; } @@ -123755,7 +125774,7 @@ static void pushOntoSorter( } assert( pSelect->iOffset==0 || pSelect->iLimit!=0 ); iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit; - pSort->labelDone = sqlite3VdbeMakeLabel(v); + pSort->labelDone = sqlite3VdbeMakeLabel(pParse); sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData, SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0)); if( bSeq ){ @@ -123794,7 +125813,7 @@ static void pushOntoSorter( pKI->nAllField-pKI->nKeyField-1); addrJmp = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); - pSort->labelBkOut = sqlite3VdbeMakeLabel(v); + pSort->labelBkOut = sqlite3VdbeMakeLabel(pParse); pSort->regReturn = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor); @@ -123927,7 +125946,7 @@ static void selectExprDefer( struct ExprList_item *pItem = &pEList->a[i]; if( pItem->u.x.iOrderByCol==0 ){ Expr *pExpr = pItem->pExpr; - Table *pTab = pExpr->pTab; + Table *pTab = pExpr->y.pTab; if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && pTab && !IsVirtual(pTab) && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF) ){ @@ -123950,12 +125969,12 @@ static void selectExprDefer( Expr *pNew = sqlite3PExpr(pParse, TK_COLUMN, 0, 0); if( pNew ){ pNew->iTable = pExpr->iTable; - pNew->pTab = pExpr->pTab; + pNew->y.pTab = pExpr->y.pTab; pNew->iColumn = pPk ? pPk->aiColumn[k] : -1; pExtra = sqlite3ExprListAppend(pParse, pExtra, pNew); } } - pSort->aDefer[nDefer].pTab = pExpr->pTab; + pSort->aDefer[nDefer].pTab = pExpr->y.pTab; pSort->aDefer[nDefer].iCsr = pExpr->iTable; pSort->aDefer[nDefer].nKey = nKey; nDefer++; @@ -124541,7 +126560,7 @@ static void generateSortTail( ){ Vdbe *v = pParse->pVdbe; /* The prepared statement */ int addrBreak = pSort->labelDone; /* Jump here to exit loop */ - int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */ + int addrContinue = sqlite3VdbeMakeLabel(pParse);/* Jump here for next cycle */ int addr; /* Top of output loop. Jump for Next. */ int addrOnce = 0; int iTab; @@ -124581,7 +126600,12 @@ static void generateSortTail( regRow = pDest->iSdst; }else{ regRowid = sqlite3GetTempReg(pParse); - regRow = sqlite3GetTempRange(pParse, nColumn); + if( eDest==SRT_EphemTab || eDest==SRT_Table ){ + regRow = sqlite3GetTempReg(pParse); + nColumn = 0; + }else{ + regRow = sqlite3GetTempRange(pParse, nColumn); + } } nKey = pOrderBy->nExpr - pSort->nOBSat; if( pSort->sortFlags & SORTFLAG_UseSorter ){ @@ -124661,6 +126685,7 @@ static void generateSortTail( switch( eDest ){ case SRT_Table: case SRT_EphemTab: { + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq, regRow); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); @@ -124804,7 +126829,7 @@ static const char *columnTypeImpl( break; } - assert( pTab && pExpr->pTab==pTab ); + assert( pTab && pExpr->y.pTab==pTab ); if( pS ){ /* The "table" is actually a sub-select or a view in the FROM clause ** of the SELECT statement. Return the declaration type and origin @@ -124989,7 +127014,7 @@ static void generateColumnNames( assert( p!=0 ); assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ - assert( p->op!=TK_COLUMN || p->pTab!=0 ); /* Covering idx not yet coded */ + assert( p->op!=TK_COLUMN || p->y.pTab!=0 ); /* Covering idx not yet coded */ if( pEList->a[i].zName ){ /* An AS clause always takes first priority */ char *zName = pEList->a[i].zName; @@ -124997,7 +127022,7 @@ static void generateColumnNames( }else if( srcName && p->op==TK_COLUMN ){ char *zCol; int iCol = p->iColumn; - pTab = p->pTab; + pTab = p->y.pTab; assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iColnCol) ); @@ -125088,7 +127113,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( if( pColExpr->op==TK_COLUMN ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; - Table *pTab = pColExpr->pTab; + Table *pTab = pColExpr->y.pTab; assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid"; @@ -125201,22 +127226,19 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation( SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){ Table *pTab; sqlite3 *db = pParse->db; - int savedFlags; + u64 savedFlags; savedFlags = db->flags; - db->flags &= ~SQLITE_FullColNames; + db->flags &= ~(u64)SQLITE_FullColNames; db->flags |= SQLITE_ShortColNames; sqlite3SelectPrep(pParse, pSelect, 0); + db->flags = savedFlags; if( pParse->nErr ) return 0; while( pSelect->pPrior ) pSelect = pSelect->pPrior; - db->flags = savedFlags; pTab = sqlite3DbMallocZero(db, sizeof(Table) ); if( pTab==0 ){ return 0; } - /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside - ** is disabled */ - assert( db->lookaside.bDisable ); pTab->nTabRef = 1; pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); @@ -125442,11 +127464,18 @@ static void generateWithRecursiveQuery( Expr *pLimit; /* Saved LIMIT and OFFSET */ int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */ +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWin ){ + sqlite3ErrorMsg(pParse, "cannot use window functions in recursive queries"); + return; + } +#endif + /* Obtain authorization to do a recursive query */ if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return; /* Process the LIMIT and OFFSET clauses, if they exist */ - addrBreak = sqlite3VdbeMakeLabel(v); + addrBreak = sqlite3VdbeMakeLabel(pParse); p->nSelectRow = 320; /* 4 billion rows */ computeLimitRegisters(pParse, p, addrBreak); pLimit = p->pLimit; @@ -125516,7 +127545,7 @@ static void generateWithRecursiveQuery( sqlite3VdbeAddOp1(v, OP_Delete, iQueue); /* Output the single row in Current */ - addrCont = sqlite3VdbeMakeLabel(v); + addrCont = sqlite3VdbeMakeLabel(pParse); codeOffset(v, regOffset, addrCont); selectInnerLoop(pParse, p, iCurrent, 0, 0, pDest, addrCont, addrBreak); @@ -125651,6 +127680,7 @@ static int multiSelect( */ assert( p && p->pPrior ); /* Calling function guarantees this much */ assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION ); + assert( p->selFlags & SF_Compound ); db = pParse->db; pPrior = p->pPrior; dest = *pDest; @@ -125824,8 +127854,8 @@ static int multiSelect( if( dest.eDest!=priorOp ){ int iCont, iBreak, iStart; assert( p->pEList ); - iBreak = sqlite3VdbeMakeLabel(v); - iCont = sqlite3VdbeMakeLabel(v); + iBreak = sqlite3VdbeMakeLabel(pParse); + iCont = sqlite3VdbeMakeLabel(pParse); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); iStart = sqlite3VdbeCurrentAddr(v); @@ -125893,8 +127923,8 @@ static int multiSelect( ** tables. */ assert( p->pEList ); - iBreak = sqlite3VdbeMakeLabel(v); - iCont = sqlite3VdbeMakeLabel(v); + iBreak = sqlite3VdbeMakeLabel(pParse); + iCont = sqlite3VdbeMakeLabel(pParse); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); r1 = sqlite3GetTempReg(pParse); @@ -126024,7 +128054,7 @@ static int generateOutputSubroutine( int addr; addr = sqlite3VdbeCurrentAddr(v); - iContinue = sqlite3VdbeMakeLabel(v); + iContinue = sqlite3VdbeMakeLabel(pParse); /* Suppress duplicates for UNION, EXCEPT, and INTERSECT */ @@ -126261,8 +128291,8 @@ static int multiSelectOrderBy( db = pParse->db; v = pParse->pVdbe; assert( v!=0 ); /* Already thrown the error if VDBE alloc failed */ - labelEnd = sqlite3VdbeMakeLabel(v); - labelCmpr = sqlite3VdbeMakeLabel(v); + labelEnd = sqlite3VdbeMakeLabel(pParse); + labelCmpr = sqlite3VdbeMakeLabel(pParse); /* Patch up the ORDER BY clause @@ -126578,6 +128608,7 @@ static Expr *substExpr( ifNullRow.iTable = pSubst->iNewTable; pCopy = &ifNullRow; } + testcase( ExprHasProperty(pCopy, EP_Subquery) ); pNew = sqlite3ExprDup(db, pCopy, 0); if( pNew && pSubst->isLeftJoin ){ ExprSetProperty(pNew, EP_CanBeNull); @@ -127070,11 +129101,9 @@ static int flattenSubquery( jointype = pSubitem->fg.jointype; }else{ assert( pParent!=p ); /* 2nd and subsequent times through the loop */ - pSrc = pParent->pSrc = sqlite3SrcListAppend(db, 0, 0, 0); - if( pSrc==0 ){ - assert( db->mallocFailed ); - break; - } + pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); + if( pSrc==0 ) break; + pParent->pSrc = pSrc; } /* The subquery uses a single slot of the FROM clause of the outer @@ -127093,10 +129122,9 @@ static int flattenSubquery( ** for the two elements in the FROM clause of the subquery. */ if( nSubSrc>1 ){ - pParent->pSrc = pSrc = sqlite3SrcListEnlarge(db, pSrc, nSubSrc-1,iFrom+1); - if( db->mallocFailed ){ - break; - } + pSrc = sqlite3SrcListEnlarge(pParse, pSrc, nSubSrc-1,iFrom+1); + if( pSrc==0 ) break; + pParent->pSrc = pSrc; } /* Transfer the FROM clause terms from the subquery into the @@ -127142,11 +129170,12 @@ static int flattenSubquery( pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; } - pWhere = sqlite3ExprDup(db, pSub->pWhere, 0); + pWhere = pSub->pWhere; + pSub->pWhere = 0; if( isLeftJoin>0 ){ setJoinExpr(pWhere, iNewParent); } - pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere); + pParent->pWhere = sqlite3ExprAnd(pParse, pWhere, pParent->pWhere); if( db->mallocFailed==0 ){ SubstContext x; x.pParse = pParse; @@ -127157,10 +129186,10 @@ static int flattenSubquery( substSelect(&x, pParent, 0); } - /* The flattened query is distinct if either the inner or the - ** outer query is distinct. - */ - pParent->selFlags |= pSub->selFlags & SF_Distinct; + /* The flattened query is a compound if either the inner or the + ** outer query is a compound. */ + pParent->selFlags |= pSub->selFlags & SF_Compound; + assert( (pSub->selFlags & SF_Distinct)==0 ); /* restriction (17b) */ /* ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y; @@ -127191,7 +129220,7 @@ static int flattenSubquery( #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* -** A structure to keep track of all of the column values that fixed to +** A structure to keep track of all of the column values that are fixed to ** a known value due to WHERE clause constraints of the form COLUMN=VALUE. */ typedef struct WhereConst WhereConst; @@ -127203,13 +129232,28 @@ struct WhereConst { }; /* -** Add a new entry to the pConst object +** Add a new entry to the pConst object. Except, do not add duplicate +** pColumn entires. */ static void constInsert( - WhereConst *pConst, - Expr *pColumn, - Expr *pValue + WhereConst *pConst, /* The WhereConst into which we are inserting */ + Expr *pColumn, /* The COLUMN part of the constraint */ + Expr *pValue /* The VALUE part of the constraint */ ){ + int i; + assert( pColumn->op==TK_COLUMN ); + + /* 2018-10-25 ticket [cf5ed20f] + ** Make sure the same pColumn is not inserted more than once */ + for(i=0; inConst; i++){ + const Expr *pExpr = pConst->apExpr[i*2]; + assert( pExpr->op==TK_COLUMN ); + if( pExpr->iTable==pColumn->iTable + && pExpr->iColumn==pColumn->iColumn + ){ + return; /* Already present. Return without doing anything. */ + } + } pConst->nConst++; pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr, @@ -127466,9 +129510,9 @@ static int pushDownWhereTerms( x.pEList = pSubq->pEList; pNew = substExpr(&x, pNew); if( pSubq->selFlags & SF_Aggregate ){ - pSubq->pHaving = sqlite3ExprAnd(pParse->db, pSubq->pHaving, pNew); + pSubq->pHaving = sqlite3ExprAnd(pParse, pSubq->pHaving, pNew); }else{ - pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew); + pSubq->pWhere = sqlite3ExprAnd(pParse, pSubq->pWhere, pNew); } pSubq = pSubq->pPrior; } @@ -127894,7 +129938,7 @@ SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFr pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral; - return SQLITE_OK; + return pParse->nErr ? SQLITE_ERROR : SQLITE_OK; } /* @@ -127940,6 +129984,10 @@ static int selectExpander(Walker *pWalker, Select *p){ if( (selFlags & SF_Expanded)!=0 ){ return WRC_Prune; } + if( pWalker->eCode ){ + /* Renumber selId because it has been copied from a view */ + p->selId = ++pParse->nSelect; + } pTabList = p->pSrc; pEList = p->pEList; sqlite3WithPush(pParse, p->pWith, 0); @@ -127989,12 +130037,15 @@ static int selectExpander(Walker *pWalker, Select *p){ #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE) if( IsVirtual(pTab) || pTab->pSelect ){ i16 nCol; + u8 eCodeOrig = pWalker->eCode; if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); nCol = pTab->nCol; pTab->nCol = -1; + pWalker->eCode = 1; /* Turn on Select.selId renumbering */ sqlite3WalkSelect(pWalker, pFrom->pSelect); + pWalker->eCode = eCodeOrig; pTab->nCol = nCol; } #endif @@ -128244,6 +130295,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ } w.xSelectCallback = selectExpander; w.xSelectCallback2 = selectPopWith; + w.eCode = 0; sqlite3WalkSelect(&w, pSelect); } @@ -128403,7 +130455,7 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ ** ** If regAcc is non-zero and there are no min() or max() aggregates ** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator -** registers i register regAcc contains 0. The caller will take care +** registers if register regAcc contains 0. The caller will take care ** of setting and clearing regAcc. */ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){ @@ -128430,7 +130482,7 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){ regAgg = 0; } if( pF->iDistinct>=0 ){ - addrNext = sqlite3VdbeMakeLabel(v); + addrNext = sqlite3VdbeMakeLabel(pParse); testcase( nArg==0 ); /* Error condition */ testcase( nArg>1 ); /* Also an error */ codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg); @@ -128515,7 +130567,7 @@ static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ if( pNew ){ Expr *pWhere = pS->pWhere; SWAP(Expr, *pNew, *pExpr); - pNew = sqlite3ExprAnd(db, pWhere, pNew); + pNew = sqlite3ExprAnd(pWalker->pParse, pWhere, pNew); pS->pWhere = pNew; pWalker->eCode = 1; } @@ -128566,13 +130618,22 @@ static struct SrcList_item *isSelfJoinView( ){ struct SrcList_item *pItem; for(pItem = pTabList->a; pItempSelect==0 ) continue; if( pItem->fg.viaCoroutine ) continue; if( pItem->zName==0 ) continue; - if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue; + assert( pItem->pTab!=0 ); + assert( pThis->pTab!=0 ); + if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue; if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; - if( sqlite3ExprCompare(0, - pThis->pSelect->pWhere, pItem->pSelect->pWhere, -1) + pS1 = pItem->pSelect; + if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){ + /* The query flattener left two different CTE tables with identical + ** names in the same FROM clause. */ + continue; + } + if( sqlite3ExprCompare(0, pThis->pSelect->pWhere, pS1->pWhere, -1) + || sqlite3ExprCompare(0, pThis->pSelect->pHaving, pS1->pHaving, -1) ){ /* The view was modified by some other optimization such as ** pushDownWhereTerms() */ @@ -128598,7 +130659,8 @@ static struct SrcList_item *isSelfJoinView( ** * The subquery is a UNION ALL of two or more terms ** * The subquery does not have a LIMIT clause ** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries -** * The outer query is a simple count(*) +** * The outer query is a simple count(*) with no WHERE clause or other +** extraneous syntax. ** ** Return TRUE if the optimization is undertaken. */ @@ -128609,6 +130671,8 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ sqlite3 *db; if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */ if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ + if( p->pWhere ) return 0; + if( p->pGroupBy ) return 0; pExpr = p->pEList->a[0].pExpr; if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */ if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */ @@ -128835,6 +130899,7 @@ SQLITE_PRIVATE int sqlite3Select( } if( flattenSubquery(pParse, p, i, isAgg) ){ + if( pParse->nErr ) goto select_end; /* This subquery can be absorbed into its parent. */ i = -1; } @@ -128930,22 +130995,12 @@ SQLITE_PRIVATE int sqlite3Select( pSub = pItem->pSelect; if( pSub==0 ) continue; - /* Sometimes the code for a subquery will be generated more than - ** once, if the subquery is part of the WHERE clause in a LEFT JOIN, - ** for example. In that case, do not regenerate the code to manifest - ** a view or the co-routine to implement a view. The first instance - ** is sufficient, though the subroutine to manifest the view does need - ** to be invoked again. */ - if( pItem->addrFillSub ){ - if( pItem->fg.viaCoroutine==0 ){ - /* The subroutine that manifests the view might be a one-time routine, - ** or it might need to be rerun on each iteration because it - ** encodes a correlated subquery. */ - testcase( sqlite3VdbeGetOp(v, pItem->addrFillSub)->opcode==OP_Once ); - sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub); - } - continue; - } + /* The code for a subquery should only be generated once, though it is + ** technically harmless for it to be generated multiple times. The + ** following assert() will detect if something changes to cause + ** the same subquery to be coded multiple times, as a signal to the + ** developers to try to optimize the situation. */ + assert( pItem->addrFillSub==0 ); /* Increment Parse.nHeight by the height of the largest expression ** tree referred to by this, the parent select. The child select @@ -129133,7 +131188,7 @@ SQLITE_PRIVATE int sqlite3Select( /* Set the limiter. */ - iEnd = sqlite3VdbeMakeLabel(v); + iEnd = sqlite3VdbeMakeLabel(pParse); if( (p->selFlags & SF_FixedLimit)==0 ){ p->nSelectRow = 320; /* 4 billion rows */ } @@ -129200,9 +131255,9 @@ SQLITE_PRIVATE int sqlite3Select( assert( p->pEList==pEList ); #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ - int addrGosub = sqlite3VdbeMakeLabel(v); - int iCont = sqlite3VdbeMakeLabel(v); - int iBreak = sqlite3VdbeMakeLabel(v); + int addrGosub = sqlite3VdbeMakeLabel(pParse); + int iCont = sqlite3VdbeMakeLabel(pParse); + int iBreak = sqlite3VdbeMakeLabel(pParse); int regGosub = ++pParse->nMem; sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub); @@ -129277,7 +131332,7 @@ SQLITE_PRIVATE int sqlite3Select( } /* Create a label to jump to when we want to abort the query */ - addrEnd = sqlite3VdbeMakeLabel(v); + addrEnd = sqlite3VdbeMakeLabel(pParse); /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the @@ -129366,9 +131421,9 @@ SQLITE_PRIVATE int sqlite3Select( iUseFlag = ++pParse->nMem; iAbortFlag = ++pParse->nMem; regOutputRow = ++pParse->nMem; - addrOutputRow = sqlite3VdbeMakeLabel(v); + addrOutputRow = sqlite3VdbeMakeLabel(pParse); regReset = ++pParse->nMem; - addrReset = sqlite3VdbeMakeLabel(v); + addrReset = sqlite3VdbeMakeLabel(pParse); iAMem = pParse->nMem + 1; pParse->nMem += pGroupBy->nExpr; iBMem = pParse->nMem + 1; @@ -130655,7 +132710,7 @@ static SrcList *targetSrcList( int iDb; /* Index of the database to use */ SrcList *pSrc; /* SrcList to be returned */ - pSrc = sqlite3SrcListAppend(db, 0, 0, 0); + pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pSrc ){ assert( pSrc->nSrc>0 ); pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget); @@ -130840,6 +132895,7 @@ static TriggerPrg *codeRowTrigger( pSubParse->zAuthContext = pTrigger->zName; pSubParse->eTriggerOp = pTrigger->op; pSubParse->nQueryLoop = pParse->nQueryLoop; + pSubParse->disableVtab = pParse->disableVtab; v = sqlite3GetVdbe(pSubParse); if( v ){ @@ -130867,7 +132923,7 @@ static TriggerPrg *codeRowTrigger( if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) && db->mallocFailed==0 ){ - iEndTrigger = sqlite3VdbeMakeLabel(v); + iEndTrigger = sqlite3VdbeMakeLabel(pSubParse); sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL); } sqlite3ExprDelete(db, pWhen); @@ -131191,6 +133247,57 @@ SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){ #endif } +/* +** Check to see if column iCol of index pIdx references any of the +** columns defined by aXRef and chngRowid. Return true if it does +** and false if not. This is an optimization. False-positives are a +** performance degradation, but false-negatives can result in a corrupt +** index and incorrect answers. +** +** aXRef[j] will be non-negative if column j of the original table is +** being updated. chngRowid will be true if the rowid of the table is +** being updated. +*/ +static int indexColumnIsBeingUpdated( + Index *pIdx, /* The index to check */ + int iCol, /* Which column of the index to check */ + int *aXRef, /* aXRef[j]>=0 if column j is being updated */ + int chngRowid /* true if the rowid is being updated */ +){ + i16 iIdxCol = pIdx->aiColumn[iCol]; + assert( iIdxCol!=XN_ROWID ); /* Cannot index rowid */ + if( iIdxCol>=0 ){ + return aXRef[iIdxCol]>=0; + } + assert( iIdxCol==XN_EXPR ); + assert( pIdx->aColExpr!=0 ); + assert( pIdx->aColExpr->a[iCol].pExpr!=0 ); + return sqlite3ExprReferencesUpdatedColumn(pIdx->aColExpr->a[iCol].pExpr, + aXRef,chngRowid); +} + +/* +** Check to see if index pIdx is a partial index whose conditional +** expression might change values due to an UPDATE. Return true if +** the index is subject to change and false if the index is guaranteed +** to be unchanged. This is an optimization. False-positives are a +** performance degradation, but false-negatives can result in a corrupt +** index and incorrect answers. +** +** aXRef[j] will be non-negative if column j of the original table is +** being updated. chngRowid will be true if the rowid of the table is +** being updated. +*/ +static int indexWhereClauseMightChange( + Index *pIdx, /* The index to check */ + int *aXRef, /* aXRef[j]>=0 if column j is being updated */ + int chngRowid /* true if the rowid is being updated */ +){ + if( pIdx->pPartIdxWhere==0 ) return 0; + return sqlite3ExprReferencesUpdatedColumn(pIdx->pPartIdxWhere, + aXRef, chngRowid); +} + /* ** Process an UPDATE statement. ** @@ -131216,11 +133323,12 @@ SQLITE_PRIVATE void sqlite3Update( Index *pIdx; /* For looping over indices */ Index *pPk; /* The PRIMARY KEY index for WITHOUT ROWID tables */ int nIdx; /* Number of indices that need updating */ + int nAllIdx; /* Total number of indexes */ int iBaseCur; /* Base cursor number */ int iDataCur; /* Cursor for the canonical data btree */ int iIdxCur; /* Cursor for the first index */ sqlite3 *db; /* The database structure */ - int *aRegIdx = 0; /* First register in array assigned to each index */ + int *aRegIdx = 0; /* Registers for to each index and the main table */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ @@ -131334,10 +133442,10 @@ SQLITE_PRIVATE void sqlite3Update( /* Allocate space for aXRef[], aRegIdx[], and aToOpen[]. ** Initialize aXRef[] and aToOpen[] to their default values. */ - aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 ); + aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx+1) + nIdx+2 ); if( aXRef==0 ) goto update_cleanup; aRegIdx = aXRef+pTab->nCol; - aToOpen = (u8*)(aRegIdx+nIdx); + aToOpen = (u8*)(aRegIdx+nIdx+1); memset(aToOpen, 1, nIdx+1); aToOpen[nIdx+1] = 0; for(i=0; inCol; i++) aXRef[i] = -1; @@ -131414,33 +133522,32 @@ SQLITE_PRIVATE void sqlite3Update( /* There is one entry in the aRegIdx[] array for each index on the table ** being updated. Fill in aRegIdx[] with a register number that will hold ** the key for accessing each index. - ** - ** FIXME: Be smarter about omitting indexes that use expressions. */ - for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + if( onError==OE_Replace ) bReplace = 1; + for(nAllIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nAllIdx++){ int reg; - if( chngKey || hasFK>1 || pIdx->pPartIdxWhere || pIdx==pPk ){ + if( chngKey || hasFK>1 || pIdx==pPk + || indexWhereClauseMightChange(pIdx,aXRef,chngRowid) + ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; }else{ reg = 0; for(i=0; inKeyCol; i++){ - i16 iIdxCol = pIdx->aiColumn[i]; - if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){ + if( indexColumnIsBeingUpdated(pIdx, i, aXRef, chngRowid) ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; - if( (onError==OE_Replace) - || (onError==OE_Default && pIdx->onError==OE_Replace) - ){ + if( onError==OE_Default && pIdx->onError==OE_Replace ){ bReplace = 1; } break; } } } - if( reg==0 ) aToOpen[j+1] = 0; - aRegIdx[j] = reg; + if( reg==0 ) aToOpen[nAllIdx+1] = 0; + aRegIdx[nAllIdx] = reg; } + aRegIdx[nAllIdx] = ++pParse->nMem; /* Register storing the table record */ if( bReplace ){ /* If REPLACE conflict resolution might be invoked, open cursors on all ** indexes in case they are needed to delete records. */ @@ -131455,7 +133562,13 @@ SQLITE_PRIVATE void sqlite3Update( /* Allocate required registers. */ if( !IsVirtual(pTab) ){ - regRowSet = ++pParse->nMem; + /* For now, regRowSet and aRegIdx[nAllIdx] share the same register. + ** If regRowSet turns out to be needed, then aRegIdx[nAllIdx] will be + ** reallocated. aRegIdx[nAllIdx] is the register in which the main + ** table record is written. regRowSet holds the RowSet for the + ** two-pass update algorithm. */ + assert( aRegIdx[nAllIdx]==pParse->nMem ); + regRowSet = aRegIdx[nAllIdx]; regOldRowid = regNewRowid = ++pParse->nMem; if( chngPk || pTrigger || hasFK ){ regOld = pParse->nMem + 1; @@ -131503,7 +133616,7 @@ SQLITE_PRIVATE void sqlite3Update( #endif /* Jump to labelBreak to abandon further processing of this UPDATE */ - labelContinue = labelBreak = sqlite3VdbeMakeLabel(v); + labelContinue = labelBreak = sqlite3VdbeMakeLabel(pParse); /* Not an UPSERT. Normal processing. Begin by ** initialize the count of updated rows */ @@ -131585,6 +133698,8 @@ SQLITE_PRIVATE void sqlite3Update( ** leave it in register regOldRowid. */ sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); if( eOnePass==ONEPASS_OFF ){ + /* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */ + aRegIdx[nAllIdx] = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid); } }else{ @@ -131638,13 +133753,13 @@ SQLITE_PRIVATE void sqlite3Update( VdbeCoverage(v); } if( eOnePass!=ONEPASS_SINGLE ){ - labelContinue = sqlite3VdbeMakeLabel(v); + labelContinue = sqlite3VdbeMakeLabel(pParse); } sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); VdbeCoverageIf(v, pPk==0); VdbeCoverageIf(v, pPk!=0); }else if( pPk ){ - labelContinue = sqlite3VdbeMakeLabel(v); + labelContinue = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0); @@ -131975,7 +134090,7 @@ static void updateVirtualTable( sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); }else{ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); - sqlite3VdbeChangeP5(v, 1); /* Enable sqlite3_vtab_nochange() */ + sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* Enable sqlite3_vtab_nochange() */ } } if( HasRowid(pTab) ){ @@ -132412,16 +134527,17 @@ static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){ ** transient would cause the database file to appear to be deleted ** following reboot. */ -SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm){ +SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){ Vdbe *v = sqlite3GetVdbe(pParse); int iDb = 0; - if( v==0 ) return; + if( v==0 ) goto build_vacuum_end; + if( pParse->nErr ) goto build_vacuum_end; if( pNm ){ #ifndef SQLITE_BUG_COMPATIBLE_20160819 /* Default behavior: Report an error if the argument to VACUUM is ** not recognized */ iDb = sqlite3TwoPartName(pParse, pNm, pNm, &pNm); - if( iDb<0 ) return; + if( iDb<0 ) goto build_vacuum_end; #else /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments ** to VACUUM are silently ignored. This is a back-out of a bug fix that @@ -132433,37 +134549,63 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm){ #endif } if( iDb!=1 ){ - sqlite3VdbeAddOp1(v, OP_Vacuum, iDb); + int iIntoReg = 0; + if( pInto && sqlite3ResolveSelfReference(pParse,0,0,pInto,0)==0 ){ + iIntoReg = ++pParse->nMem; + sqlite3ExprCode(pParse, pInto, iIntoReg); + } + sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg); sqlite3VdbeUsesBtree(v, iDb); } +build_vacuum_end: + sqlite3ExprDelete(pParse->db, pInto); return; } /* ** This routine implements the OP_Vacuum opcode of the VDBE. */ -SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ +SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( + char **pzErrMsg, /* Write error message here */ + sqlite3 *db, /* Database connection */ + int iDb, /* Which attached DB to vacuum */ + sqlite3_value *pOut /* Write results here, if not NULL. VACUUM INTO */ +){ int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ Btree *pTemp; /* The temporary database we vacuum into */ - u16 saved_mDbFlags; /* Saved value of db->mDbFlags */ - u32 saved_flags; /* Saved value of db->flags */ + u32 saved_mDbFlags; /* Saved value of db->mDbFlags */ + u64 saved_flags; /* Saved value of db->flags */ int saved_nChange; /* Saved value of db->nChange */ int saved_nTotalChange; /* Saved value of db->nTotalChange */ + u32 saved_openFlags; /* Saved value of db->openFlags */ u8 saved_mTrace; /* Saved trace settings */ Db *pDb = 0; /* Database to detach at end of vacuum */ int isMemDb; /* True if vacuuming a :memory: database */ int nRes; /* Bytes of reserved space at the end of each page */ int nDb; /* Number of attached databases */ const char *zDbMain; /* Schema name of database to vacuum */ + const char *zOut; /* Name of output file */ if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); - return SQLITE_ERROR; + return SQLITE_ERROR; /* IMP: R-12218-18073 */ } if( db->nVdbeActive>1 ){ sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); - return SQLITE_ERROR; + return SQLITE_ERROR; /* IMP: R-15610-35227 */ + } + saved_openFlags = db->openFlags; + if( pOut ){ + if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){ + sqlite3SetString(pzErrMsg, db, "non-text filename"); + return SQLITE_ERROR; + } + zOut = (const char*)sqlite3_value_text(pOut); + db->openFlags &= ~SQLITE_OPEN_READONLY; + db->openFlags |= SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE; + }else{ + zOut = ""; } /* Save the current value of the database flags so that it can be @@ -132476,7 +134618,8 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ saved_mTrace = db->mTrace; db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum; - db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows); + db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder + | SQLITE_Defensive | SQLITE_CountRows); db->mTrace = 0; zDbMain = db->aDb[iDb].zDbSName; @@ -132498,19 +134641,23 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ ** to write the journal header file. */ nDb = db->nDb; - rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db"); + rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut); + db->openFlags = saved_openFlags; if( rc!=SQLITE_OK ) goto end_of_vacuum; assert( (db->nDb-1)==nDb ); pDb = &db->aDb[nDb]; assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); pTemp = pDb->pBt; - - /* The call to execSql() to attach the temp database has left the file - ** locked (as there was more than one active statement when the transaction - ** to read the schema was concluded. Unlock it here so that this doesn't - ** cause problems for the call to BtreeSetPageSize() below. */ - sqlite3BtreeCommit(pTemp); - + if( pOut ){ + sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp)); + i64 sz = 0; + if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){ + rc = SQLITE_ERROR; + sqlite3SetString(pzErrMsg, db, "output file already exists"); + goto end_of_vacuum; + } + db->mDbFlags |= DBFLAG_VacuumInto; + } nRes = sqlite3BtreeGetOptimalReserve(pMain); /* A VACUUM cannot change the pagesize of an encrypted database. */ @@ -132534,7 +134681,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ */ rc = execSql(db, pzErrMsg, "BEGIN"); if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = sqlite3BtreeBeginTrans(pMain, 2, 0); + rc = sqlite3BtreeBeginTrans(pMain, pOut==0 ? 2 : 0, 0); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Do not attempt to change the page size for a WAL database */ @@ -132629,7 +134776,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ }; assert( 1==sqlite3BtreeIsInTrans(pTemp) ); - assert( 1==sqlite3BtreeIsInTrans(pMain) ); + assert( pOut!=0 || 1==sqlite3BtreeIsInTrans(pMain) ); /* Copy Btree meta values */ for(i=0; iflags */ @@ -132992,9 +135145,13 @@ SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){ ** string will be freed automatically when the table is ** deleted. */ -static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){ - int nBytes = sizeof(char *)*(2+pTable->nModuleArg); +static void addModuleArgument(Parse *pParse, Table *pTable, char *zArg){ + sqlite3_int64 nBytes = sizeof(char *)*(2+pTable->nModuleArg); char **azModuleArg; + sqlite3 *db = pParse->db; + if( pTable->nModuleArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){ + sqlite3ErrorMsg(pParse, "too many columns on %s", pTable->zName); + } azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes); if( azModuleArg==0 ){ sqlite3DbFree(db, zArg); @@ -133018,7 +135175,6 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( Token *pModuleName, /* Name of the module for the virtual table */ int ifNotExists /* No error if the table already exists */ ){ - int iDb; /* The database the table is being created in */ Table *pTable; /* The new virtual table */ sqlite3 *db; /* Database connection */ @@ -133028,13 +135184,11 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( assert( 0==pTable->pIndex ); db = pParse->db; - iDb = sqlite3SchemaToIndex(db, pTable->pSchema); - assert( iDb>=0 ); assert( pTable->nModuleArg==0 ); - addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); - addModuleArgument(db, pTable, 0); - addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); + addModuleArgument(pParse, pTable, sqlite3NameFromToken(db, pModuleName)); + addModuleArgument(pParse, pTable, 0); + addModuleArgument(pParse, pTable, sqlite3DbStrDup(db, pTable->zName)); assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0) || (pParse->sNameToken.z==pName1->z && pName2->z==0) ); @@ -133049,6 +135203,8 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( ** The second call, to obtain permission to create the table, is made now. */ if( pTable->azModuleArg ){ + int iDb = sqlite3SchemaToIndex(db, pTable->pSchema); + assert( iDb>=0 ); /* The database the table is being created in */ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName); } @@ -133065,7 +135221,7 @@ static void addArgumentToVtab(Parse *pParse){ const char *z = (const char*)pParse->sArg.z; int n = pParse->sArg.n; sqlite3 *db = pParse->db; - addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); + addModuleArgument(pParse, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); } } @@ -133354,7 +135510,8 @@ static int growVTrans(sqlite3 *db){ /* Grow the sqlite3.aVTrans array if required */ if( (db->nVTrans%ARRAY_INCR)==0 ){ VTable **aVTrans; - int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR); + sqlite3_int64 nBytes = sizeof(sqlite3_vtab*)* + ((sqlite3_int64)db->nVTrans + ARRAY_INCR); aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes); if( !aVTrans ){ return SQLITE_NOMEM_BKPT; @@ -133527,6 +135684,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab p = vtabDisconnectAll(db, pTab); xDestroy = p->pMod->pModule->xDestroy; assert( xDestroy!=0 ); /* Checked before the virtual table is created */ + pTab->nTabRef++; rc = xDestroy(p->pVtab); /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */ if( rc==SQLITE_OK ){ @@ -133535,6 +135693,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab pTab->pVTable = 0; sqlite3VtabUnlock(p); } + sqlite3DeleteTable(db, pTab); } return rc; @@ -133692,6 +135851,7 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ const sqlite3_module *pMod = pVTab->pMod->pModule; if( pVTab->pVtab && pMod->iVersion>=2 ){ int (*xMethod)(sqlite3_vtab *, int); + sqlite3VtabLock(pVTab); switch( op ){ case SAVEPOINT_BEGIN: xMethod = pMod->xSavepoint; @@ -133707,6 +135867,7 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ if( xMethod && pVTab->iSavepoint>iSavepoint ){ rc = xMethod(pVTab->pVtab, iSavepoint); } + sqlite3VtabUnlock(pVTab); } } } @@ -133743,7 +135904,7 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction( /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; - pTab = pExpr->pTab; + pTab = pExpr->y.pTab; if( pTab==0 ) return pDef; if( !IsVirtual(pTab) ) return pDef; pVtab = sqlite3GetVTable(db, pTab)->pVtab; @@ -133848,9 +136009,9 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ pTab->pSchema = db->aDb[0].pSchema; assert( pTab->nModuleArg==0 ); pTab->iPKey = -1; - addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); - addModuleArgument(db, pTab, 0); - addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); + addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); + addModuleArgument(pParse, pTab, 0); + addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr); if( rc ){ sqlite3ErrorMsg(pParse, "%s", zErr); @@ -133975,6 +136136,8 @@ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){ ** planner logic in "where.c". These definitions are broken out into ** a separate source file for easier editing. */ +#ifndef SQLITE_WHEREINT_H +#define SQLITE_WHEREINT_H /* ** Trace output macros @@ -134363,12 +136526,33 @@ struct WhereLoopBuilder { int nRecValid; /* Number of valid fields currently in pRec */ #endif unsigned int bldFlags; /* SQLITE_BLDF_* flags */ + unsigned int iPlanLimit; /* Search limiter */ }; /* Allowed values for WhereLoopBuider.bldFlags */ #define SQLITE_BLDF_INDEXED 0x0001 /* An index is used */ #define SQLITE_BLDF_UNIQUE 0x0002 /* All keys of a UNIQUE index used */ +/* The WhereLoopBuilder.iPlanLimit is used to limit the number of +** index+constraint combinations the query planner will consider for a +** particular query. If this parameter is unlimited, then certain +** pathological queries can spend excess time in the sqlite3WhereBegin() +** routine. The limit is high enough that is should not impact real-world +** queries. +** +** SQLITE_QUERY_PLANNER_LIMIT is the baseline limit. The limit is +** increased by SQLITE_QUERY_PLANNER_LIMIT_INCR before each term of the FROM +** clause is processed, so that every table in a join is guaranteed to be +** able to propose a some index+constraint combinations even if the initial +** baseline limit was exhausted by prior tables of the join. +*/ +#ifndef SQLITE_QUERY_PLANNER_LIMIT +# define SQLITE_QUERY_PLANNER_LIMIT 20000 +#endif +#ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR +# define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000 +#endif + /* ** The WHERE clause processing routine has two halves. The ** first part does the start of the WHERE loop and the second @@ -134447,8 +136631,11 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( # define sqlite3WhereAddScanStatus(a, b, c, d) ((void)d) #endif SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( + Parse *pParse, /* Parsing context */ + Vdbe *v, /* Prepared statement under construction */ WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ + WhereLevel *pLevel, /* The current level pointer */ Bitmask notReady /* Which tables are currently available */ ); @@ -134522,6 +136709,8 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC #define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */ #define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */ +#endif /* !defined(SQLITE_WHEREINT_H) */ + /************** End of whereInt.h ********************************************/ /************** Continuing where we left off in wherecode.c ******************/ @@ -134718,6 +136907,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( } #endif zMsg = sqlite3StrAccumFinish(&str); + sqlite3ExplainBreakpoint("",zMsg); ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), pParse->addrExplain, 0, zMsg,P4_DYNAMIC); } @@ -134930,7 +137120,7 @@ static Expr *removeUnindexableInClauseTerms( for(i=iEq; inLTerm; i++){ if( pLoop->aLTerm[i]->pExpr==pX ){ int iField = pLoop->aLTerm[i]->iField - 1; - assert( pOrigRhs->a[iField].pExpr!=0 ); + if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */ pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr); pOrigRhs->a[iField].pExpr = 0; assert( pOrigLhs->a[iField].pExpr!=0 ); @@ -135043,16 +137233,17 @@ static int codeEqualityTerm( if( pLoop->aLTerm[i]->pExpr==pX ) nEq++; } + iTab = 0; if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){ - eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0); + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab); }else{ sqlite3 *db = pParse->db; pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX); if( !db->mallocFailed ){ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq); - eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap); - pTerm->pExpr->iTable = pX->iTable; + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab); + pTerm->pExpr->iTable = iTab; } sqlite3ExprDelete(db, pX); pX = pTerm->pExpr; @@ -135062,7 +137253,6 @@ static int codeEqualityTerm( testcase( bRev ); bRev = !bRev; } - iTab = pX->iTable; sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); VdbeCoverageIf(v, bRev); VdbeCoverageIf(v, !bRev); @@ -135070,7 +137260,7 @@ static int codeEqualityTerm( pLoop->wsFlags |= WHERE_IN_ABLE; if( pLevel->u.in.nIn==0 ){ - pLevel->addrNxt = sqlite3VdbeMakeLabel(v); + pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse); } i = pLevel->u.in.nIn; @@ -135086,7 +137276,6 @@ static int codeEqualityTerm( if( pLoop->aLTerm[i]->pExpr==pX ){ int iOut = iReg + i - iEq; if( eType==IN_INDEX_ROWID ){ - testcase( nEq>1 ); /* Happens with a UNIQUE index on ROWID */ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut); }else{ int iCol = aiMap ? aiMap[iMap++] : 0; @@ -135504,7 +137693,7 @@ static void codeCursorHint( } /* If we survive all prior tests, that means this term is worth hinting */ - pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); + pExpr = sqlite3ExprAnd(pParse, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); } if( pExpr!=0 ){ sWalker.xExprCallback = codeCursorHintFixExpr; @@ -135581,7 +137770,9 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){ #ifndef SQLITE_OMIT_SUBQUERY if( (p->flags & EP_xIsSelect) ){ Vdbe *v = pParse->pVdbe; - int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0); + int iSelect; + assert( p->op==TK_SELECT ); + iSelect = sqlite3CodeSubselect(pParse, p); sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1); }else #endif @@ -135622,7 +137813,7 @@ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ pExpr->op = TK_COLUMN; pExpr->iTable = pX->iIdxCur; pExpr->iColumn = pX->iIdxCol; - pExpr->pTab = 0; + pExpr->y.pTab = 0; return WRC_Prune; }else{ return WRC_Continue; @@ -135662,27 +137853,54 @@ static void whereIndexExprTrans( } } +/* +** The pTruth expression is always true because it is the WHERE clause +** a partial index that is driving a query loop. Look through all of the +** WHERE clause terms on the query, and if any of those terms must be +** true because pTruth is true, then mark those WHERE clause terms as +** coded. +*/ +static void whereApplyPartialIndexConstraints( + Expr *pTruth, + int iTabCur, + WhereClause *pWC +){ + int i; + WhereTerm *pTerm; + while( pTruth->op==TK_AND ){ + whereApplyPartialIndexConstraints(pTruth->pLeft, iTabCur, pWC); + pTruth = pTruth->pRight; + } + for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){ + Expr *pExpr; + if( pTerm->wtFlags & TERM_CODED ) continue; + pExpr = pTerm->pExpr; + if( sqlite3ExprCompare(0, pExpr, pTruth, iTabCur)==0 ){ + pTerm->wtFlags |= TERM_CODED; + } + } +} + /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( + Parse *pParse, /* Parsing context */ + Vdbe *v, /* Prepared statement under construction */ WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ + WhereLevel *pLevel, /* The current level pointer */ Bitmask notReady /* Which tables are currently available */ ){ int j, k; /* Loop counters */ int iCur; /* The VDBE cursor for the table */ int addrNxt; /* Where to jump to continue with the next IN case */ - int omitTable; /* True if we use the index only */ int bRev; /* True if we need to scan in reverse order */ - WhereLevel *pLevel; /* The where level to be coded */ WhereLoop *pLoop; /* The WhereLoop object being coded */ WhereClause *pWC; /* Decomposition of the entire WHERE clause */ WhereTerm *pTerm; /* A WHERE clause term */ - Parse *pParse; /* Parsing context */ sqlite3 *db; /* Database connection */ - Vdbe *v; /* The prepared stmt under constructions */ struct SrcList_item *pTabItem; /* FROM clause term being coded */ int addrBrk; /* Jump here to break out of the loop */ int addrHalt; /* addrBrk for the outermost loop */ @@ -135692,18 +137910,13 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( Index *pIdx = 0; /* Index used by loop (if any) */ int iLoop; /* Iteration of constraint generator loop */ - pParse = pWInfo->pParse; - v = pParse->pVdbe; pWC = &pWInfo->sWC; db = pParse->db; - pLevel = &pWInfo->a[iLevel]; pLoop = pLevel->pWLoop; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; - omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 - && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0; VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); /* Create labels for the "break" and "continue" instructions @@ -135716,8 +137929,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** there are no IN operators in the constraints, the "addrNxt" label ** is the same as "addrBrk". */ - addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(v); - addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(v); + addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse); + addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(pParse); /* If this is the right table of a LEFT OUTER JOIN, allocate and ** initialize a memory cell that records if this table matches any @@ -135844,7 +138057,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); - assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); iReleaseReg = ++pParse->nMem; iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); @@ -135853,6 +138065,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); VdbeCoverage(v); pLevel->op = OP_Noop; + if( (pTerm->prereqAll & pLevel->notReady)==0 ){ + pTerm->wtFlags |= TERM_CODED; + } }else if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 ){ @@ -135863,7 +138078,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int memEndValue = 0; WhereTerm *pStart, *pEnd; - assert( omitTable==0 ); j = 0; pStart = pEnd = 0; if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++]; @@ -136027,6 +138241,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( char *zEndAff = 0; /* Affinity for end of range constraint */ u8 bSeekPastNull = 0; /* True to seek past initial nulls */ u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ + int omitTable; /* True if we use the index only */ + pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; @@ -136228,6 +138444,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } /* Seek the table cursor, if required */ + omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0; if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ @@ -136262,11 +138480,24 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** the cursor. In this case it is important to do the full evaluation, ** as the result of the expression may not be NULL, even if all table ** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a + ** + ** Also, do not do this when processing one index an a multi-index + ** OR clause, since the transformation will become invalid once we + ** move forward to the next index. + ** https://sqlite.org/src/info/4e8e4857d32d401f */ - if( pLevel->iLeftJoin==0 ){ + if( pLevel->iLeftJoin==0 && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo); } + /* If a partial index is driving the loop, try to eliminate WHERE clause + ** terms from the query that must be true due to the WHERE clause of + ** the partial index + */ + if( pIdx->pPartIdxWhere ){ + whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC); + } + /* Record the instruction used to terminate the loop. */ if( pLoop->wsFlags & WHERE_ONEROW ){ pLevel->op = OP_Noop; @@ -136338,7 +138569,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ int regRowset = 0; /* Register for RowSet object */ int regRowid = 0; /* Register holding rowid */ - int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */ + int iLoopBody = sqlite3VdbeMakeLabel(pParse);/* Start of loop body */ int iRetInit; /* Address of regReturn init */ int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ @@ -136427,10 +138658,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO ); pExpr = sqlite3ExprDup(db, pExpr, 0); - pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr); + pAndExpr = sqlite3ExprAnd(pParse, pAndExpr, pExpr); } if( pAndExpr ){ - pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr); + /* The extra 0x10000 bit on the opcode is masked off and does not + ** become part of the new Expr.op. However, it does make the + ** op==TK_AND comparison inside of sqlite3PExpr() false, and this + ** prevents sqlite3PExpr() from implementing AND short-circuit + ** optimization, which we do not want here. */ + pAndExpr = sqlite3PExpr(pParse, TK_AND|0x10000, 0, pAndExpr); } } @@ -136454,6 +138690,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ + ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1)); WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, wctrlFlags, iCovCur); @@ -136557,6 +138794,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( /* Finish the loop through table entries that match term pOrTerm. */ sqlite3WhereEnd(pSubWInfo); + ExplainQueryPlanPop(pParse); } } } @@ -136571,7 +138809,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( sqlite3VdbeGoto(v, pLevel->addrBrk); sqlite3VdbeResolveLabel(v, iLoopBody); - if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab); + if( pWInfo->nLevel>1 ){ sqlite3StackFree(db, pOrTab); } if( !untestedTerms ) disableTerm(pLevel, pTerm); }else #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ @@ -136658,8 +138896,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( u32 x = pLevel->iLikeRepCntr; if( x>0 ){ skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If,(int)(x>>1)); + VdbeCoverageIf(v, (x&1)==1); + VdbeCoverageIf(v, (x&1)==0); } - VdbeCoverage(v); #endif } #ifdef WHERETRACE_ENABLED /* 0xffff */ @@ -137003,27 +139242,33 @@ static int isLikeOrGlob( zNew[iTo++] = zNew[iFrom]; } zNew[iTo] = 0; + assert( iTo>0 ); - /* If the RHS begins with a digit or a minus sign, then the LHS must be - ** an ordinary column (not a virtual table column) with TEXT affinity. - ** Otherwise the LHS might be numeric and "lhs >= rhs" would be false - ** even though "lhs LIKE rhs" is true. But if the RHS does not start - ** with a digit or '-', then "lhs LIKE rhs" will always be false if - ** the LHS is numeric and so the optimization still works. + /* If the LHS is not an ordinary column with TEXT affinity, then the + ** pattern prefix boundaries (both the start and end boundaries) must + ** not look like a number. Otherwise the pattern might be treated as + ** a number, which will invalidate the LIKE optimization. ** - ** 2018-09-10 ticket c94369cae9b561b1f996d0054bfab11389f9d033 - ** The RHS pattern must not be '/%' because the termination condition - ** will then become "x<'0'" and if the affinity is numeric, will then - ** be converted into "x<0", which is incorrect. + ** Getting this right has been a persistent source of bugs in the + ** LIKE optimization. See, for example: + ** 2018-09-10 https://sqlite.org/src/info/c94369cae9b561b1 + ** 2019-05-02 https://sqlite.org/src/info/b043a54c3de54b28 + ** 2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07 + ** 2019-06-14 https://sqlite.org/src/info/ce8717f0885af975 */ - if( sqlite3Isdigit(zNew[0]) - || zNew[0]=='-' - || (zNew[0]+1=='0' && iTo==1) + if( pLeft->op!=TK_COLUMN + || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT + || IsVirtual(pLeft->y.pTab) /* Value might be numeric */ ){ - if( pLeft->op!=TK_COLUMN - || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT - || IsVirtual(pLeft->pTab) /* Value might be numeric */ - ){ + int isNum; + double rDummy; + isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + if( isNum<=0 ){ + zNew[iTo-1]++; + isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + zNew[iTo-1]--; + } + if( isNum>0 ){ sqlite3ExprDelete(db, pPrefix); sqlite3ValueFree(pVal); return 0; @@ -137123,7 +139368,7 @@ static int isAuxiliaryVtabOperator( ** MATCH(expression,vtab_column) */ pCol = pList->a[1].pExpr; - if( pCol->op==TK_COLUMN && IsVirtual(pCol->pTab) ){ + if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){ for(i=0; iu.zToken, aOp[i].zOp)==0 ){ *peOp2 = aOp[i].eOp2; @@ -137145,12 +139390,12 @@ static int isAuxiliaryVtabOperator( ** with function names in an arbitrary case. */ pCol = pList->a[0].pExpr; - if( pCol->op==TK_COLUMN && IsVirtual(pCol->pTab) ){ + if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){ sqlite3_vtab *pVtab; sqlite3_module *pMod; void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**); void *pNotUsed; - pVtab = sqlite3GetVTable(db, pCol->pTab)->pVtab; + pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); pMod = (sqlite3_module *)pVtab->pModule; @@ -137168,10 +139413,10 @@ static int isAuxiliaryVtabOperator( int res = 0; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; - if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->pTab) ){ + if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->y.pTab) ){ res++; } - if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->pTab) ){ + if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->y.pTab) ){ res++; SWAP(Expr*, pLeft, pRight); } @@ -137518,6 +139763,7 @@ static void exprAnalyzeOrTerm( ** and column is found but leave okToChngToIN false if not found. */ for(j=0; j<2 && !okToChngToIN; j++){ + Expr *pLeft = 0; pOrTerm = pOrWc->a; for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ assert( pOrTerm->eOperator & WO_EQ ); @@ -137541,6 +139787,7 @@ static void exprAnalyzeOrTerm( } iColumn = pOrTerm->u.leftColumn; iCursor = pOrTerm->leftCursor; + pLeft = pOrTerm->pExpr->pLeft; break; } if( i<0 ){ @@ -137560,7 +139807,9 @@ static void exprAnalyzeOrTerm( assert( pOrTerm->eOperator & WO_EQ ); if( pOrTerm->leftCursor!=iCursor ){ pOrTerm->wtFlags &= ~TERM_OR_OK; - }else if( pOrTerm->u.leftColumn!=iColumn ){ + }else if( pOrTerm->u.leftColumn!=iColumn || (iColumn==XN_EXPR + && sqlite3ExprCompare(pParse, pOrTerm->pExpr->pLeft, pLeft, -1) + )){ okToChngToIN = 0; }else{ int affLeft, affRight; @@ -138123,6 +140372,7 @@ static void exprAnalyze( if( pExpr->op==TK_NOTNULL && pExpr->pLeft->op==TK_COLUMN && pExpr->pLeft->iColumn>=0 + && !ExprHasProperty(pExpr, EP_FromJoin) && OptimizationEnabled(db, SQLITE_Stat34) ){ Expr *pNewExpr; @@ -138256,6 +140506,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){ }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->op==TK_FUNCTION && p->y.pWin ){ + mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition); + mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy); + } +#endif return mask; } SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ @@ -138314,6 +140570,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( pArgs = pItem->u1.pFuncArg; if( pArgs==0 ) return; for(j=k=0; jnExpr; j++){ + Expr *pRhs; while( knCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;} if( k>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d", @@ -138324,9 +140581,10 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( if( pColRef==0 ) return; pColRef->iTable = pItem->iCursor; pColRef->iColumn = k++; - pColRef->pTab = pTab; - pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, - sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0)); + pColRef->y.pTab = pTab; + pRhs = sqlite3PExpr(pParse, TK_UPLUS, + sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); + pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } @@ -138645,6 +140903,17 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ return 0; } +/* +** This is whereScanInit() for the case of an index on an expression. +** It is factored out into a separate tail-recursion subroutine so that +** the normal whereScanInit() routine, which is a high-runner, does not +** need to push registers onto the stack as part of its prologue. +*/ +static SQLITE_NOINLINE WhereTerm *whereScanInitIndexExpr(WhereScan *pScan){ + pScan->idxaff = sqlite3ExprAffinity(pScan->pIdxExpr); + return whereScanNext(pScan); +} + /* ** Initialize a WHERE clause scanner object. Return a pointer to the ** first match. Return NULL if there are no matches. @@ -138677,12 +140946,19 @@ static WhereTerm *whereScanInit( pScan->pIdxExpr = 0; pScan->idxaff = 0; pScan->zCollName = 0; + pScan->opMask = opMask; + pScan->k = 0; + pScan->aiCur[0] = iCur; + pScan->nEquiv = 1; + pScan->iEquiv = 1; if( pIdx ){ int j = iColumn; iColumn = pIdx->aiColumn[j]; if( iColumn==XN_EXPR ){ pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; pScan->zCollName = pIdx->azColl[j]; + pScan->aiColumn[0] = XN_EXPR; + return whereScanInitIndexExpr(pScan); }else if( iColumn==pIdx->pTable->iPKey ){ iColumn = XN_ROWID; }else if( iColumn>=0 ){ @@ -138692,12 +140968,7 @@ static WhereTerm *whereScanInit( }else if( iColumn==XN_EXPR ){ return 0; } - pScan->opMask = opMask; - pScan->k = 0; - pScan->aiCur[0] = iCur; pScan->aiColumn[0] = iColumn; - pScan->nEquiv = 1; - pScan->iEquiv = 1; return whereScanNext(pScan); } @@ -138884,17 +141155,17 @@ static LogEst estLog(LogEst N){ ** opcodes into OP_Copy when the table is being accessed via co-routine ** instead of via table lookup. ** -** If the bIncrRowid parameter is 0, then any OP_Rowid instructions on -** cursor iTabCur are transformed into OP_Null. Or, if bIncrRowid is non-zero, -** then each OP_Rowid is transformed into an instruction to increment the -** value stored in its output register. +** If the iAutoidxCur is not zero, then any OP_Rowid instructions on +** cursor iTabCur are transformed into OP_Sequence opcode for the +** iAutoidxCur cursor, in order to generate unique rowids for the +** automatic index being generated. */ static void translateColumnToCopy( Parse *pParse, /* Parsing context */ int iStart, /* Translate from this opcode to the end */ int iTabCur, /* OP_Column/OP_Rowid references to this table */ int iRegister, /* The first column is in this register */ - int bIncrRowid /* If non-zero, transform OP_rowid to OP_AddImm(1) */ + int iAutoidxCur /* If non-zero, cursor of autoindex being generated */ ){ Vdbe *v = pParse->pVdbe; VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart); @@ -138908,11 +141179,9 @@ static void translateColumnToCopy( pOp->p2 = pOp->p3; pOp->p3 = 0; }else if( pOp->opcode==OP_Rowid ){ - if( bIncrRowid ){ - /* Increment the value stored in the P2 operand of the OP_Rowid. */ - pOp->opcode = OP_AddImm; - pOp->p1 = pOp->p2; - pOp->p2 = 1; + if( iAutoidxCur ){ + pOp->opcode = OP_Sequence; + pOp->p1 = iAutoidxCur; }else{ pOp->opcode = OP_Null; pOp->p1 = 0; @@ -139059,7 +141328,7 @@ static void constructAutomaticIndex( && (pTerm->wtFlags & TERM_VIRTUAL)==0 && !ExprHasProperty(pExpr, EP_FromJoin) && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){ - pPartial = sqlite3ExprAnd(pParse->db, pPartial, + pPartial = sqlite3ExprAnd(pParse, pPartial, sqlite3ExprDup(pParse->db, pExpr, 0)); } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ @@ -139172,7 +141441,7 @@ static void constructAutomaticIndex( addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); } if( pPartial ){ - iContinue = sqlite3VdbeMakeLabel(v); + iContinue = sqlite3VdbeMakeLabel(pParse); sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL); pLoop->wsFlags |= WHERE_PARTIALIDX; } @@ -139186,8 +141455,9 @@ static void constructAutomaticIndex( if( pTabItem->fg.viaCoroutine ){ sqlite3VdbeChangeP2(v, addrCounter, regBase+n); testcase( pParse->db->mallocFailed ); + assert( pLevel->iIdxCur>0 ); translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, - pTabItem->regResult, 1); + pTabItem->regResult, pLevel->iIdxCur); sqlite3VdbeGoto(v, addrTop); pTabItem->fg.viaCoroutine = 0; }else{ @@ -139367,9 +141637,11 @@ static sqlite3_index_info *allocateIndexInfo( ** method of the virtual table with the sqlite3_index_info object that ** comes in as the 3rd argument to this function. ** -** If an error occurs, pParse is populated with an error message and a -** non-zero value is returned. Otherwise, 0 is returned and the output -** part of the sqlite3_index_info structure is left populated. +** If an error occurs, pParse is populated with an error message and an +** appropriate error code is returned. A return of SQLITE_CONSTRAINT from +** xBestIndex is not considered an error. SQLITE_CONSTRAINT indicates that +** the current configuration of "unusable" flags in sqlite3_index_info can +** not result in a valid plan. ** ** Whether or not an error is returned, it is the responsibility of the ** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates @@ -139383,7 +141655,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ rc = pVtab->pModule->xBestIndex(pVtab, p); TRACE_IDX_OUTPUTS(p); - if( rc!=SQLITE_OK ){ + if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){ if( rc==SQLITE_NOMEM ){ sqlite3OomFault(pParse->db); }else if( !pVtab->zErrMsg ){ @@ -139394,19 +141666,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ } sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = 0; - -#if 0 - /* This error is now caught by the caller. - ** Search for "xBestIndex malfunction" below */ - for(i=0; inConstraint; i++){ - if( !p->aConstraint[i].usable && p->aConstraintUsage[i].argvIndex>0 ){ - sqlite3ErrorMsg(pParse, - "table %s: xBestIndex returned an invalid plan", pTab->zName); - } - } -#endif - - return pParse->nErr; + return rc; } #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ @@ -140461,6 +142721,14 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ sqlite3 *db = pWInfo->pParse->db; int rc; + /* Stop the search once we hit the query planner search limit */ + if( pBuilder->iPlanLimit==0 ){ + WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n")); + if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0; + return SQLITE_DONE; + } + pBuilder->iPlanLimit--; + /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. */ @@ -140547,7 +142815,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ rc = whereLoopXfer(db, p, pTemplate); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ Index *pIndex = p->u.btree.pIndex; - if( pIndex && pIndex->tnum==0 ){ + if( pIndex && pIndex->idxType==SQLITE_IDXTYPE_IPK ){ p->u.btree.pIndex = 0; } } @@ -140714,8 +142982,8 @@ static int whereRangeVectorLen( ** terms only. If it is modified, this value is restored before this ** function returns. ** -** If pProbe->tnum==0, that means pIndex is a fake index used for the -** INTEGER PRIMARY KEY. +** If pProbe->idxType==SQLITE_IDXTYPE_IPK, that means pIndex is +** a fake index used for the INTEGER PRIMARY KEY. */ static int whereLoopAddBtreeIndex( WhereLoopBuilder *pBuilder, /* The WhereLoop factory */ @@ -141215,6 +143483,7 @@ static int whereLoopAddBtree( sPk.onError = OE_Replace; sPk.pTable = pTab; sPk.szIdxRow = pTab->szTabRow; + sPk.idxType = SQLITE_IDXTYPE_IPK; aiRowEstPk[0] = pTab->nRowLogEst; aiRowEstPk[1] = 0; pFirst = pSrc->pTab->pIndex; @@ -141305,7 +143574,7 @@ static int whereLoopAddBtree( b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); /* The ONEPASS_DESIRED flags never occurs together with ORDER BY */ assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 ); - if( pProbe->tnum<=0 ){ + if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){ /* Integer primary key index */ pNew->wsFlags = WHERE_IPK; @@ -141471,7 +143740,17 @@ static int whereLoopAddVirtualOne( /* Invoke the virtual table xBestIndex() method */ rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo); - if( rc ) return rc; + if( rc ){ + if( rc==SQLITE_CONSTRAINT ){ + /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means + ** that the particular combination of parameters provided is unusable. + ** Make no entries in the loop table. + */ + WHERETRACE(0xffff, (" ^^^^--- non-viable plan rejected!\n")); + return SQLITE_OK; + } + return rc; + } mxTerm = -1; assert( pNew->nLSlot>=nConstraint ); @@ -141648,11 +143927,11 @@ static int whereLoopAddVirtual( rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn); /* If the call to xBestIndex() with all terms enabled produced a plan - ** that does not require any source tables (IOW: a plan with mBest==0), - ** then there is no point in making any further calls to xBestIndex() - ** since they will all return the same result (if the xBestIndex() - ** implementation is sane). */ - if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){ + ** that does not require any source tables (IOW: a plan with mBest==0) + ** and does not use an IN(...) operator, then there is no point in making + ** any further calls to xBestIndex() since they will all return the same + ** result (if the xBestIndex() implementation is sane). */ + if( rc==SQLITE_OK && ((mBest = (pNew->prereq & ~mPrereq))!=0 || bIn) ){ int seenZero = 0; /* True if a plan with no prereqs seen */ int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */ Bitmask mPrev = 0; @@ -141867,9 +144146,11 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; whereLoopInit(pNew); + pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT; for(iTab=0, pItem=pTabList->a; pItemiTab = iTab; + pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){ /* This condition is true when pItem is the FROM clause term on the @@ -141895,7 +144176,15 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable); } mPrior |= pNew->maskSelf; - if( rc || db->mallocFailed ) break; + if( rc || db->mallocFailed ){ + if( rc==SQLITE_DONE ){ + /* We hit the query planner search limit set by iPlanLimit */ + sqlite3_log(SQLITE_WARNING, "abbreviated query algorithm search"); + rc = SQLITE_OK; + }else{ + break; + } + } } whereLoopClear(db, pNew); @@ -142961,7 +145250,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( pWInfo->pResultSet = pResultSet; pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1; pWInfo->nLevel = nTabList; - pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v); + pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(pParse); pWInfo->wctrlFlags = wctrlFlags; pWInfo->iLimit = iAuxArg; pWInfo->savedNQueryLoop = pParse->nQueryLoop; @@ -143235,9 +145524,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){ int wsFlags = pWInfo->a[0].pWLoop->wsFlags; int bOnerow = (wsFlags & WHERE_ONEROW)!=0; + assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) ); if( bOnerow || ( 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW) - && 0==(wsFlags & WHERE_VIRTUALTABLE) + && !IsVirtual(pTabList->a[0].pTab) && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK)) )){ pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI; @@ -143392,7 +145682,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( pParse, pTabList, pLevel, wctrlFlags ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); - notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady); + notReady = sqlite3WhereCodeOneLoopStart(pParse,v,pWInfo,ii,pLevel,notReady); pWInfo->iContinue = pLevel->addrCont; if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){ sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain); @@ -143577,6 +145867,29 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ continue; } +#ifdef SQLITE_ENABLE_EARLY_CURSOR_CLOSE + /* Close all of the cursors that were opened by sqlite3WhereBegin. + ** Except, do not close cursors that will be reused by the OR optimization + ** (WHERE_OR_SUBCLAUSE). And do not close the OP_OpenWrite cursors + ** created for the ONEPASS optimization. + */ + if( (pTab->tabFlags & TF_Ephemeral)==0 + && pTab->pSelect==0 + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 + ){ + int ws = pLoop->wsFlags; + if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){ + sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); + } + if( (ws & WHERE_INDEXED)!=0 + && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0 + && pLevel->iIdxCur!=pWInfo->aiCurOnePass[1] + ){ + sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur); + } + } +#endif + /* If this scan uses an index, make VDBE code substitutions to read data ** from the index instead of from the table where possible. In some cases ** this optimization prevents the table from ever being read, which can @@ -143851,6 +146164,96 @@ static void dense_rankValueFunc(sqlite3_context *pCtx){ } } +/* +** Implementation of built-in window function nth_value(). This +** implementation is used in "slow mode" only - when the EXCLUDE clause +** is not set to the default value "NO OTHERS". +*/ +struct NthValueCtx { + i64 nStep; + sqlite3_value *pValue; +}; +static void nth_valueStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + i64 iVal; + switch( sqlite3_value_numeric_type(apArg[1]) ){ + case SQLITE_INTEGER: + iVal = sqlite3_value_int64(apArg[1]); + break; + case SQLITE_FLOAT: { + double fVal = sqlite3_value_double(apArg[1]); + if( ((i64)fVal)!=fVal ) goto error_out; + iVal = (i64)fVal; + break; + } + default: + goto error_out; + } + if( iVal<=0 ) goto error_out; + + p->nStep++; + if( iVal==p->nStep ){ + p->pValue = sqlite3_value_dup(apArg[0]); + if( !p->pValue ){ + sqlite3_result_error_nomem(pCtx); + } + } + } + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); + return; + + error_out: + sqlite3_result_error( + pCtx, "second argument to nth_value must be a positive integer", -1 + ); +} +static void nth_valueFinalizeFunc(sqlite3_context *pCtx){ + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, 0); + if( p && p->pValue ){ + sqlite3_result_value(pCtx, p->pValue); + sqlite3_value_free(p->pValue); + p->pValue = 0; + } +} +#define nth_valueInvFunc noopStepFunc +#define nth_valueValueFunc noopValueFunc + +static void first_valueStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->pValue==0 ){ + p->pValue = sqlite3_value_dup(apArg[0]); + if( !p->pValue ){ + sqlite3_result_error_nomem(pCtx); + } + } + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); +} +static void first_valueFinalizeFunc(sqlite3_context *pCtx){ + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->pValue ){ + sqlite3_result_value(pCtx, p->pValue); + sqlite3_value_free(p->pValue); + p->pValue = 0; + } +} +#define first_valueInvFunc noopStepFunc +#define first_valueValueFunc noopValueFunc + /* ** Implementation of built-in window function rank(). Assumes that ** the window frame has been set to: @@ -143886,7 +146289,7 @@ static void rankValueFunc(sqlite3_context *pCtx){ ** Implementation of built-in window function percent_rank(). Assumes that ** the window frame has been set to: ** -** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +** GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING */ static void percent_rankStepFunc( sqlite3_context *pCtx, @@ -143894,38 +146297,44 @@ static void percent_rankStepFunc( sqlite3_value **apArg ){ struct CallCount *p; - UNUSED_PARAMETER(nArg); assert( nArg==1 ); - + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ - if( p->nTotal==0 ){ - p->nTotal = sqlite3_value_int64(apArg[0]); - } - p->nStep++; - if( p->nValue==0 ){ - p->nValue = p->nStep; - } + p->nTotal++; } } +static void percent_rankInvFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct CallCount *p; + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p->nStep++; +} static void percent_rankValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ + p->nValue = p->nStep; if( p->nTotal>1 ){ - double r = (double)(p->nValue-1) / (double)(p->nTotal-1); + double r = (double)p->nValue / (double)(p->nTotal-1); sqlite3_result_double(pCtx, r); }else{ sqlite3_result_double(pCtx, 0.0); } - p->nValue = 0; } } +#define percent_rankFinalizeFunc percent_rankValueFunc /* ** Implementation of built-in window function cume_dist(). Assumes that ** the window frame has been set to: ** -** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +** GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING */ static void cume_distStepFunc( sqlite3_context *pCtx, @@ -143933,24 +146342,33 @@ static void cume_distStepFunc( sqlite3_value **apArg ){ struct CallCount *p; - assert( nArg==1 ); UNUSED_PARAMETER(nArg); - + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ - if( p->nTotal==0 ){ - p->nTotal = sqlite3_value_int64(apArg[0]); - } - p->nStep++; + p->nTotal++; } } -static void cume_distValueFunc(sqlite3_context *pCtx){ +static void cume_distInvFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ struct CallCount *p; + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); - if( p && p->nTotal ){ + p->nStep++; +} +static void cume_distValueFunc(sqlite3_context *pCtx){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, 0); + if( p ){ double r = (double)(p->nStep) / (double)(p->nTotal); sqlite3_result_double(pCtx, r); } } +#define cume_distFinalizeFunc cume_distValueFunc /* ** Context object for ntile() window function. @@ -143965,7 +146383,7 @@ struct NtileCtx { ** Implementation of ntile(). This assumes that the window frame has ** been coerced to: ** -** ROWS UNBOUNDED PRECEDING AND CURRENT ROW +** ROWS CURRENT ROW AND UNBOUNDED FOLLOWING */ static void ntileStepFunc( sqlite3_context *pCtx, @@ -143973,32 +146391,42 @@ static void ntileStepFunc( sqlite3_value **apArg ){ struct NtileCtx *p; - assert( nArg==2 ); UNUSED_PARAMETER(nArg); + assert( nArg==1 ); UNUSED_PARAMETER(nArg); p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ if( p->nTotal==0 ){ p->nParam = sqlite3_value_int64(apArg[0]); - p->nTotal = sqlite3_value_int64(apArg[1]); if( p->nParam<=0 ){ sqlite3_result_error( pCtx, "argument of ntile must be a positive integer", -1 ); } } - p->iRow++; + p->nTotal++; } } +static void ntileInvFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct NtileCtx *p; + assert( nArg==1 ); UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); + p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p->iRow++; +} static void ntileValueFunc(sqlite3_context *pCtx){ struct NtileCtx *p; p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p && p->nParam>0 ){ int nSize = (p->nTotal / p->nParam); if( nSize==0 ){ - sqlite3_result_int64(pCtx, p->iRow); + sqlite3_result_int64(pCtx, p->iRow+1); }else{ i64 nLarge = p->nTotal - p->nParam*nSize; i64 iSmall = nLarge*(nSize+1); - i64 iRow = p->iRow-1; + i64 iRow = p->iRow; assert( (nLarge*(nSize+1) + (p->nParam-nLarge)*nSize)==p->nTotal ); @@ -144010,6 +146438,7 @@ static void ntileValueFunc(sqlite3_context *pCtx){ } } } +#define ntileFinalizeFunc ntileValueFunc /* ** Context object for last_value() window function. @@ -144059,7 +146488,7 @@ static void last_valueInvFunc( } static void last_valueValueFunc(sqlite3_context *pCtx){ struct LastValueCtx *p; - p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, 0); if( p && p->pVal ){ sqlite3_result_value(pCtx, p->pVal); } @@ -144149,12 +146578,12 @@ SQLITE_PRIVATE void sqlite3WindowFunctions(void){ WINDOWFUNCX(row_number, 0, 0), WINDOWFUNCX(dense_rank, 0, 0), WINDOWFUNCX(rank, 0, 0), - WINDOWFUNCX(percent_rank, 0, SQLITE_FUNC_WINDOW_SIZE), - WINDOWFUNCX(cume_dist, 0, SQLITE_FUNC_WINDOW_SIZE), - WINDOWFUNCX(ntile, 1, SQLITE_FUNC_WINDOW_SIZE), + WINDOWFUNCALL(percent_rank, 0, 0), + WINDOWFUNCALL(cume_dist, 0, 0), + WINDOWFUNCALL(ntile, 1, 0), WINDOWFUNCALL(last_value, 1, 0), - WINDOWFUNCNOOP(nth_value, 2, 0), - WINDOWFUNCNOOP(first_value, 1, 0), + WINDOWFUNCALL(nth_value, 2, 0), + WINDOWFUNCALL(first_value, 1, 0), WINDOWFUNCNOOP(lead, 1, 0), WINDOWFUNCNOOP(lead, 2, 0), WINDOWFUNCNOOP(lead, 3, 0), @@ -144165,6 +146594,17 @@ SQLITE_PRIVATE void sqlite3WindowFunctions(void){ sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs)); } +static Window *windowFind(Parse *pParse, Window *pList, const char *zName){ + Window *p; + for(p=pList; p; p=p->pNextWin){ + if( sqlite3StrICmp(p->zName, zName)==0 ) break; + } + if( p==0 ){ + sqlite3ErrorMsg(pParse, "no such window: %s", zName); + } + return p; +} + /* ** This function is called immediately after resolving the function name ** for a window function within a SELECT statement. Argument pList is a @@ -144188,48 +146628,66 @@ SQLITE_PRIVATE void sqlite3WindowUpdate( Window *pWin, /* Window frame to update */ FuncDef *pFunc /* Window function definition */ ){ - if( pWin->zName && pWin->eType==0 ){ - Window *p; - for(p=pList; p; p=p->pNextWin){ - if( sqlite3StrICmp(p->zName, pWin->zName)==0 ) break; - } - if( p==0 ){ - sqlite3ErrorMsg(pParse, "no such window: %s", pWin->zName); - return; - } + if( pWin->zName && pWin->eFrmType==0 ){ + Window *p = windowFind(pParse, pList, pWin->zName); + if( p==0 ) return; pWin->pPartition = sqlite3ExprListDup(pParse->db, p->pPartition, 0); pWin->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy, 0); pWin->pStart = sqlite3ExprDup(pParse->db, p->pStart, 0); pWin->pEnd = sqlite3ExprDup(pParse->db, p->pEnd, 0); pWin->eStart = p->eStart; pWin->eEnd = p->eEnd; - pWin->eType = p->eType; + pWin->eFrmType = p->eFrmType; + pWin->eExclude = p->eExclude; + }else{ + sqlite3WindowChain(pParse, pWin, pList); } + if( (pWin->eFrmType==TK_RANGE) + && (pWin->pStart || pWin->pEnd) + && (pWin->pOrderBy==0 || pWin->pOrderBy->nExpr!=1) + ){ + sqlite3ErrorMsg(pParse, + "RANGE with offset PRECEDING/FOLLOWING requires one ORDER BY expression" + ); + }else if( pFunc->funcFlags & SQLITE_FUNC_WINDOW ){ sqlite3 *db = pParse->db; if( pWin->pFilter ){ sqlite3ErrorMsg(pParse, "FILTER clause may only be used with aggregate window functions" ); - }else - if( pFunc->zName==row_numberName || pFunc->zName==ntileName ){ - sqlite3ExprDelete(db, pWin->pStart); - sqlite3ExprDelete(db, pWin->pEnd); - pWin->pStart = pWin->pEnd = 0; - pWin->eType = TK_ROWS; - pWin->eStart = TK_UNBOUNDED; - pWin->eEnd = TK_CURRENT; - }else - - if( pFunc->zName==dense_rankName || pFunc->zName==rankName - || pFunc->zName==percent_rankName || pFunc->zName==cume_distName - ){ - sqlite3ExprDelete(db, pWin->pStart); - sqlite3ExprDelete(db, pWin->pEnd); - pWin->pStart = pWin->pEnd = 0; - pWin->eType = TK_RANGE; - pWin->eStart = TK_UNBOUNDED; - pWin->eEnd = TK_CURRENT; + }else{ + struct WindowUpdate { + const char *zFunc; + int eFrmType; + int eStart; + int eEnd; + } aUp[] = { + { row_numberName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT }, + { dense_rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT }, + { rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT }, + { percent_rankName, TK_GROUPS, TK_CURRENT, TK_UNBOUNDED }, + { cume_distName, TK_GROUPS, TK_FOLLOWING, TK_UNBOUNDED }, + { ntileName, TK_ROWS, TK_CURRENT, TK_UNBOUNDED }, + { leadName, TK_ROWS, TK_UNBOUNDED, TK_UNBOUNDED }, + { lagName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT }, + }; + int i; + for(i=0; izName==aUp[i].zFunc ){ + sqlite3ExprDelete(db, pWin->pStart); + sqlite3ExprDelete(db, pWin->pEnd); + pWin->pEnd = pWin->pStart = 0; + pWin->eFrmType = aUp[i].eFrmType; + pWin->eStart = aUp[i].eStart; + pWin->eEnd = aUp[i].eEnd; + pWin->eExclude = 0; + if( pWin->eStart==TK_FOLLOWING ){ + pWin->pStart = sqlite3Expr(db, TK_INTEGER, "1"); + } + break; + } + } } } pWin->pFunc = pFunc; @@ -144244,6 +146702,7 @@ struct WindowRewrite { Window *pWin; SrcList *pSrc; ExprList *pSub; + Table *pTab; Select *pSubSelect; /* Current sub-select, if any */ }; @@ -144277,12 +146736,12 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ switch( pExpr->op ){ case TK_FUNCTION: - if( pExpr->pWin==0 ){ + if( !ExprHasProperty(pExpr, EP_WinFunc) ){ break; }else{ Window *pWin; for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){ - if( pExpr->pWin==pWin ){ + if( pExpr->y.pWin==pWin ){ assert( pWin->pOwner==pExpr ); return WRC_Prune; } @@ -144304,6 +146763,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ pExpr->op = TK_COLUMN; pExpr->iColumn = p->pSub->nExpr-1; pExpr->iTable = p->pWin->iEphCsr; + pExpr->y.pTab = p->pTab; } break; @@ -144347,6 +146807,7 @@ static void selectWindowRewriteEList( Window *pWin, SrcList *pSrc, ExprList *pEList, /* Rewrite expressions in this list */ + Table *pTab, ExprList **ppSub /* IN/OUT: Sub-select expression-list */ ){ Walker sWalker; @@ -144358,6 +146819,7 @@ static void selectWindowRewriteEList( sRewrite.pSub = *ppSub; sRewrite.pWin = pWin; sRewrite.pSrc = pSrc; + sRewrite.pTab = pTab; sWalker.pParse = pParse; sWalker.xExprCallback = selectWindowRewriteExprCb; @@ -144376,13 +146838,18 @@ static void selectWindowRewriteEList( static ExprList *exprListAppendList( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to append. Might be NULL */ - ExprList *pAppend /* List of values to append. Might be NULL */ + ExprList *pAppend, /* List of values to append. Might be NULL */ + int bIntToNull ){ if( pAppend ){ int i; int nInit = pList ? pList->nExpr : 0; for(i=0; inExpr; i++){ Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0); + if( bIntToNull && pDup && pDup->op==TK_INTEGER ){ + pDup->op = TK_NULL; + pDup->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse); + } pList = sqlite3ExprListAppend(pParse, pList, pDup); if( pList ) pList->a[nInit+i].sortOrder = pAppend->a[i].sortOrder; } @@ -144399,7 +146866,7 @@ static ExprList *exprListAppendList( */ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ int rc = SQLITE_OK; - if( p->pWin ){ + if( p->pWin && p->pPrior==0 ){ Vdbe *v = sqlite3GetVdbe(pParse); sqlite3 *db = pParse->db; Select *pSub = 0; /* The subquery */ @@ -144412,17 +146879,24 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ ExprList *pSublist = 0; /* Expression list for sub-query */ Window *pMWin = p->pWin; /* Master window object */ Window *pWin; /* Window object iterator */ + Table *pTab; + + pTab = sqlite3DbMallocZero(db, sizeof(Table)); + if( pTab==0 ){ + return SQLITE_NOMEM; + } p->pSrc = 0; p->pWhere = 0; p->pGroupBy = 0; p->pHaving = 0; + p->selFlags &= ~SF_Aggregate; /* Create the ORDER BY clause for the sub-select. This is the concatenation ** of the window PARTITION and ORDER BY clauses. Then, if this makes it ** redundant, remove the ORDER BY from the parent SELECT. */ pSort = sqlite3ExprListDup(db, pMWin->pPartition, 0); - pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy); + pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy, 1); if( pSort && p->pOrderBy ){ if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){ sqlite3ExprListDelete(db, p->pOrderBy); @@ -144434,16 +146908,17 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ ** The OpenEphemeral instruction is coded later, after it is known how ** many columns the table will have. */ pMWin->iEphCsr = pParse->nTab++; + pParse->nTab += 3; - selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, &pSublist); - selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, &pSublist); + selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, pTab, &pSublist); + selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, pTab, &pSublist); pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0); /* Append the PARTITION BY and ORDER BY expressions to the to the ** sub-select expression list. They are required to figure out where ** boundaries for partitions and sets of peer rows lie. */ - pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition); - pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy); + pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition, 0); + pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy, 0); /* Append the arguments passed to each window function to the ** sub-select expression list. Also allocate two registers for each @@ -144451,7 +146926,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ ** results. */ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); - pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList); + pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList, 0); if( pWin->pFilter ){ Expr *pFilter = sqlite3ExprDup(db, pWin->pFilter, 0); pSublist = sqlite3ExprListAppend(pParse, pSublist, pFilter); @@ -144476,24 +146951,30 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ pSub = sqlite3SelectNew( pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0 ); - p->pSrc = sqlite3SrcListAppend(db, 0, 0, 0); - assert( p->pSrc || db->mallocFailed ); + p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( p->pSrc ){ + Table *pTab2; p->pSrc->a[0].pSelect = pSub; sqlite3SrcListAssignCursors(pParse, p->pSrc); - if( sqlite3ExpandSubquery(pParse, &p->pSrc->a[0]) ){ + pSub->selFlags |= SF_Expanded; + pTab2 = sqlite3ResultSetOfSelect(pParse, pSub); + if( pTab2==0 ){ rc = SQLITE_NOMEM; }else{ - pSub->selFlags |= SF_Expanded; - p->selFlags &= ~SF_Aggregate; - sqlite3SelectPrep(pParse, pSub, 0); + memcpy(pTab, pTab2, sizeof(Table)); + pTab->tabFlags |= TF_Ephemeral; + p->pSrc->a[0].pTab = pTab; + pTab = pTab2; } - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr); }else{ sqlite3SelectDelete(db, pSub); } if( db->mallocFailed ) rc = SQLITE_NOMEM; + sqlite3DbFree(db, pTab); } return rc; @@ -144510,6 +146991,7 @@ SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3 *db, Window *p){ sqlite3ExprDelete(db, p->pEnd); sqlite3ExprDelete(db, p->pStart); sqlite3DbFree(db, p->zName); + sqlite3DbFree(db, p->zBase); sqlite3DbFree(db, p); } } @@ -144534,6 +147016,7 @@ SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p){ */ static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ if( 0==sqlite3ExprIsConstant(pExpr) ){ + if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr); sqlite3ExprDelete(pParse->db, pExpr); pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0); } @@ -144545,16 +147028,18 @@ static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ */ SQLITE_PRIVATE Window *sqlite3WindowAlloc( Parse *pParse, /* Parsing context */ - int eType, /* Frame type. TK_RANGE or TK_ROWS */ + int eType, /* Frame type. TK_RANGE, TK_ROWS, TK_GROUPS, or 0 */ int eStart, /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */ Expr *pStart, /* Start window size if TK_PRECEDING or FOLLOWING */ int eEnd, /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */ - Expr *pEnd /* End window size if TK_FOLLOWING or PRECEDING */ + Expr *pEnd, /* End window size if TK_FOLLOWING or PRECEDING */ + u8 eExclude /* EXCLUDE clause */ ){ Window *pWin = 0; + int bImplicitFrame = 0; /* Parser assures the following: */ - assert( eType==TK_RANGE || eType==TK_ROWS ); + assert( eType==0 || eType==TK_RANGE || eType==TK_ROWS || eType==TK_GROUPS ); assert( eStart==TK_CURRENT || eStart==TK_PRECEDING || eStart==TK_UNBOUNDED || eStart==TK_FOLLOWING ); assert( eEnd==TK_CURRENT || eEnd==TK_FOLLOWING @@ -144562,13 +147047,9 @@ SQLITE_PRIVATE Window *sqlite3WindowAlloc( assert( (eStart==TK_PRECEDING || eStart==TK_FOLLOWING)==(pStart!=0) ); assert( (eEnd==TK_FOLLOWING || eEnd==TK_PRECEDING)==(pEnd!=0) ); - - /* If a frame is declared "RANGE" (not "ROWS"), then it may not use - ** either " PRECEDING" or " FOLLOWING". - */ - if( eType==TK_RANGE && (pStart!=0 || pEnd!=0) ){ - sqlite3ErrorMsg(pParse, "RANGE must use only UNBOUNDED or CURRENT ROW"); - goto windowAllocErr; + if( eType==0 ){ + bImplicitFrame = 1; + eType = TK_RANGE; } /* Additionally, the @@ -144588,15 +147069,20 @@ SQLITE_PRIVATE Window *sqlite3WindowAlloc( if( (eStart==TK_CURRENT && eEnd==TK_PRECEDING) || (eStart==TK_FOLLOWING && (eEnd==TK_PRECEDING || eEnd==TK_CURRENT)) ){ - sqlite3ErrorMsg(pParse, "unsupported frame delimiter for ROWS"); + sqlite3ErrorMsg(pParse, "unsupported frame specification"); goto windowAllocErr; } pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( pWin==0 ) goto windowAllocErr; - pWin->eType = eType; + pWin->eFrmType = eType; pWin->eStart = eStart; pWin->eEnd = eEnd; + if( eExclude==0 && OptimizationDisabled(pParse->db, SQLITE_WindowFunc) ){ + eExclude = TK_NO; + } + pWin->eExclude = eExclude; + pWin->bImplicitFrame = bImplicitFrame; pWin->pEnd = sqlite3WindowOffsetExpr(pParse, pEnd); pWin->pStart = sqlite3WindowOffsetExpr(pParse, pStart); return pWin; @@ -144607,16 +147093,81 @@ SQLITE_PRIVATE Window *sqlite3WindowAlloc( return 0; } +/* +** Attach PARTITION and ORDER BY clauses pPartition and pOrderBy to window +** pWin. Also, if parameter pBase is not NULL, set pWin->zBase to the +** equivalent nul-terminated string. +*/ +SQLITE_PRIVATE Window *sqlite3WindowAssemble( + Parse *pParse, + Window *pWin, + ExprList *pPartition, + ExprList *pOrderBy, + Token *pBase +){ + if( pWin ){ + pWin->pPartition = pPartition; + pWin->pOrderBy = pOrderBy; + if( pBase ){ + pWin->zBase = sqlite3DbStrNDup(pParse->db, pBase->z, pBase->n); + } + }else{ + sqlite3ExprListDelete(pParse->db, pPartition); + sqlite3ExprListDelete(pParse->db, pOrderBy); + } + return pWin; +} + +/* +** Window *pWin has just been created from a WINDOW clause. Tokne pBase +** is the base window. Earlier windows from the same WINDOW clause are +** stored in the linked list starting at pWin->pNextWin. This function +** either updates *pWin according to the base specification, or else +** leaves an error in pParse. +*/ +SQLITE_PRIVATE void sqlite3WindowChain(Parse *pParse, Window *pWin, Window *pList){ + if( pWin->zBase ){ + sqlite3 *db = pParse->db; + Window *pExist = windowFind(pParse, pList, pWin->zBase); + if( pExist ){ + const char *zErr = 0; + /* Check for errors */ + if( pWin->pPartition ){ + zErr = "PARTITION clause"; + }else if( pExist->pOrderBy && pWin->pOrderBy ){ + zErr = "ORDER BY clause"; + }else if( pExist->bImplicitFrame==0 ){ + zErr = "frame specification"; + } + if( zErr ){ + sqlite3ErrorMsg(pParse, + "cannot override %s of window: %s", zErr, pWin->zBase + ); + }else{ + pWin->pPartition = sqlite3ExprListDup(db, pExist->pPartition, 0); + if( pExist->pOrderBy ){ + assert( pWin->pOrderBy==0 ); + pWin->pOrderBy = sqlite3ExprListDup(db, pExist->pOrderBy, 0); + } + sqlite3DbFree(db, pWin->zBase); + pWin->zBase = 0; + } + } + } +} + /* ** Attach window object pWin to expression p. */ SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ if( p ){ + assert( p->op==TK_FUNCTION ); /* This routine is only called for the parser. If pWin was not ** allocated due to an OOM, then the parser would fail before ever ** invoking this routine */ if( ALWAYS(pWin) ){ - p->pWin = pWin; + p->y.pWin = pWin; + ExprSetProperty(p, EP_WinFunc); pWin->pOwner = p; if( p->flags & EP_Distinct ){ sqlite3ErrorMsg(pParse, @@ -144633,9 +147184,10 @@ SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ ** Identical window objects can be processed in a single scan. */ SQLITE_PRIVATE int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){ - if( p1->eType!=p2->eType ) return 1; + if( p1->eFrmType!=p2->eFrmType ) return 1; if( p1->eStart!=p2->eStart ) return 1; if( p1->eEnd!=p2->eEnd ) return 1; + if( p1->eExclude!=p2->eExclude ) return 1; if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1; if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1; if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1; @@ -144652,12 +147204,27 @@ SQLITE_PRIVATE int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){ SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){ Window *pWin; Vdbe *v = sqlite3GetVdbe(pParse); - int nPart = (pMWin->pPartition ? pMWin->pPartition->nExpr : 0); - nPart += (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); - if( nPart ){ + + /* Allocate registers to use for PARTITION BY values, if any. Initialize + ** said registers to NULL. */ + if( pMWin->pPartition ){ + int nExpr = pMWin->pPartition->nExpr; pMWin->regPart = pParse->nMem+1; - pParse->nMem += nPart; - sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nPart-1); + pParse->nMem += nExpr; + sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nExpr-1); + } + + pMWin->regOne = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regOne); + + if( pMWin->eExclude ){ + pMWin->regStartRowid = ++pParse->nMem; + pMWin->regEndRowid = ++pParse->nMem; + pMWin->csrApp = pParse->nTab++; + sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->csrApp, pMWin->iEphCsr); + return; } for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ @@ -144686,20 +147253,24 @@ SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){ else if( p->zName==nth_valueName || p->zName==first_valueName ){ /* Allocate two registers at pWin->regApp. These will be used to ** store the start and end index of the current frame. */ - assert( pMWin->iEphCsr ); pWin->regApp = pParse->nMem+1; pWin->csrApp = pParse->nTab++; pParse->nMem += 2; sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); } else if( p->zName==leadName || p->zName==lagName ){ - assert( pMWin->iEphCsr ); pWin->csrApp = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); } } } +#define WINDOW_STARTING_INT 0 +#define WINDOW_ENDING_INT 1 +#define WINDOW_NTH_VALUE_INT 2 +#define WINDOW_STARTING_NUM 3 +#define WINDOW_ENDING_NUM 4 + /* ** A "PRECEDING " (eCond==0) or "FOLLOWING " (eCond==1) or the ** value of the second argument to nth_value() (eCond==2) has just been @@ -144707,25 +147278,43 @@ SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){ ** code to check that the value is a non-negative integer and throws an ** exception if it is not. */ -static void windowCheckIntValue(Parse *pParse, int reg, int eCond){ +static void windowCheckValue(Parse *pParse, int reg, int eCond){ static const char *azErr[] = { "frame starting offset must be a non-negative integer", "frame ending offset must be a non-negative integer", - "second argument to nth_value must be a positive integer" + "second argument to nth_value must be a positive integer", + "frame starting offset must be a non-negative number", + "frame ending offset must be a non-negative number", }; - static int aOp[] = { OP_Ge, OP_Ge, OP_Gt }; + static int aOp[] = { OP_Ge, OP_Ge, OP_Gt, OP_Ge, OP_Ge }; Vdbe *v = sqlite3GetVdbe(pParse); int regZero = sqlite3GetTempReg(pParse); - assert( eCond==0 || eCond==1 || eCond==2 ); + assert( eCond>=0 && eCond=WINDOW_STARTING_NUM ){ + int regString = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); + sqlite3VdbeAddOp3(v, OP_Ge, regString, sqlite3VdbeCurrentAddr(v)+2, reg); + sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC|SQLITE_JUMPIFNULL); + VdbeCoverage(v); + assert( eCond==3 || eCond==4 ); + VdbeCoverageIf(v, eCond==3); + VdbeCoverageIf(v, eCond==4); + }else{ + sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + assert( eCond==0 || eCond==1 || eCond==2 ); + VdbeCoverageIf(v, eCond==0); + VdbeCoverageIf(v, eCond==1); + VdbeCoverageIf(v, eCond==2); + } sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg); - VdbeCoverageNeverNullIf(v, eCond==0); - VdbeCoverageNeverNullIf(v, eCond==1); + VdbeCoverageNeverNullIf(v, eCond==0); /* NULL case captured by */ + VdbeCoverageNeverNullIf(v, eCond==1); /* the OP_MustBeInt */ VdbeCoverageNeverNullIf(v, eCond==2); + VdbeCoverageNeverNullIf(v, eCond==3); /* NULL case caught by */ + VdbeCoverageNeverNullIf(v, eCond==4); /* the OP_Ge */ + sqlite3MayAbort(pParse); sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort); sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC); sqlite3ReleaseTempReg(pParse, regZero); @@ -144764,37 +147353,28 @@ static void windowAggStep( Window *pMWin, /* Linked list of window functions */ int csr, /* Read arguments from this cursor */ int bInverse, /* True to invoke xInverse instead of xStep */ - int reg, /* Array of registers */ - int regPartSize /* Register containing size of partition */ + int reg /* Array of registers */ ){ Vdbe *v = sqlite3GetVdbe(pParse); Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ - int flags = pWin->pFunc->funcFlags; + FuncDef *pFunc = pWin->pFunc; int regArg; int nArg = windowArgCount(pWin); + int i; - if( csr>=0 ){ - int i; - for(i=0; izName!=nth_valueName ){ sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i); + }else{ + sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i); } - regArg = reg; - if( flags & SQLITE_FUNC_WINDOW_SIZE ){ - if( nArg==0 ){ - regArg = regPartSize; - }else{ - sqlite3VdbeAddOp2(v, OP_SCopy, regPartSize, reg+nArg); - } - nArg++; - } - }else{ - assert( !(flags & SQLITE_FUNC_WINDOW_SIZE) ); - regArg = reg + pWin->iArgCol; } + regArg = reg; - if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) - && pWin->eStart!=TK_UNBOUNDED + if( pMWin->regStartRowid==0 + && (pFunc->funcFlags & SQLITE_FUNC_MINMAX) + && (pWin->eStart!=TK_UNBOUNDED) ){ int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg); VdbeCoverage(v); @@ -144811,34 +147391,24 @@ static void windowAggStep( } sqlite3VdbeJumpHere(v, addrIsNull); }else if( pWin->regApp ){ - assert( pWin->pFunc->zName==nth_valueName - || pWin->pFunc->zName==first_valueName + assert( pFunc->zName==nth_valueName + || pFunc->zName==first_valueName ); assert( bInverse==0 || bInverse==1 ); sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1); - }else if( pWin->pFunc->zName==leadName - || pWin->pFunc->zName==lagName - ){ - /* no-op */ - }else{ + }else if( pFunc->xSFunc!=noopStepFunc ){ int addrIf = 0; if( pWin->pFilter ){ int regTmp; assert( nArg==0 || nArg==pWin->pOwner->x.pList->nExpr ); assert( nArg || pWin->pOwner->x.pList==0 ); - if( csr>0 ){ - regTmp = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); - }else{ - regTmp = regArg + nArg; - } + regTmp = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); VdbeCoverage(v); - if( csr>0 ){ - sqlite3ReleaseTempReg(pParse, regTmp); - } + sqlite3ReleaseTempReg(pParse, regTmp); } - if( pWin->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ + if( pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl; assert( nArg>0 ); pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr); @@ -144846,45 +147416,96 @@ static void windowAggStep( } sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep, bInverse, regArg, pWin->regAccum); - sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } } } +typedef struct WindowCodeArg WindowCodeArg; +typedef struct WindowCsrAndReg WindowCsrAndReg; +struct WindowCsrAndReg { + int csr; + int reg; +}; + +struct WindowCodeArg { + Parse *pParse; + Window *pMWin; + Vdbe *pVdbe; + int regGosub; + int addrGosub; + int regArg; + int eDelete; + + WindowCsrAndReg start; + WindowCsrAndReg current; + WindowCsrAndReg end; +}; + +/* +** Values that may be passed as the second argument to windowCodeOp(). +*/ +#define WINDOW_RETURN_ROW 1 +#define WINDOW_AGGINVERSE 2 +#define WINDOW_AGGSTEP 3 + /* -** Generate VM code to invoke either xValue() (bFinal==0) or xFinalize() -** (bFinal==1) for each window function in the linked list starting at +** Generate VM code to read the window frames peer values from cursor csr into +** an array of registers starting at reg. +*/ +static void windowReadPeerValues( + WindowCodeArg *p, + int csr, + int reg +){ + Window *pMWin = p->pMWin; + ExprList *pOrderBy = pMWin->pOrderBy; + if( pOrderBy ){ + Vdbe *v = sqlite3GetVdbe(p->pParse); + ExprList *pPart = pMWin->pPartition; + int iColOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0); + int i; + for(i=0; inExpr; i++){ + sqlite3VdbeAddOp3(v, OP_Column, csr, iColOff+i, reg+i); + } + } +} + +/* +** Generate VM code to invoke either xValue() (bFin==0) or xFinalize() +** (bFin==1) for each window function in the linked list starting at ** pMWin. Or, for built-in window-functions that do not use the standard ** API, generate the equivalent VM code. */ -static void windowAggFinal(Parse *pParse, Window *pMWin, int bFinal){ +static void windowAggFinal(WindowCodeArg *p, int bFin){ + Parse *pParse = p->pParse; + Window *pMWin = p->pMWin; Vdbe *v = sqlite3GetVdbe(pParse); Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ - if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) - && pWin->eStart!=TK_UNBOUNDED + if( pMWin->regStartRowid==0 + && (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) + && (pWin->eStart!=TK_UNBOUNDED) ){ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); sqlite3VdbeAddOp1(v, OP_Last, pWin->csrApp); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Column, pWin->csrApp, 0, pWin->regResult); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); - if( bFinal ){ - sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); - } }else if( pWin->regApp ){ + assert( pMWin->regStartRowid==0 ); }else{ - if( bFinal ){ - sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, windowArgCount(pWin)); + int nArg = windowArgCount(pWin); + if( bFin ){ + sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, nArg); sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); }else{ - sqlite3VdbeAddOp3(v, OP_AggValue, pWin->regAccum, windowArgCount(pWin), - pWin->regResult); + sqlite3VdbeAddOp3(v, OP_AggValue,pWin->regAccum,nArg,pWin->regResult); sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); } } @@ -144892,66 +147513,97 @@ static void windowAggFinal(Parse *pParse, Window *pMWin, int bFinal){ } /* -** This function generates VM code to invoke the sub-routine at address -** lblFlushPart once for each partition with the entire partition cached in -** the Window.iEphCsr temp table. +** Generate code to calculate the current values of all window functions in the +** p->pMWin list by doing a full scan of the current window frame. Store the +** results in the Window.regResult registers, ready to return the upper +** layer. */ -static void windowPartitionCache( - Parse *pParse, - Select *p, /* The rewritten SELECT statement */ - WhereInfo *pWInfo, /* WhereInfo to call WhereEnd() on */ - int regFlushPart, /* Register to use with Gosub lblFlushPart */ - int lblFlushPart, /* Subroutine to Gosub to */ - int *pRegSize /* OUT: Register containing partition size */ -){ - Window *pMWin = p->pWin; - Vdbe *v = sqlite3GetVdbe(pParse); - int iSubCsr = p->pSrc->a[0].iCursor; - int nSub = p->pSrc->a[0].pTab->nCol; - int k; +static void windowFullScan(WindowCodeArg *p){ + Window *pWin; + Parse *pParse = p->pParse; + Window *pMWin = p->pMWin; + Vdbe *v = p->pVdbe; - int reg = pParse->nMem+1; - int regRecord = reg+nSub; - int regRowid = regRecord+1; + int regCRowid = 0; /* Current rowid value */ + int regCPeer = 0; /* Current peer values */ + int regRowid = 0; /* AggStep rowid value */ + int regPeer = 0; /* AggStep peer values */ - *pRegSize = regRowid; - pParse->nMem += nSub + 2; + int nPeer; + int lblNext; + int lblBrk; + int addrNext; + int csr = pMWin->csrApp; - /* Load the column values for the row returned by the sub-select - ** into an array of registers starting at reg. */ - for(k=0; kpOrderBy ? pMWin->pOrderBy->nExpr : 0); + + lblNext = sqlite3VdbeMakeLabel(pParse); + lblBrk = sqlite3VdbeMakeLabel(pParse); + + regCRowid = sqlite3GetTempReg(pParse); + regRowid = sqlite3GetTempReg(pParse); + if( nPeer ){ + regCPeer = sqlite3GetTempRange(pParse, nPeer); + regPeer = sqlite3GetTempRange(pParse, nPeer); } - sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, nSub, regRecord); - /* Check if this is the start of a new partition. If so, call the - ** flush_partition sub-routine. */ - if( pMWin->pPartition ){ + sqlite3VdbeAddOp2(v, OP_Rowid, pMWin->iEphCsr, regCRowid); + windowReadPeerValues(p, pMWin->iEphCsr, regCPeer); + + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); + } + + sqlite3VdbeAddOp3(v, OP_SeekGE, csr, lblBrk, pMWin->regStartRowid); + VdbeCoverage(v); + addrNext = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_Rowid, csr, regRowid); + sqlite3VdbeAddOp3(v, OP_Gt, pMWin->regEndRowid, lblBrk, regRowid); + VdbeCoverageNeverNull(v); + + if( pMWin->eExclude==TK_CURRENT ){ + sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, lblNext, regRowid); + VdbeCoverageNeverNull(v); + }else if( pMWin->eExclude!=TK_NO ){ int addr; - ExprList *pPart = pMWin->pPartition; - int nPart = pPart->nExpr; - int regNewPart = reg + pMWin->nBufferCol; - KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); + int addrEq = 0; + KeyInfo *pKeyInfo = 0; - addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart); - sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); - sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2); - VdbeCoverageEqNe(v); - sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1); - sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart); - VdbeComment((v, "call flush_partition")); + if( pMWin->pOrderBy ){ + pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pMWin->pOrderBy, 0, 0); + } + if( pMWin->eExclude==TK_TIES ){ + addrEq = sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, 0, regRowid); + VdbeCoverageNeverNull(v); + } + if( pKeyInfo ){ + windowReadPeerValues(p, csr, regPeer); + sqlite3VdbeAddOp3(v, OP_Compare, regPeer, regCPeer, nPeer); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + addr = sqlite3VdbeCurrentAddr(v)+1; + sqlite3VdbeAddOp3(v, OP_Jump, addr, lblNext, addr); + VdbeCoverageEqNe(v); + }else{ + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblNext); + } + if( addrEq ) sqlite3VdbeJumpHere(v, addrEq); } - /* Buffer the current row in the ephemeral table. */ - sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid); + windowAggStep(pParse, pMWin, csr, 0, p->regArg); - /* End of the input loop */ - sqlite3WhereEnd(pWInfo); + sqlite3VdbeResolveLabel(v, lblNext); + sqlite3VdbeAddOp2(v, OP_Next, csr, addrNext); + VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addrNext-1); + sqlite3VdbeJumpHere(v, addrNext+1); + sqlite3ReleaseTempReg(pParse, regRowid); + sqlite3ReleaseTempReg(pParse, regCRowid); + if( nPeer ){ + sqlite3ReleaseTempRange(pParse, regPeer, nPeer); + sqlite3ReleaseTempRange(pParse, regCPeer, nPeer); + } - /* Invoke "flush_partition" to deal with the final (or only) partition */ - sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart); - VdbeComment((v, "call flush_partition")); + windowAggFinal(p, 1); } /* @@ -144967,110 +147619,74 @@ static void windowPartitionCache( ** lag() ** lead() */ -static void windowReturnOneRow( - Parse *pParse, - Window *pMWin, - int regGosub, - int addrGosub -){ - Vdbe *v = sqlite3GetVdbe(pParse); - Window *pWin; - for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ - FuncDef *pFunc = pWin->pFunc; - if( pFunc->zName==nth_valueName - || pFunc->zName==first_valueName - ){ - int csr = pWin->csrApp; - int lbl = sqlite3VdbeMakeLabel(v); - int tmpReg = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); +static void windowReturnOneRow(WindowCodeArg *p){ + Window *pMWin = p->pMWin; + Vdbe *v = p->pVdbe; - if( pFunc->zName==nth_valueName ){ - sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+1,tmpReg); - windowCheckIntValue(pParse, tmpReg, 2); - }else{ - sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); - } - sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg); - sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg); - VdbeCoverageNeverNull(v); - sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg); - VdbeCoverageNeverTaken(v); - sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); - sqlite3VdbeResolveLabel(v, lbl); - sqlite3ReleaseTempReg(pParse, tmpReg); - } - else if( pFunc->zName==leadName || pFunc->zName==lagName ){ - int nArg = pWin->pOwner->x.pList->nExpr; - int iEph = pMWin->iEphCsr; - int csr = pWin->csrApp; - int lbl = sqlite3VdbeMakeLabel(v); - int tmpReg = sqlite3GetTempReg(pParse); - - if( nArg<3 ){ + if( pMWin->regStartRowid ){ + windowFullScan(p); + }else{ + Parse *pParse = p->pParse; + Window *pWin; + + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *pFunc = pWin->pFunc; + if( pFunc->zName==nth_valueName + || pFunc->zName==first_valueName + ){ + int csr = pWin->csrApp; + int lbl = sqlite3VdbeMakeLabel(pParse); + int tmpReg = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); - }else{ - sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+2, pWin->regResult); - } - sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg); - if( nArg<2 ){ - int val = (pFunc->zName==leadName ? 1 : -1); - sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val); - }else{ - int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract); - int tmpReg2 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2); - sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg); - sqlite3ReleaseTempReg(pParse, tmpReg2); + + if( pFunc->zName==nth_valueName ){ + sqlite3VdbeAddOp3(v, OP_Column,pMWin->iEphCsr,pWin->iArgCol+1,tmpReg); + windowCheckValue(pParse, tmpReg, 2); + }else{ + sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); + } + sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg); + sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg); + VdbeCoverageNeverNull(v); + sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg); + VdbeCoverageNeverTaken(v); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); + sqlite3VdbeResolveLabel(v, lbl); + sqlite3ReleaseTempReg(pParse, tmpReg); + } + else if( pFunc->zName==leadName || pFunc->zName==lagName ){ + int nArg = pWin->pOwner->x.pList->nExpr; + int csr = pWin->csrApp; + int lbl = sqlite3VdbeMakeLabel(pParse); + int tmpReg = sqlite3GetTempReg(pParse); + int iEph = pMWin->iEphCsr; + + if( nArg<3 ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); + }else{ + sqlite3VdbeAddOp3(v, OP_Column, iEph,pWin->iArgCol+2,pWin->regResult); + } + sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg); + if( nArg<2 ){ + int val = (pFunc->zName==leadName ? 1 : -1); + sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val); + }else{ + int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract); + int tmpReg2 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2); + sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg); + sqlite3ReleaseTempReg(pParse, tmpReg2); + } + + sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); + sqlite3VdbeResolveLabel(v, lbl); + sqlite3ReleaseTempReg(pParse, tmpReg); } - - sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); - sqlite3VdbeResolveLabel(v, lbl); - sqlite3ReleaseTempReg(pParse, tmpReg); } } - sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub); -} - -/* -** Invoke the code generated by windowReturnOneRow() and, optionally, the -** xInverse() function for each window function, for one or more rows -** from the Window.iEphCsr temp table. This routine generates VM code -** similar to: -** -** while( regCtr>0 ){ -** regCtr--; -** windowReturnOneRow() -** if( bInverse ){ -** AggInverse -** } -** Next (Window.iEphCsr) -** } -*/ -static void windowReturnRows( - Parse *pParse, - Window *pMWin, /* List of window functions */ - int regCtr, /* Register containing number of rows */ - int regGosub, /* Register for Gosub addrGosub */ - int addrGosub, /* Address of sub-routine for ReturnOneRow */ - int regInvArg, /* Array of registers for xInverse args */ - int regInvSize /* Register containing size of partition */ -){ - int addr; - Vdbe *v = sqlite3GetVdbe(pParse); - windowAggFinal(pParse, pMWin, 0); - addr = sqlite3VdbeAddOp3(v, OP_IfPos, regCtr, sqlite3VdbeCurrentAddr(v)+2 ,1); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Goto, 0, 0); - windowReturnOneRow(pParse, pMWin, regGosub, addrGosub); - if( regInvArg ){ - windowAggStep(pParse, pMWin, pMWin->iEphCsr, 1, regInvArg, regInvSize); - } - sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, addr); - VdbeCoverage(v); - sqlite3VdbeJumpHere(v, addr+1); /* The OP_Goto */ + sqlite3VdbeAddOp2(v, OP_Gosub, p->regGosub, p->addrGosub); } /* @@ -145088,17 +147704,17 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){ FuncDef *pFunc = pWin->pFunc; sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); nArg = MAX(nArg, windowArgCount(pWin)); - if( pFunc->zName==nth_valueName - || pFunc->zName==first_valueName - ){ - sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp); - sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); - } + if( pMWin->regStartRowid==0 ){ + if( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ){ + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); + } - if( (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->csrApp ){ - assert( pWin->eStart!=TK_UNBOUNDED ); - sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); - sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); + if( (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->csrApp ){ + assert( pWin->eStart!=TK_UNBOUNDED ); + sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); + } } } regArg = pParse->nMem+1; @@ -145106,672 +147722,248 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){ return regArg; } +/* +** Return true if the current frame should be cached in the ephemeral table, +** even if there are no xInverse() calls required. +*/ +static int windowCacheFrame(Window *pMWin){ + Window *pWin; + if( pMWin->regStartRowid ) return 1; + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *pFunc = pWin->pFunc; + if( (pFunc->zName==nth_valueName) + || (pFunc->zName==first_valueName) + || (pFunc->zName==leadName) + || (pFunc->zName==lagName) + ){ + return 1; + } + } + return 0; +} /* -** This function does the work of sqlite3WindowCodeStep() for all "ROWS" -** window frame types except for "BETWEEN UNBOUNDED PRECEDING AND CURRENT -** ROW". Pseudo-code for each follows. -** -** ROWS BETWEEN PRECEDING AND FOLLOWING -** -** ... -** if( new partition ){ -** Gosub flush_partition -** } -** Insert (record in eph-table) -** sqlite3WhereEnd() -** Gosub flush_partition -** -** flush_partition: -** Once { -** OpenDup (iEphCsr -> csrStart) -** OpenDup (iEphCsr -> csrEnd) -** } -** regStart = // PRECEDING expression -** regEnd = // FOLLOWING expression -** if( regStart<0 || regEnd<0 ){ error! } -** Rewind (csr,csrStart,csrEnd) // if EOF goto flush_partition_done -** Next(csrEnd) // if EOF skip Aggstep -** Aggstep (csrEnd) -** if( (regEnd--)<=0 ){ -** AggFinal (xValue) -** Gosub addrGosub -** Next(csr) // if EOF goto flush_partition_done -** if( (regStart--)<=0 ){ -** AggInverse (csrStart) -** Next(csrStart) -** } -** } -** flush_partition_done: -** ResetSorter (csr) -** Return -** -** ROWS BETWEEN PRECEDING AND CURRENT ROW -** ROWS BETWEEN CURRENT ROW AND FOLLOWING -** ROWS BETWEEN UNBOUNDED PRECEDING AND FOLLOWING -** -** These are similar to the above. For "CURRENT ROW", intialize the -** register to 0. For "UNBOUNDED PRECEDING" to infinity. -** -** ROWS BETWEEN PRECEDING AND UNBOUNDED FOLLOWING -** ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING -** -** Rewind (csr,csrStart,csrEnd) // if EOF goto flush_partition_done -** while( 1 ){ -** Next(csrEnd) // Exit while(1) at EOF -** Aggstep (csrEnd) -** } -** while( 1 ){ -** AggFinal (xValue) -** Gosub addrGosub -** Next(csr) // if EOF goto flush_partition_done -** if( (regStart--)<=0 ){ -** AggInverse (csrStart) -** Next(csrStart) -** } -** } -** -** For the "CURRENT ROW AND UNBOUNDED FOLLOWING" case, the final if() -** condition is always true (as if regStart were initialized to 0). -** -** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING -** -** This is the only RANGE case handled by this routine. It modifies the -** second while( 1 ) loop in "ROWS BETWEEN CURRENT ... UNBOUNDED..." to -** be: -** -** while( 1 ){ -** AggFinal (xValue) -** while( 1 ){ -** regPeer++ -** Gosub addrGosub -** Next(csr) // if EOF goto flush_partition_done -** if( new peer ) break; -** } -** while( (regPeer--)>0 ){ -** AggInverse (csrStart) -** Next(csrStart) -** } -** } -** -** ROWS BETWEEN FOLLOWING AND FOLLOWING -** -** regEnd = regEnd - regStart -** Rewind (csr,csrStart,csrEnd) // if EOF goto flush_partition_done -** Aggstep (csrEnd) -** Next(csrEnd) // if EOF fall-through -** if( (regEnd--)<=0 ){ -** if( (regStart--)<=0 ){ -** AggFinal (xValue) -** Gosub addrGosub -** Next(csr) // if EOF goto flush_partition_done -** } -** AggInverse (csrStart) -** Next (csrStart) -** } -** -** ROWS BETWEEN PRECEDING AND PRECEDING -** -** Replace the bit after "Rewind" in the above with: -** -** if( (regEnd--)<=0 ){ -** AggStep (csrEnd) -** Next (csrEnd) -** } -** AggFinal (xValue) -** Gosub addrGosub -** Next(csr) // if EOF goto flush_partition_done -** if( (regStart--)<=0 ){ -** AggInverse (csr2) -** Next (csr2) -** } +** regOld and regNew are each the first register in an array of size +** pOrderBy->nExpr. This function generates code to compare the two +** arrays of registers using the collation sequences and other comparison +** parameters specified by pOrderBy. ** +** If the two arrays are not equal, the contents of regNew is copied to +** regOld and control falls through. Otherwise, if the contents of the arrays +** are equal, an OP_Goto is executed. The address of the OP_Goto is returned. */ -static void windowCodeRowExprStep( - Parse *pParse, - Select *p, - WhereInfo *pWInfo, - int regGosub, - int addrGosub +static void windowIfNewPeer( + Parse *pParse, + ExprList *pOrderBy, + int regNew, /* First in array of new values */ + int regOld, /* First in array of old values */ + int addr /* Jump here */ ){ - Window *pMWin = p->pWin; Vdbe *v = sqlite3GetVdbe(pParse); - int regFlushPart; /* Register for "Gosub flush_partition" */ - int lblFlushPart; /* Label for "Gosub flush_partition" */ - int lblFlushDone; /* Label for "Gosub flush_partition_done" */ - - int regArg; - int addr; - int csrStart = pParse->nTab++; - int csrEnd = pParse->nTab++; - int regStart; /* Value of PRECEDING */ - int regEnd; /* Value of FOLLOWING */ - int addrGoto; - int addrTop; - int addrIfPos1 = 0; - int addrIfPos2 = 0; - int regSize = 0; - - assert( pMWin->eStart==TK_PRECEDING - || pMWin->eStart==TK_CURRENT - || pMWin->eStart==TK_FOLLOWING - || pMWin->eStart==TK_UNBOUNDED - ); - assert( pMWin->eEnd==TK_FOLLOWING - || pMWin->eEnd==TK_CURRENT - || pMWin->eEnd==TK_UNBOUNDED - || pMWin->eEnd==TK_PRECEDING - ); - - /* Allocate register and label for the "flush_partition" sub-routine. */ - regFlushPart = ++pParse->nMem; - lblFlushPart = sqlite3VdbeMakeLabel(v); - lblFlushDone = sqlite3VdbeMakeLabel(v); - - regStart = ++pParse->nMem; - regEnd = ++pParse->nMem; - - windowPartitionCache(pParse, p, pWInfo, regFlushPart, lblFlushPart, ®Size); - - addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); - - /* Start of "flush_partition" */ - sqlite3VdbeResolveLabel(v, lblFlushPart); - sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3); - VdbeCoverage(v); - VdbeComment((v, "Flush_partition subroutine")); - sqlite3VdbeAddOp2(v, OP_OpenDup, csrStart, pMWin->iEphCsr); - sqlite3VdbeAddOp2(v, OP_OpenDup, csrEnd, pMWin->iEphCsr); - - /* If either regStart or regEnd are not non-negative integers, throw - ** an exception. */ - if( pMWin->pStart ){ - sqlite3ExprCode(pParse, pMWin->pStart, regStart); - windowCheckIntValue(pParse, regStart, 0); - } - if( pMWin->pEnd ){ - sqlite3ExprCode(pParse, pMWin->pEnd, regEnd); - windowCheckIntValue(pParse, regEnd, 1); - } - - /* If this is "ROWS FOLLOWING AND ROWS FOLLOWING", do: - ** - ** if( regEndpEnd && pMWin->eStart==TK_FOLLOWING ){ - assert( pMWin->pStart!=0 ); - assert( pMWin->eEnd==TK_FOLLOWING ); - sqlite3VdbeAddOp3(v, OP_Ge, regStart, sqlite3VdbeCurrentAddr(v)+2, regEnd); - VdbeCoverageNeverNull(v); - sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart); - sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regEnd); - } - - if( pMWin->pStart && pMWin->eEnd==TK_PRECEDING ){ - assert( pMWin->pEnd!=0 ); - assert( pMWin->eStart==TK_PRECEDING ); - sqlite3VdbeAddOp3(v, OP_Le, regStart, sqlite3VdbeCurrentAddr(v)+3, regEnd); - VdbeCoverageNeverNull(v); - sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart); - sqlite3VdbeAddOp2(v, OP_Copy, regSize, regEnd); - } - - /* Initialize the accumulator register for each window function to NULL */ - regArg = windowInitAccum(pParse, pMWin); - - sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, lblFlushDone); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, csrStart, lblFlushDone); - VdbeCoverageNeverTaken(v); - sqlite3VdbeChangeP5(v, 1); - sqlite3VdbeAddOp2(v, OP_Rewind, csrEnd, lblFlushDone); - VdbeCoverageNeverTaken(v); - sqlite3VdbeChangeP5(v, 1); - - /* Invoke AggStep function for each window function using the row that - ** csrEnd currently points to. Or, if csrEnd is already at EOF, - ** do nothing. */ - addrTop = sqlite3VdbeCurrentAddr(v); - if( pMWin->eEnd==TK_PRECEDING ){ - addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1); - VdbeCoverage(v); - } - sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - addr = sqlite3VdbeAddOp0(v, OP_Goto); - windowAggStep(pParse, pMWin, csrEnd, 0, regArg, regSize); - if( pMWin->eEnd==TK_UNBOUNDED ){ - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop); - sqlite3VdbeJumpHere(v, addr); - addrTop = sqlite3VdbeCurrentAddr(v); + if( pOrderBy ){ + int nVal = pOrderBy->nExpr; + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0); + sqlite3VdbeAddOp3(v, OP_Compare, regOld, regNew, nVal); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + sqlite3VdbeAddOp3(v, OP_Jump, + sqlite3VdbeCurrentAddr(v)+1, addr, sqlite3VdbeCurrentAddr(v)+1 + ); + VdbeCoverageEqNe(v); + sqlite3VdbeAddOp3(v, OP_Copy, regNew, regOld, nVal-1); }else{ - sqlite3VdbeJumpHere(v, addr); - if( pMWin->eEnd==TK_PRECEDING ){ - sqlite3VdbeJumpHere(v, addrIfPos1); - } - } - - if( pMWin->eEnd==TK_FOLLOWING ){ - addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1); - VdbeCoverage(v); - } - if( pMWin->eStart==TK_FOLLOWING ){ - addrIfPos2 = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0 , 1); - VdbeCoverage(v); - } - windowAggFinal(pParse, pMWin, 0); - windowReturnOneRow(pParse, pMWin, regGosub, addrGosub); - sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Goto, 0, lblFlushDone); - if( pMWin->eStart==TK_FOLLOWING ){ - sqlite3VdbeJumpHere(v, addrIfPos2); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); } - - if( pMWin->eStart==TK_CURRENT - || pMWin->eStart==TK_PRECEDING - || pMWin->eStart==TK_FOLLOWING - ){ - int lblSkipInverse = sqlite3VdbeMakeLabel(v);; - if( pMWin->eStart==TK_PRECEDING ){ - sqlite3VdbeAddOp3(v, OP_IfPos, regStart, lblSkipInverse, 1); - VdbeCoverage(v); - } - if( pMWin->eStart==TK_FOLLOWING ){ - sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Goto, 0, lblSkipInverse); - }else{ - sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1); - VdbeCoverageAlwaysTaken(v); - } - windowAggStep(pParse, pMWin, csrStart, 1, regArg, regSize); - sqlite3VdbeResolveLabel(v, lblSkipInverse); - } - if( pMWin->eEnd==TK_FOLLOWING ){ - sqlite3VdbeJumpHere(v, addrIfPos1); - } - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop); - - /* flush_partition_done: */ - sqlite3VdbeResolveLabel(v, lblFlushDone); - sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr); - sqlite3VdbeAddOp1(v, OP_Return, regFlushPart); - VdbeComment((v, "end flush_partition subroutine")); - - /* Jump to here to skip over flush_partition */ - sqlite3VdbeJumpHere(v, addrGoto); } /* -** This function does the work of sqlite3WindowCodeStep() for cases that -** would normally be handled by windowCodeDefaultStep() when there are -** one or more built-in window-functions that require the entire partition -** to be cached in a temp table before any rows can be returned. Additionally. -** "RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING" is always handled by -** this function. -** -** Pseudo-code corresponding to the VM code generated by this function -** for each type of window follows. -** -** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -** -** flush_partition: -** Once { -** OpenDup (iEphCsr -> csrLead) -** } -** Integer ctr 0 -** foreach row (csrLead){ -** if( new peer ){ -** AggFinal (xValue) -** for(i=0; i= csr2.peerVal ) goto lbl; ** -** flush_partition: -** Once { -** OpenDup (iEphCsr -> csrLead) -** } -** foreach row (csrLead) { -** AggStep (csrLead) -** } -** foreach row (iEphCsr) { -** Gosub addrGosub -** } -** -** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING -** -** flush_partition: -** Once { -** OpenDup (iEphCsr -> csrLead) -** } -** foreach row (csrLead){ -** AggStep (csrLead) -** } -** Rewind (csrLead) -** Integer ctr 0 -** foreach row (csrLead){ -** if( new peer ){ -** AggFinal (xValue) -** for(i=0; ipWin; + Parse *pParse = p->pParse; Vdbe *v = sqlite3GetVdbe(pParse); - int k; - int addr; - ExprList *pPart = pMWin->pPartition; - ExprList *pOrderBy = pMWin->pOrderBy; - int nPeer = pOrderBy ? pOrderBy->nExpr : 0; - int regNewPeer; - - int addrGoto; /* Address of Goto used to jump flush_par.. */ - int addrNext; /* Jump here for next iteration of loop */ - int regFlushPart; - int lblFlushPart; - int csrLead; - int regCtr; - int regArg; /* Register array to martial function args */ - int regSize; - int lblEmpty; - int bReverse = pMWin->pOrderBy && pMWin->eStart==TK_CURRENT - && pMWin->eEnd==TK_UNBOUNDED; - - assert( (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT) - || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_UNBOUNDED) - || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_CURRENT) - || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED) - ); - - lblEmpty = sqlite3VdbeMakeLabel(v); - regNewPeer = pParse->nMem+1; - pParse->nMem += nPeer; - - /* Allocate register and label for the "flush_partition" sub-routine. */ - regFlushPart = ++pParse->nMem; - lblFlushPart = sqlite3VdbeMakeLabel(v); - - csrLead = pParse->nTab++; - regCtr = ++pParse->nMem; - - windowPartitionCache(pParse, p, pWInfo, regFlushPart, lblFlushPart, ®Size); - addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); - - /* Start of "flush_partition" */ - sqlite3VdbeResolveLabel(v, lblFlushPart); - sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_OpenDup, csrLead, pMWin->iEphCsr); - - /* Initialize the accumulator register for each window function to NULL */ - regArg = windowInitAccum(pParse, pMWin); - - sqlite3VdbeAddOp2(v, OP_Integer, 0, regCtr); - sqlite3VdbeAddOp2(v, OP_Rewind, csrLead, lblEmpty); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, lblEmpty); - VdbeCoverageNeverTaken(v); + int reg1 = sqlite3GetTempReg(pParse); + int reg2 = sqlite3GetTempReg(pParse); + int arith = OP_Add; + int addrGe; - if( bReverse ){ - int addr2 = sqlite3VdbeCurrentAddr(v); - windowAggStep(pParse, pMWin, csrLead, 0, regArg, regSize); - sqlite3VdbeAddOp2(v, OP_Next, csrLead, addr2); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, csrLead, lblEmpty); - VdbeCoverageNeverTaken(v); - } - addrNext = sqlite3VdbeCurrentAddr(v); + int regString = ++pParse->nMem; - if( pOrderBy && (pMWin->eEnd==TK_CURRENT || pMWin->eStart==TK_CURRENT) ){ - int bCurrent = (pMWin->eStart==TK_CURRENT); - int addrJump = 0; /* Address of OP_Jump below */ - if( pMWin->eType==TK_RANGE ){ - int iOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0); - int regPeer = pMWin->regPart + (pPart ? pPart->nExpr : 0); - KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0); - for(k=0; kpMWin->pOrderBy && p->pMWin->pOrderBy->nExpr==1 ); + if( p->pMWin->pOrderBy->a[0].sortOrder ){ + switch( op ){ + case OP_Ge: op = OP_Le; break; + case OP_Gt: op = OP_Lt; break; + default: assert( op==OP_Le ); op = OP_Ge; break; } - - windowReturnRows(pParse, pMWin, regCtr, regGosub, addrGosub, - (bCurrent ? regArg : 0), (bCurrent ? regSize : 0) - ); - if( addrJump ) sqlite3VdbeJumpHere(v, addrJump); + arith = OP_Subtract; } - if( bReverse==0 ){ - windowAggStep(pParse, pMWin, csrLead, 0, regArg, regSize); - } - sqlite3VdbeAddOp2(v, OP_AddImm, regCtr, 1); - sqlite3VdbeAddOp2(v, OP_Next, csrLead, addrNext); - VdbeCoverage(v); + windowReadPeerValues(p, csr1, reg1); + windowReadPeerValues(p, csr2, reg2); - windowReturnRows(pParse, pMWin, regCtr, regGosub, addrGosub, 0, 0); - - sqlite3VdbeResolveLabel(v, lblEmpty); - sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr); - sqlite3VdbeAddOp1(v, OP_Return, regFlushPart); + /* Check if the peer value for csr1 value is a text or blob by comparing + ** it to the smallest possible string - ''. If it is, jump over the + ** OP_Add or OP_Subtract operation and proceed directly to the comparison. */ + sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); + addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1); + sqlite3VdbeJumpHere(v, addrGe); + sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le ); + testcase(op==OP_Ge); VdbeCoverageIf(v, op==OP_Ge); + testcase(op==OP_Lt); VdbeCoverageIf(v, op==OP_Lt); + testcase(op==OP_Le); VdbeCoverageIf(v, op==OP_Le); + testcase(op==OP_Gt); VdbeCoverageIf(v, op==OP_Gt); - /* Jump to here to skip over flush_partition */ - sqlite3VdbeJumpHere(v, addrGoto); + sqlite3ReleaseTempReg(pParse, reg1); + sqlite3ReleaseTempReg(pParse, reg2); } - /* -** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -** -** ... -** if( new partition ){ -** AggFinal (xFinalize) -** Gosub addrGosub -** ResetSorter eph-table -** } -** else if( new peer ){ -** AggFinal (xValue) -** Gosub addrGosub -** ResetSorter eph-table -** } -** AggStep -** Insert (record into eph-table) -** sqlite3WhereEnd() -** AggFinal (xFinalize) -** Gosub addrGosub -** -** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING -** -** As above, except take no action for a "new peer". Invoke -** the sub-routine once only for each partition. -** -** RANGE BETWEEN CURRENT ROW AND CURRENT ROW -** -** As above, except that the "new peer" condition is handled in the -** same way as "new partition" (so there is no "else if" block). -** -** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -** -** As above, except assume every row is a "new peer". +** Helper function for sqlite3WindowCodeStep(). Each call to this function +** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE +** operation. Refer to the header comment for sqlite3WindowCodeStep() for +** details. */ -static void windowCodeDefaultStep( - Parse *pParse, - Select *p, - WhereInfo *pWInfo, - int regGosub, - int addrGosub +static int windowCodeOp( + WindowCodeArg *p, /* Context object */ + int op, /* WINDOW_RETURN_ROW, AGGSTEP or AGGINVERSE */ + int regCountdown, /* Register for OP_IfPos countdown */ + int jumpOnEof /* Jump here if stepped cursor reaches EOF */ ){ - Window *pMWin = p->pWin; - Vdbe *v = sqlite3GetVdbe(pParse); - int k; - int iSubCsr = p->pSrc->a[0].iCursor; - int nSub = p->pSrc->a[0].pTab->nCol; - int reg = pParse->nMem+1; - int regRecord = reg+nSub; - int regRowid = regRecord+1; - int addr; - ExprList *pPart = pMWin->pPartition; - ExprList *pOrderBy = pMWin->pOrderBy; - - assert( pMWin->eType==TK_RANGE - || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT) - ); - - assert( (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT) - || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_UNBOUNDED) - || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_CURRENT) - || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED && !pOrderBy) - ); - - if( pMWin->eEnd==TK_UNBOUNDED ){ - pOrderBy = 0; - } - - pParse->nMem += nSub + 2; - - /* Load the individual column values of the row returned by - ** the sub-select into an array of registers. */ - for(k=0; kpParse; + Window *pMWin = p->pMWin; + int ret = 0; + Vdbe *v = p->pVdbe; + int addrIf = 0; + int addrContinue = 0; + int addrGoto = 0; + int bPeer = (pMWin->eFrmType!=TK_ROWS); + + int lblDone = sqlite3VdbeMakeLabel(pParse); + int addrNextRange = 0; + + /* Special case - WINDOW_AGGINVERSE is always a no-op if the frame + ** starts with UNBOUNDED PRECEDING. */ + if( op==WINDOW_AGGINVERSE && pMWin->eStart==TK_UNBOUNDED ){ + assert( regCountdown==0 && jumpOnEof==0 ); + return 0; } - /* Check if this is the start of a new partition or peer group. */ - if( pPart || pOrderBy ){ - int nPart = (pPart ? pPart->nExpr : 0); - int addrGoto = 0; - int addrJump = 0; - int nPeer = (pOrderBy ? pOrderBy->nExpr : 0); - - if( pPart ){ - int regNewPart = reg + pMWin->nBufferCol; - KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); - addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart); - sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); - addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2); - VdbeCoverageEqNe(v); - windowAggFinal(pParse, pMWin, 1); - if( pOrderBy ){ - addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); + if( regCountdown>0 ){ + if( pMWin->eFrmType==TK_RANGE ){ + addrNextRange = sqlite3VdbeCurrentAddr(v); + assert( op==WINDOW_AGGINVERSE || op==WINDOW_AGGSTEP ); + if( op==WINDOW_AGGINVERSE ){ + if( pMWin->eStart==TK_FOLLOWING ){ + windowCodeRangeTest( + p, OP_Le, p->current.csr, regCountdown, p->start.csr, lblDone + ); + }else{ + windowCodeRangeTest( + p, OP_Ge, p->start.csr, regCountdown, p->current.csr, lblDone + ); + } + }else{ + windowCodeRangeTest( + p, OP_Gt, p->end.csr, regCountdown, p->current.csr, lblDone + ); } + }else{ + addrIf = sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, 0, 1); + VdbeCoverage(v); } + } - if( pOrderBy ){ - int regNewPeer = reg + pMWin->nBufferCol + nPart; - int regPeer = pMWin->regPart + nPart; + if( op==WINDOW_RETURN_ROW && pMWin->regStartRowid==0 ){ + windowAggFinal(p, 0); + } + addrContinue = sqlite3VdbeCurrentAddr(v); + switch( op ){ + case WINDOW_RETURN_ROW: + csr = p->current.csr; + reg = p->current.reg; + windowReturnOneRow(p); + break; - if( addrJump ) sqlite3VdbeJumpHere(v, addrJump); - if( pMWin->eType==TK_RANGE ){ - KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0); - addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer); - sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); - addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2); - VdbeCoverage(v); + case WINDOW_AGGINVERSE: + csr = p->start.csr; + reg = p->start.reg; + if( pMWin->regStartRowid ){ + assert( pMWin->regEndRowid ); + sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regStartRowid, 1); }else{ - addrJump = 0; + windowAggStep(pParse, pMWin, csr, 1, p->regArg); } - windowAggFinal(pParse, pMWin, pMWin->eStart==TK_CURRENT); - if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto); - } - - sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr,sqlite3VdbeCurrentAddr(v)+3); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub); - sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)-1); - VdbeCoverage(v); - - sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr); - sqlite3VdbeAddOp3( - v, OP_Copy, reg+pMWin->nBufferCol, pMWin->regPart, nPart+nPeer-1 - ); + break; - if( addrJump ) sqlite3VdbeJumpHere(v, addrJump); + default: + assert( op==WINDOW_AGGSTEP ); + csr = p->end.csr; + reg = p->end.reg; + if( pMWin->regStartRowid ){ + assert( pMWin->regEndRowid ); + sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regEndRowid, 1); + }else{ + windowAggStep(pParse, pMWin, csr, 0, p->regArg); + } + break; } - /* Invoke step function for window functions */ - windowAggStep(pParse, pMWin, -1, 0, reg, 0); + if( op==p->eDelete ){ + sqlite3VdbeAddOp1(v, OP_Delete, csr); + sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); + } - /* Buffer the current row in the ephemeral table. */ - if( pMWin->nBufferCol>0 ){ - sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, pMWin->nBufferCol, regRecord); + if( jumpOnEof ){ + sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + ret = sqlite3VdbeAddOp0(v, OP_Goto); }else{ - sqlite3VdbeAddOp2(v, OP_Blob, 0, regRecord); - sqlite3VdbeAppendP4(v, (void*)"", 0); + sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+1+bPeer); + VdbeCoverage(v); + if( bPeer ){ + addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); + } } - sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid); - /* End the database scan loop. */ - sqlite3WhereEnd(pWInfo); + if( bPeer ){ + int nReg = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); + int regTmp = (nReg ? sqlite3GetTempRange(pParse, nReg) : 0); + windowReadPeerValues(p, csr, regTmp); + windowIfNewPeer(pParse, pMWin->pOrderBy, regTmp, reg, addrContinue); + sqlite3ReleaseTempRange(pParse, regTmp, nReg); + } - windowAggFinal(pParse, pMWin, 1); - sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr,sqlite3VdbeCurrentAddr(v)+3); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub); - sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)-1); - VdbeCoverage(v); + if( addrNextRange ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNextRange); + } + sqlite3VdbeResolveLabel(v, lblDone); + if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto); + if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); + return ret; } + /* ** Allocate and return a duplicate of the Window object indicated by the ** third argument. Set the Window.pOwner field of the new object to @@ -145779,16 +147971,18 @@ static void windowCodeDefaultStep( */ SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){ Window *pNew = 0; - if( p ){ + if( ALWAYS(p) ){ pNew = sqlite3DbMallocZero(db, sizeof(Window)); if( pNew ){ pNew->zName = sqlite3DbStrDup(db, p->zName); pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0); + pNew->pFunc = p->pFunc; pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0); pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0); - pNew->eType = p->eType; + pNew->eFrmType = p->eFrmType; pNew->eEnd = p->eEnd; pNew->eStart = p->eStart; + pNew->eExclude = p->eExclude; pNew->pStart = sqlite3ExprDup(db, p->pStart, 0); pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0); pNew->pOwner = pOwner; @@ -145815,12 +148009,360 @@ SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p){ return pRet; } +/* +** Return true if it can be determined at compile time that expression +** pExpr evaluates to a value that, when cast to an integer, is greater +** than zero. False otherwise. +** +** If an OOM error occurs, this function sets the Parse.db.mallocFailed +** flag and returns zero. +*/ +static int windowExprGtZero(Parse *pParse, Expr *pExpr){ + int ret = 0; + sqlite3 *db = pParse->db; + sqlite3_value *pVal = 0; + sqlite3ValueFromExpr(db, pExpr, db->enc, SQLITE_AFF_NUMERIC, &pVal); + if( pVal && sqlite3_value_int(pVal)>0 ){ + ret = 1; + } + sqlite3ValueFree(pVal); + return ret; +} + /* ** sqlite3WhereBegin() has already been called for the SELECT statement ** passed as the second argument when this function is invoked. It generates -** code to populate the Window.regResult register for each window function and -** invoke the sub-routine at instruction addrGosub once for each row. -** This function calls sqlite3WhereEnd() before returning. +** code to populate the Window.regResult register for each window function +** and invoke the sub-routine at instruction addrGosub once for each row. +** sqlite3WhereEnd() is always called before returning. +** +** This function handles several different types of window frames, which +** require slightly different processing. The following pseudo code is +** used to implement window frames of the form: +** +** ROWS BETWEEN PRECEDING AND FOLLOWING +** +** Other window frame types use variants of the following: +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** +** if( first row of partition ){ +** // Rewind three cursors, all open on the eph table. +** Rewind(csrEnd); +** Rewind(csrStart); +** Rewind(csrCurrent); +** +** regEnd = // FOLLOWING expression +** regStart = // PRECEDING expression +** }else{ +** // First time this branch is taken, the eph table contains two +** // rows. The first row in the partition, which all three cursors +** // currently point to, and the following row. +** AGGSTEP +** if( (regEnd--)<=0 ){ +** RETURN_ROW +** if( (regStart--)<=0 ){ +** AGGINVERSE +** } +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** RETURN ROW +** if( csrCurrent is EOF ) break; +** if( (regStart--)<=0 ){ +** AggInverse(csrStart) +** Next(csrStart) +** } +** } +** +** The pseudo-code above uses the following shorthand: +** +** AGGSTEP: invoke the aggregate xStep() function for each window function +** with arguments read from the current row of cursor csrEnd, then +** step cursor csrEnd forward one row (i.e. sqlite3BtreeNext()). +** +** RETURN_ROW: return a row to the caller based on the contents of the +** current row of csrCurrent and the current state of all +** aggregates. Then step cursor csrCurrent forward one row. +** +** AGGINVERSE: invoke the aggregate xInverse() function for each window +** functions with arguments read from the current row of cursor +** csrStart. Then step csrStart forward one row. +** +** There are two other ROWS window frames that are handled significantly +** differently from the above - "BETWEEN PRECEDING AND PRECEDING" +** and "BETWEEN FOLLOWING AND FOLLOWING". These are special +** cases because they change the order in which the three cursors (csrStart, +** csrCurrent and csrEnd) iterate through the ephemeral table. Cases that +** use UNBOUNDED or CURRENT ROW are much simpler variations on one of these +** three. +** +** ROWS BETWEEN PRECEDING AND PRECEDING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** }else{ +** if( (regEnd--)<=0 ){ +** AGGSTEP +** } +** RETURN_ROW +** if( (regStart--)<=0 ){ +** AGGINVERSE +** } +** } +** } +** flush: +** if( (regEnd--)<=0 ){ +** AGGSTEP +** } +** RETURN_ROW +** +** +** ROWS BETWEEN FOLLOWING AND FOLLOWING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = regEnd - +** }else{ +** AGGSTEP +** if( (regEnd--)<=0 ){ +** RETURN_ROW +** } +** if( (regStart--)<=0 ){ +** AGGINVERSE +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** if( (regEnd--)<=0 ){ +** RETURN_ROW +** if( eof ) break; +** } +** if( (regStart--)<=0 ){ +** AGGINVERSE +** if( eof ) break +** } +** } +** while( !eof csrCurrent ){ +** RETURN_ROW +** } +** +** For the most part, the patterns above are adapted to support UNBOUNDED by +** assuming that it is equivalent to "infinity PRECEDING/FOLLOWING" and +** CURRENT ROW by assuming that it is equivilent to "0 PRECEDING/FOLLOWING". +** This is optimized of course - branches that will never be taken and +** conditions that are always true are omitted from the VM code. The only +** exceptional case is: +** +** ROWS BETWEEN FOLLOWING AND UNBOUNDED FOLLOWING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regStart = +** }else{ +** AGGSTEP +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** if( (regStart--)<=0 ){ +** AGGINVERSE +** if( eof ) break +** } +** RETURN_ROW +** } +** while( !eof csrCurrent ){ +** RETURN_ROW +** } +** +** Also requiring special handling are the cases: +** +** ROWS BETWEEN PRECEDING AND PRECEDING +** ROWS BETWEEN FOLLOWING AND FOLLOWING +** +** when (expr1 < expr2). This is detected at runtime, not by this function. +** To handle this case, the pseudo-code programs depicted above are modified +** slightly to be: +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** if( regEnd < regStart ){ +** RETURN_ROW +** delete eph table contents +** continue +** } +** ... +** +** The new "continue" statement in the above jumps to the next iteration +** of the outer loop - the one started by sqlite3WhereBegin(). +** +** The various GROUPS cases are implemented using the same patterns as +** ROWS. The VM code is modified slightly so that: +** +** 1. The else branch in the main loop is only taken if the row just +** added to the ephemeral table is the start of a new group. In +** other words, it becomes: +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** }else if( new group ){ +** ... +** } +** } +** +** 2. Instead of processing a single row, each RETURN_ROW, AGGSTEP or +** AGGINVERSE step processes the current row of the relevant cursor and +** all subsequent rows belonging to the same group. +** +** RANGE window frames are a little different again. As for GROUPS, the +** main loop runs once per group only. And RETURN_ROW, AGGSTEP and AGGINVERSE +** deal in groups instead of rows. As for ROWS and GROUPS, there are three +** basic cases: +** +** RANGE BETWEEN PRECEDING AND FOLLOWING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** }else{ +** AGGSTEP +** while( (csrCurrent.key + regEnd) < csrEnd.key ){ +** RETURN_ROW +** while( csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** RETURN ROW +** if( csrCurrent is EOF ) break; +** while( csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** } +** } +** +** In the above notation, "csr.key" means the current value of the ORDER BY +** expression (there is only ever 1 for a RANGE that uses an FOLLOWING +** or PRECEDING AND PRECEDING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** }else{ +** if( (csrEnd.key + regEnd) <= csrCurrent.key ){ +** AGGSTEP +** } +** while( (csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** RETURN_ROW +** } +** } +** flush: +** while( (csrEnd.key + regEnd) <= csrCurrent.key ){ +** AGGSTEP +** } +** while( (csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** RETURN_ROW +** +** RANGE BETWEEN FOLLOWING AND FOLLOWING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** }else{ +** AGGSTEP +** while( (csrCurrent.key + regEnd) < csrEnd.key ){ +** while( (csrCurrent.key + regStart) > csrStart.key ){ +** AGGINVERSE +** } +** RETURN_ROW +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** while( (csrCurrent.key + regStart) > csrStart.key ){ +** AGGINVERSE +** if( eof ) break "while( 1 )" loop. +** } +** RETURN_ROW +** } +** while( !eof csrCurrent ){ +** RETURN_ROW +** } +** +** The text above leaves out many details. Refer to the code and comments +** below for a more complete picture. */ SQLITE_PRIVATE void sqlite3WindowCodeStep( Parse *pParse, /* Parse context */ @@ -145830,75 +148372,321 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( int addrGosub /* OP_Gosub here to return each row */ ){ Window *pMWin = p->pWin; + ExprList *pOrderBy = pMWin->pOrderBy; + Vdbe *v = sqlite3GetVdbe(pParse); + int csrWrite; /* Cursor used to write to eph. table */ + int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */ + int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */ + int iInput; /* To iterate through sub cols */ + int addrNe; /* Address of OP_Ne */ + int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */ + int addrInteger = 0; /* Address of OP_Integer */ + int addrEmpty; /* Address of OP_Rewind in flush: */ + int regStart = 0; /* Value of PRECEDING */ + int regEnd = 0; /* Value of FOLLOWING */ + int regNew; /* Array of registers holding new input row */ + int regRecord; /* regNew array in record form */ + int regRowid; /* Rowid for regRecord in eph table */ + int regNewPeer = 0; /* Peer values for new row (part of regNew) */ + int regPeer = 0; /* Peer values for current row */ + int regFlushPart = 0; /* Register for "Gosub flush_partition" */ + WindowCodeArg s; /* Context object for sub-routines */ + int lblWhereEnd; /* Label just before sqlite3WhereEnd() code */ + + assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_CURRENT + || pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED + ); + assert( pMWin->eEnd==TK_FOLLOWING || pMWin->eEnd==TK_CURRENT + || pMWin->eEnd==TK_UNBOUNDED || pMWin->eEnd==TK_PRECEDING + ); + assert( pMWin->eExclude==0 || pMWin->eExclude==TK_CURRENT + || pMWin->eExclude==TK_GROUP || pMWin->eExclude==TK_TIES + || pMWin->eExclude==TK_NO + ); - /* There are three different functions that may be used to do the work - ** of this one, depending on the window frame and the specific built-in - ** window functions used (if any). - ** - ** windowCodeRowExprStep() handles all "ROWS" window frames, except for: - ** - ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW - ** - ** The exception is because windowCodeRowExprStep() implements all window - ** frame types by caching the entire partition in a temp table, and - ** "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW" is easy enough to - ** implement without such a cache. - ** - ** windowCodeCacheStep() is used for: - ** - ** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING - ** - ** It is also used for anything not handled by windowCodeRowExprStep() - ** that invokes a built-in window function that requires the entire - ** partition to be cached in a temp table before any rows are returned - ** (e.g. nth_value() or percent_rank()). - ** - ** Finally, assuming there is no built-in window function that requires - ** the partition to be cached, windowCodeDefaultStep() is used for: - ** - ** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW - ** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING - ** RANGE BETWEEN CURRENT ROW AND CURRENT ROW - ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW - ** - ** windowCodeDefaultStep() is the only one of the three functions that - ** does not cache each partition in a temp table before beginning to - ** return rows. - */ - if( pMWin->eType==TK_ROWS - && (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy) - ){ - VdbeModuleComment((pParse->pVdbe, "Begin RowExprStep()")); - windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub); - }else{ - Window *pWin; - int bCache = 0; /* True to use CacheStep() */ - - if( pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED ){ - bCache = 1; - }else{ - for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ - FuncDef *pFunc = pWin->pFunc; - if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE) - || (pFunc->zName==nth_valueName) - || (pFunc->zName==first_valueName) - || (pFunc->zName==leadName) - || (pFunc->zName==lagName) - ){ - bCache = 1; - break; + lblWhereEnd = sqlite3VdbeMakeLabel(pParse); + + /* Fill in the context object */ + memset(&s, 0, sizeof(WindowCodeArg)); + s.pParse = pParse; + s.pMWin = pMWin; + s.pVdbe = v; + s.regGosub = regGosub; + s.addrGosub = addrGosub; + s.current.csr = pMWin->iEphCsr; + csrWrite = s.current.csr+1; + s.start.csr = s.current.csr+2; + s.end.csr = s.current.csr+3; + + /* Figure out when rows may be deleted from the ephemeral table. There + ** are four options - they may never be deleted (eDelete==0), they may + ** be deleted as soon as they are no longer part of the window frame + ** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row + ** has been returned to the caller (WINDOW_RETURN_ROW), or they may + ** be deleted after they enter the frame (WINDOW_AGGSTEP). */ + switch( pMWin->eStart ){ + case TK_FOLLOWING: + if( pMWin->eFrmType!=TK_RANGE + && windowExprGtZero(pParse, pMWin->pStart) + ){ + s.eDelete = WINDOW_RETURN_ROW; + } + break; + case TK_UNBOUNDED: + if( windowCacheFrame(pMWin)==0 ){ + if( pMWin->eEnd==TK_PRECEDING ){ + if( pMWin->eFrmType!=TK_RANGE + && windowExprGtZero(pParse, pMWin->pEnd) + ){ + s.eDelete = WINDOW_AGGSTEP; + } + }else{ + s.eDelete = WINDOW_RETURN_ROW; } } + break; + default: + s.eDelete = WINDOW_AGGINVERSE; + break; + } + + /* Allocate registers for the array of values from the sub-query, the + ** samve values in record form, and the rowid used to insert said record + ** into the ephemeral table. */ + regNew = pParse->nMem+1; + pParse->nMem += nInput; + regRecord = ++pParse->nMem; + regRowid = ++pParse->nMem; + + /* If the window frame contains an " PRECEDING" or " FOLLOWING" + ** clause, allocate registers to store the results of evaluating each + ** . */ + if( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING ){ + regStart = ++pParse->nMem; + } + if( pMWin->eEnd==TK_PRECEDING || pMWin->eEnd==TK_FOLLOWING ){ + regEnd = ++pParse->nMem; + } + + /* If this is not a "ROWS BETWEEN ..." frame, then allocate arrays of + ** registers to store copies of the ORDER BY expressions (peer values) + ** for the main loop, and for each cursor (start, current and end). */ + if( pMWin->eFrmType!=TK_ROWS ){ + int nPeer = (pOrderBy ? pOrderBy->nExpr : 0); + regNewPeer = regNew + pMWin->nBufferCol; + if( pMWin->pPartition ) regNewPeer += pMWin->pPartition->nExpr; + regPeer = pParse->nMem+1; pParse->nMem += nPeer; + s.start.reg = pParse->nMem+1; pParse->nMem += nPeer; + s.current.reg = pParse->nMem+1; pParse->nMem += nPeer; + s.end.reg = pParse->nMem+1; pParse->nMem += nPeer; + } + + /* Load the column values for the row returned by the sub-select + ** into an array of registers starting at regNew. Assemble them into + ** a record in register regRecord. */ + for(iInput=0; iInputpPartition ){ + int addr; + ExprList *pPart = pMWin->pPartition; + int nPart = pPart->nExpr; + int regNewPart = regNew + pMWin->nBufferCol; + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); + + regFlushPart = ++pParse->nMem; + addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart, nPart); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2); + VdbeCoverageEqNe(v); + addrGosubFlush = sqlite3VdbeAddOp1(v, OP_Gosub, regFlushPart); + VdbeComment((v, "call flush_partition")); + sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1); + } + + /* Insert the new row into the ephemeral table */ + sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, regRowid); + addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, regRowid); + VdbeCoverageNeverNull(v); + + /* This block is run for the first row of each partition */ + s.regArg = windowInitAccum(pParse, pMWin); + + if( regStart ){ + sqlite3ExprCode(pParse, pMWin->pStart, regStart); + windowCheckValue(pParse, regStart, 0 + (pMWin->eFrmType==TK_RANGE ? 3 : 0)); + } + if( regEnd ){ + sqlite3ExprCode(pParse, pMWin->pEnd, regEnd); + windowCheckValue(pParse, regEnd, 1 + (pMWin->eFrmType==TK_RANGE ? 3 : 0)); + } + + if( pMWin->eStart==pMWin->eEnd && regStart ){ + int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le); + int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd); + VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound */ + VdbeCoverageNeverNullIf(v, op==OP_Le); /* values previously checked */ + windowAggFinal(&s, 0); + sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1); + VdbeCoverageNeverTaken(v); + windowReturnOneRow(&s); + sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr); + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd); + sqlite3VdbeJumpHere(v, addrGe); + } + if( pMWin->eStart==TK_FOLLOWING && pMWin->eFrmType!=TK_RANGE && regEnd ){ + assert( pMWin->eEnd==TK_FOLLOWING ); + sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regStart); + } + + if( pMWin->eStart!=TK_UNBOUNDED ){ + sqlite3VdbeAddOp2(v, OP_Rewind, s.start.csr, 1); + VdbeCoverageNeverTaken(v); + } + sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1); + VdbeCoverageNeverTaken(v); + sqlite3VdbeAddOp2(v, OP_Rewind, s.end.csr, 1); + VdbeCoverageNeverTaken(v); + if( regPeer && pOrderBy ){ + sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, pOrderBy->nExpr-1); + sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.start.reg, pOrderBy->nExpr-1); + sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.current.reg, pOrderBy->nExpr-1); + sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.end.reg, pOrderBy->nExpr-1); + } + + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd); + + sqlite3VdbeJumpHere(v, addrNe); + + /* Beginning of the block executed for the second and subsequent rows. */ + if( regPeer ){ + windowIfNewPeer(pParse, pOrderBy, regNewPeer, regPeer, lblWhereEnd); + } + if( pMWin->eStart==TK_FOLLOWING ){ + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + if( pMWin->eEnd!=TK_UNBOUNDED ){ + if( pMWin->eFrmType==TK_RANGE ){ + int lbl = sqlite3VdbeMakeLabel(pParse); + int addrNext = sqlite3VdbeCurrentAddr(v); + windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext); + sqlite3VdbeResolveLabel(v, lbl); + }else{ + windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 0); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + } } + }else + if( pMWin->eEnd==TK_PRECEDING ){ + int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE); + windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0); + if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + if( !bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + }else{ + int addr = 0; + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + if( pMWin->eEnd!=TK_UNBOUNDED ){ + if( pMWin->eFrmType==TK_RANGE ){ + int lbl = 0; + addr = sqlite3VdbeCurrentAddr(v); + if( regEnd ){ + lbl = sqlite3VdbeMakeLabel(pParse); + windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl); + } + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + if( regEnd ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); + sqlite3VdbeResolveLabel(v, lbl); + } + }else{ + if( regEnd ){ + addr = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1); + VdbeCoverage(v); + } + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + if( regEnd ) sqlite3VdbeJumpHere(v, addr); + } + } + } - /* Otherwise, call windowCodeDefaultStep(). */ - if( bCache ){ - VdbeModuleComment((pParse->pVdbe, "Begin CacheStep()")); - windowCodeCacheStep(pParse, p, pWInfo, regGosub, addrGosub); - }else{ - VdbeModuleComment((pParse->pVdbe, "Begin DefaultStep()")); - windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub); + /* End of the main input loop */ + sqlite3VdbeResolveLabel(v, lblWhereEnd); + sqlite3WhereEnd(pWInfo); + + /* Fall through */ + if( pMWin->pPartition ){ + addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart); + sqlite3VdbeJumpHere(v, addrGosubFlush); + } + + addrEmpty = sqlite3VdbeAddOp1(v, OP_Rewind, csrWrite); + VdbeCoverage(v); + if( pMWin->eEnd==TK_PRECEDING ){ + int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE); + windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0); + if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + }else if( pMWin->eStart==TK_FOLLOWING ){ + int addrStart; + int addrBreak1; + int addrBreak2; + int addrBreak3; + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + if( pMWin->eFrmType==TK_RANGE ){ + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1); + addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); + }else + if( pMWin->eEnd==TK_UNBOUNDED ){ + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regStart, 1); + addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, 0, 1); + }else{ + assert( pMWin->eEnd==TK_FOLLOWING ); + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 1); + addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1); + } + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); + sqlite3VdbeJumpHere(v, addrBreak2); + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak3 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); + sqlite3VdbeJumpHere(v, addrBreak1); + sqlite3VdbeJumpHere(v, addrBreak3); + }else{ + int addrBreak; + int addrStart; + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); + sqlite3VdbeJumpHere(v, addrBreak); + } + sqlite3VdbeJumpHere(v, addrEmpty); + + sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr); + if( pMWin->pPartition ){ + if( pMWin->regStartRowid ){ + sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid); } + sqlite3VdbeChangeP1(v, addrInteger, sqlite3VdbeCurrentAddr(v)); + sqlite3VdbeAddOp1(v, OP_Return, regFlushPart); } } @@ -145931,6 +148719,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( ** input grammar file: */ /* #include */ +/* #include */ /************ Begin %include sections from the grammar ************************/ /* #include "sqliteInt.h" */ @@ -146032,19 +148821,15 @@ static void disableLookaside(Parse *pParse){ p->pLeft = p->pRight = 0; p->x.pList = 0; p->pAggInfo = 0; - p->pTab = 0; + p->y.pTab = 0; p->op2 = 0; p->iTable = 0; p->iColumn = 0; -#ifndef SQLITE_OMIT_WINDOWFUNC - p->pWin = 0; -#endif p->u.zToken = (char*)&p[1]; memcpy(p->u.zToken, t.z, t.n); p->u.zToken[t.n] = 0; if( sqlite3Isquote(p->u.zToken[0]) ){ - if( p->u.zToken[0]=='"' ) p->flags |= EP_DblQuoted; - sqlite3Dequote(p->u.zToken); + sqlite3DequoteExpr(p); } #if SQLITE_MAX_EXPR_DEPTH>0 p->nHeight = 1; @@ -146090,6 +148875,10 @@ static void disableLookaside(Parse *pParse){ sqlite3ExprListSetName(pParse, p, pIdToken, 1); return p; } + +#if TK_SPAN>255 +# error too many tokens in the grammar +#endif /**************** End of %include directives **********************************/ /* These constants specify the various numeric values for terminal symbols ** in a format understandable to "makeheaders". This section is blank unless @@ -146153,27 +148942,28 @@ static void disableLookaside(Parse *pParse){ #endif /************* Begin control #defines *****************************************/ #define YYCODETYPE unsigned short int -#define YYNOCODE 277 +#define YYNOCODE 302 #define YYACTIONTYPE unsigned short int -#define YYWILDCARD 91 +#define YYWILDCARD 95 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; sqlite3ParserTOKENTYPE yy0; - Expr* yy18; - struct TrigEvent yy34; - IdList* yy48; - int yy70; - struct {int value; int mask;} yy111; - struct FrameBound yy119; - SrcList* yy135; - TriggerStep* yy207; - Window* yy327; - Upsert* yy340; - const char* yy392; - ExprList* yy420; - With* yy449; - Select* yy489; + TriggerStep* yy11; + IdList* yy76; + ExprList* yy94; + Upsert* yy95; + int yy100; + Expr* yy102; + struct {int value; int mask;} yy199; + u8 yy218; + With* yy243; + struct TrigEvent yy298; + Window* yy379; + struct FrameBound yy389; + Select* yy391; + SrcList* yy407; + const char* yy528; } YYMINORTYPE; #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 @@ -146189,17 +148979,17 @@ typedef union { #define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse; #define sqlite3ParserCTX_STORE yypParser->pParse=pParse; #define YYFALLBACK 1 -#define YYNSTATE 521 -#define YYNRULE 367 -#define YYNTOKEN 155 -#define YY_MAX_SHIFT 520 -#define YY_MIN_SHIFTREDUCE 756 -#define YY_MAX_SHIFTREDUCE 1122 -#define YY_ERROR_ACTION 1123 -#define YY_ACCEPT_ACTION 1124 -#define YY_NO_ACTION 1125 -#define YY_MIN_REDUCE 1126 -#define YY_MAX_REDUCE 1492 +#define YYNSTATE 540 +#define YYNRULE 376 +#define YYNTOKEN 176 +#define YY_MAX_SHIFT 539 +#define YY_MIN_SHIFTREDUCE 783 +#define YY_MAX_SHIFTREDUCE 1158 +#define YY_ERROR_ACTION 1159 +#define YY_ACCEPT_ACTION 1160 +#define YY_NO_ACTION 1161 +#define YY_MIN_REDUCE 1162 +#define YY_MAX_REDUCE 1537 /************* End control #defines *******************************************/ #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) @@ -146266,568 +149056,601 @@ typedef union { ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (2009) +#define YY_ACTTAB_COUNT (2142) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 368, 105, 102, 197, 105, 102, 197, 515, 1124, 1, - /* 10 */ 1, 520, 2, 1128, 515, 1192, 1171, 1456, 275, 370, - /* 20 */ 127, 1389, 1197, 1197, 1192, 1166, 178, 1205, 64, 64, - /* 30 */ 477, 887, 322, 428, 348, 37, 37, 808, 362, 888, - /* 40 */ 509, 509, 509, 112, 113, 103, 1100, 1100, 953, 956, - /* 50 */ 946, 946, 110, 110, 111, 111, 111, 111, 365, 252, - /* 60 */ 252, 515, 252, 252, 497, 515, 309, 515, 459, 515, - /* 70 */ 1079, 491, 512, 478, 6, 512, 809, 134, 498, 228, - /* 80 */ 194, 428, 37, 37, 515, 208, 64, 64, 64, 64, - /* 90 */ 13, 13, 109, 109, 109, 109, 108, 108, 107, 107, - /* 100 */ 107, 106, 401, 258, 381, 13, 13, 398, 397, 428, - /* 110 */ 252, 252, 370, 476, 405, 1104, 1079, 1080, 1081, 386, - /* 120 */ 1106, 390, 497, 512, 497, 1423, 1419, 304, 1105, 307, - /* 130 */ 1256, 496, 370, 499, 16, 16, 112, 113, 103, 1100, - /* 140 */ 1100, 953, 956, 946, 946, 110, 110, 111, 111, 111, - /* 150 */ 111, 262, 1107, 495, 1107, 401, 112, 113, 103, 1100, - /* 160 */ 1100, 953, 956, 946, 946, 110, 110, 111, 111, 111, - /* 170 */ 111, 129, 1425, 343, 1420, 339, 1059, 492, 1057, 263, - /* 180 */ 73, 105, 102, 197, 994, 109, 109, 109, 109, 108, - /* 190 */ 108, 107, 107, 107, 106, 401, 370, 111, 111, 111, - /* 200 */ 111, 104, 492, 89, 1432, 109, 109, 109, 109, 108, - /* 210 */ 108, 107, 107, 107, 106, 401, 111, 111, 111, 111, - /* 220 */ 112, 113, 103, 1100, 1100, 953, 956, 946, 946, 110, - /* 230 */ 110, 111, 111, 111, 111, 109, 109, 109, 109, 108, - /* 240 */ 108, 107, 107, 107, 106, 401, 114, 108, 108, 107, - /* 250 */ 107, 107, 106, 401, 109, 109, 109, 109, 108, 108, - /* 260 */ 107, 107, 107, 106, 401, 152, 399, 399, 399, 109, - /* 270 */ 109, 109, 109, 108, 108, 107, 107, 107, 106, 401, - /* 280 */ 178, 493, 1412, 434, 1037, 1486, 1079, 515, 1486, 370, - /* 290 */ 421, 297, 357, 412, 74, 1079, 109, 109, 109, 109, - /* 300 */ 108, 108, 107, 107, 107, 106, 401, 1413, 37, 37, - /* 310 */ 1431, 274, 506, 112, 113, 103, 1100, 1100, 953, 956, - /* 320 */ 946, 946, 110, 110, 111, 111, 111, 111, 1436, 520, - /* 330 */ 2, 1128, 1079, 1080, 1081, 430, 275, 1079, 127, 366, - /* 340 */ 933, 1079, 1080, 1081, 220, 1205, 913, 458, 455, 454, - /* 350 */ 392, 167, 515, 1035, 152, 445, 924, 453, 152, 874, - /* 360 */ 923, 289, 109, 109, 109, 109, 108, 108, 107, 107, - /* 370 */ 107, 106, 401, 13, 13, 261, 853, 252, 252, 227, - /* 380 */ 106, 401, 370, 1079, 1080, 1081, 311, 388, 1079, 296, - /* 390 */ 512, 923, 923, 925, 231, 323, 1255, 1388, 1423, 490, - /* 400 */ 274, 506, 12, 208, 274, 506, 112, 113, 103, 1100, - /* 410 */ 1100, 953, 956, 946, 946, 110, 110, 111, 111, 111, - /* 420 */ 111, 1440, 286, 1128, 288, 1079, 1097, 247, 275, 1098, - /* 430 */ 127, 387, 405, 389, 1079, 1080, 1081, 1205, 159, 238, - /* 440 */ 255, 321, 461, 316, 460, 225, 790, 105, 102, 197, - /* 450 */ 513, 314, 842, 842, 445, 109, 109, 109, 109, 108, - /* 460 */ 108, 107, 107, 107, 106, 401, 515, 514, 515, 252, - /* 470 */ 252, 1079, 1080, 1081, 435, 370, 1098, 933, 1460, 794, - /* 480 */ 274, 506, 512, 105, 102, 197, 336, 63, 63, 64, - /* 490 */ 64, 27, 790, 924, 287, 208, 1354, 923, 515, 112, - /* 500 */ 113, 103, 1100, 1100, 953, 956, 946, 946, 110, 110, - /* 510 */ 111, 111, 111, 111, 107, 107, 107, 106, 401, 49, - /* 520 */ 49, 515, 28, 1079, 405, 497, 421, 297, 923, 923, - /* 530 */ 925, 186, 468, 1079, 467, 999, 999, 442, 515, 1079, - /* 540 */ 334, 515, 45, 45, 1083, 342, 173, 168, 109, 109, - /* 550 */ 109, 109, 108, 108, 107, 107, 107, 106, 401, 13, - /* 560 */ 13, 205, 13, 13, 252, 252, 1195, 1195, 370, 1079, - /* 570 */ 1080, 1081, 787, 265, 5, 359, 494, 512, 469, 1079, - /* 580 */ 1080, 1081, 398, 397, 1079, 1079, 1080, 1081, 3, 282, - /* 590 */ 1079, 1083, 112, 113, 103, 1100, 1100, 953, 956, 946, - /* 600 */ 946, 110, 110, 111, 111, 111, 111, 252, 252, 1015, - /* 610 */ 220, 1079, 873, 458, 455, 454, 943, 943, 954, 957, - /* 620 */ 512, 252, 252, 453, 1016, 1079, 445, 1107, 1209, 1107, - /* 630 */ 1079, 1080, 1081, 515, 512, 426, 1079, 1080, 1081, 1017, - /* 640 */ 512, 109, 109, 109, 109, 108, 108, 107, 107, 107, - /* 650 */ 106, 401, 1052, 515, 50, 50, 515, 1079, 1080, 1081, - /* 660 */ 828, 370, 1051, 379, 411, 1064, 1358, 207, 408, 773, - /* 670 */ 829, 1079, 1080, 1081, 64, 64, 322, 64, 64, 1302, - /* 680 */ 947, 411, 410, 1358, 1360, 112, 113, 103, 1100, 1100, - /* 690 */ 953, 956, 946, 946, 110, 110, 111, 111, 111, 111, - /* 700 */ 294, 482, 515, 1037, 1487, 515, 434, 1487, 354, 1120, - /* 710 */ 483, 996, 913, 485, 466, 996, 132, 178, 33, 450, - /* 720 */ 1203, 136, 406, 64, 64, 479, 64, 64, 419, 369, - /* 730 */ 283, 1146, 252, 252, 109, 109, 109, 109, 108, 108, - /* 740 */ 107, 107, 107, 106, 401, 512, 224, 440, 411, 266, - /* 750 */ 1358, 266, 252, 252, 370, 296, 416, 284, 934, 396, - /* 760 */ 976, 470, 400, 252, 252, 512, 9, 473, 231, 500, - /* 770 */ 354, 1036, 1035, 1488, 355, 374, 512, 1121, 112, 113, - /* 780 */ 103, 1100, 1100, 953, 956, 946, 946, 110, 110, 111, - /* 790 */ 111, 111, 111, 252, 252, 1015, 515, 1347, 295, 252, - /* 800 */ 252, 252, 252, 1098, 375, 249, 512, 445, 872, 322, - /* 810 */ 1016, 480, 512, 195, 512, 434, 273, 15, 15, 515, - /* 820 */ 314, 515, 95, 515, 93, 1017, 367, 109, 109, 109, - /* 830 */ 109, 108, 108, 107, 107, 107, 106, 401, 515, 1121, - /* 840 */ 39, 39, 51, 51, 52, 52, 503, 370, 515, 1204, - /* 850 */ 1098, 918, 439, 341, 133, 436, 223, 222, 221, 53, - /* 860 */ 53, 322, 1400, 761, 762, 763, 515, 370, 88, 54, - /* 870 */ 54, 112, 113, 103, 1100, 1100, 953, 956, 946, 946, - /* 880 */ 110, 110, 111, 111, 111, 111, 407, 55, 55, 196, - /* 890 */ 515, 112, 113, 103, 1100, 1100, 953, 956, 946, 946, - /* 900 */ 110, 110, 111, 111, 111, 111, 135, 264, 1149, 376, - /* 910 */ 515, 40, 40, 515, 872, 515, 993, 515, 993, 116, - /* 920 */ 109, 109, 109, 109, 108, 108, 107, 107, 107, 106, - /* 930 */ 401, 41, 41, 515, 43, 43, 44, 44, 56, 56, - /* 940 */ 109, 109, 109, 109, 108, 108, 107, 107, 107, 106, - /* 950 */ 401, 515, 379, 515, 57, 57, 515, 799, 515, 379, - /* 960 */ 515, 445, 200, 515, 323, 515, 1397, 515, 1459, 515, - /* 970 */ 1287, 817, 58, 58, 14, 14, 515, 59, 59, 118, - /* 980 */ 118, 60, 60, 515, 46, 46, 61, 61, 62, 62, - /* 990 */ 47, 47, 515, 190, 189, 91, 515, 140, 140, 515, - /* 1000 */ 394, 515, 277, 1200, 141, 141, 515, 1115, 515, 992, - /* 1010 */ 515, 992, 515, 69, 69, 370, 278, 48, 48, 259, - /* 1020 */ 65, 65, 119, 119, 246, 246, 260, 66, 66, 120, - /* 1030 */ 120, 121, 121, 117, 117, 370, 515, 512, 383, 112, - /* 1040 */ 113, 103, 1100, 1100, 953, 956, 946, 946, 110, 110, - /* 1050 */ 111, 111, 111, 111, 515, 872, 515, 139, 139, 112, - /* 1060 */ 113, 103, 1100, 1100, 953, 956, 946, 946, 110, 110, - /* 1070 */ 111, 111, 111, 111, 1287, 138, 138, 125, 125, 515, - /* 1080 */ 12, 515, 281, 1287, 515, 445, 131, 1287, 109, 109, - /* 1090 */ 109, 109, 108, 108, 107, 107, 107, 106, 401, 515, - /* 1100 */ 124, 124, 122, 122, 515, 123, 123, 515, 109, 109, - /* 1110 */ 109, 109, 108, 108, 107, 107, 107, 106, 401, 515, - /* 1120 */ 68, 68, 463, 783, 515, 70, 70, 302, 67, 67, - /* 1130 */ 1032, 253, 253, 356, 1287, 191, 196, 1433, 465, 1301, - /* 1140 */ 38, 38, 384, 94, 512, 42, 42, 177, 848, 274, - /* 1150 */ 506, 385, 420, 847, 1356, 441, 508, 376, 377, 153, - /* 1160 */ 423, 872, 432, 370, 224, 251, 194, 887, 182, 293, - /* 1170 */ 783, 848, 88, 254, 466, 888, 847, 915, 807, 806, - /* 1180 */ 230, 1241, 910, 370, 17, 413, 797, 112, 113, 103, - /* 1190 */ 1100, 1100, 953, 956, 946, 946, 110, 110, 111, 111, - /* 1200 */ 111, 111, 395, 814, 815, 1175, 983, 112, 101, 103, - /* 1210 */ 1100, 1100, 953, 956, 946, 946, 110, 110, 111, 111, - /* 1220 */ 111, 111, 375, 422, 427, 429, 298, 230, 230, 88, - /* 1230 */ 1240, 451, 312, 797, 226, 88, 109, 109, 109, 109, - /* 1240 */ 108, 108, 107, 107, 107, 106, 401, 86, 433, 979, - /* 1250 */ 927, 881, 226, 983, 230, 415, 109, 109, 109, 109, - /* 1260 */ 108, 108, 107, 107, 107, 106, 401, 320, 845, 781, - /* 1270 */ 846, 100, 130, 100, 1403, 290, 370, 319, 1377, 1376, - /* 1280 */ 437, 1449, 299, 1237, 303, 306, 308, 310, 1188, 1174, - /* 1290 */ 1173, 1172, 315, 324, 325, 1228, 370, 927, 1249, 271, - /* 1300 */ 1286, 113, 103, 1100, 1100, 953, 956, 946, 946, 110, - /* 1310 */ 110, 111, 111, 111, 111, 1224, 1235, 502, 501, 1292, - /* 1320 */ 1221, 1155, 103, 1100, 1100, 953, 956, 946, 946, 110, - /* 1330 */ 110, 111, 111, 111, 111, 1148, 1137, 1136, 1138, 1443, - /* 1340 */ 446, 244, 184, 98, 507, 188, 4, 353, 327, 109, - /* 1350 */ 109, 109, 109, 108, 108, 107, 107, 107, 106, 401, - /* 1360 */ 510, 329, 331, 199, 414, 456, 292, 285, 318, 109, - /* 1370 */ 109, 109, 109, 108, 108, 107, 107, 107, 106, 401, - /* 1380 */ 11, 1271, 1279, 402, 361, 192, 1171, 1351, 431, 505, - /* 1390 */ 346, 1350, 333, 98, 507, 504, 4, 187, 1446, 1115, - /* 1400 */ 233, 1396, 155, 1394, 1112, 152, 72, 75, 378, 425, - /* 1410 */ 510, 165, 149, 157, 933, 1276, 86, 30, 1268, 417, - /* 1420 */ 96, 96, 8, 160, 161, 162, 163, 97, 418, 402, - /* 1430 */ 517, 516, 449, 402, 923, 210, 358, 424, 1282, 438, - /* 1440 */ 169, 214, 360, 1345, 80, 504, 31, 444, 1365, 301, - /* 1450 */ 245, 274, 506, 216, 174, 305, 488, 447, 217, 462, - /* 1460 */ 1139, 487, 218, 363, 933, 923, 923, 925, 926, 24, - /* 1470 */ 96, 96, 1191, 1190, 1189, 391, 1182, 97, 1163, 402, - /* 1480 */ 517, 516, 799, 364, 923, 1162, 317, 1161, 98, 507, - /* 1490 */ 1181, 4, 1458, 472, 393, 269, 270, 475, 481, 1232, - /* 1500 */ 85, 1233, 326, 328, 232, 510, 495, 1231, 330, 98, - /* 1510 */ 507, 1230, 4, 486, 335, 923, 923, 925, 926, 24, - /* 1520 */ 1435, 1068, 404, 181, 336, 256, 510, 115, 402, 332, - /* 1530 */ 352, 352, 351, 241, 349, 1214, 1414, 770, 338, 10, - /* 1540 */ 504, 340, 272, 92, 1331, 1213, 87, 183, 484, 402, - /* 1550 */ 201, 488, 280, 239, 344, 345, 489, 1145, 29, 933, - /* 1560 */ 279, 504, 1074, 518, 240, 96, 96, 242, 243, 519, - /* 1570 */ 1134, 1129, 97, 154, 402, 517, 516, 372, 373, 923, - /* 1580 */ 933, 142, 143, 128, 1381, 267, 96, 96, 852, 757, - /* 1590 */ 203, 144, 403, 97, 1382, 402, 517, 516, 204, 1380, - /* 1600 */ 923, 146, 1379, 1159, 1158, 71, 1156, 276, 202, 185, - /* 1610 */ 923, 923, 925, 926, 24, 198, 257, 126, 991, 989, - /* 1620 */ 907, 98, 507, 156, 4, 145, 158, 206, 831, 209, - /* 1630 */ 291, 923, 923, 925, 926, 24, 1005, 911, 510, 164, - /* 1640 */ 147, 380, 371, 382, 166, 76, 77, 274, 506, 148, - /* 1650 */ 78, 79, 1008, 211, 212, 1004, 137, 213, 18, 300, - /* 1660 */ 230, 402, 997, 1109, 443, 215, 32, 170, 171, 772, - /* 1670 */ 409, 448, 319, 504, 219, 172, 452, 81, 19, 457, - /* 1680 */ 313, 20, 82, 268, 488, 150, 810, 179, 83, 487, - /* 1690 */ 464, 151, 933, 180, 959, 84, 1040, 34, 96, 96, - /* 1700 */ 471, 1041, 35, 474, 193, 97, 248, 402, 517, 516, - /* 1710 */ 1068, 404, 923, 250, 256, 880, 229, 175, 875, 352, - /* 1720 */ 352, 351, 241, 349, 100, 21, 770, 22, 1054, 1056, - /* 1730 */ 7, 98, 507, 1045, 4, 337, 1058, 23, 974, 201, - /* 1740 */ 176, 280, 88, 923, 923, 925, 926, 24, 510, 279, - /* 1750 */ 960, 958, 962, 1014, 963, 1013, 235, 234, 25, 36, - /* 1760 */ 99, 90, 507, 928, 4, 511, 350, 782, 26, 841, - /* 1770 */ 236, 402, 347, 1069, 237, 1125, 1125, 1451, 510, 203, - /* 1780 */ 1450, 1125, 1125, 504, 1125, 1125, 1125, 204, 1125, 1125, - /* 1790 */ 146, 1125, 1125, 1125, 1125, 1125, 1125, 202, 1125, 1125, - /* 1800 */ 1125, 402, 933, 1125, 1125, 1125, 1125, 1125, 96, 96, - /* 1810 */ 1125, 1125, 1125, 504, 1125, 97, 1125, 402, 517, 516, - /* 1820 */ 1125, 1125, 923, 1125, 1125, 1125, 1125, 1125, 1125, 1125, - /* 1830 */ 1125, 371, 933, 1125, 1125, 1125, 274, 506, 96, 96, - /* 1840 */ 1125, 1125, 1125, 1125, 1125, 97, 1125, 402, 517, 516, - /* 1850 */ 1125, 1125, 923, 923, 923, 925, 926, 24, 1125, 409, - /* 1860 */ 1125, 1125, 1125, 256, 1125, 1125, 1125, 1125, 352, 352, - /* 1870 */ 351, 241, 349, 1125, 1125, 770, 1125, 1125, 1125, 1125, - /* 1880 */ 1125, 1125, 1125, 923, 923, 925, 926, 24, 201, 1125, - /* 1890 */ 280, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 279, 1125, - /* 1900 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, - /* 1910 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, - /* 1920 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 203, 1125, - /* 1930 */ 1125, 1125, 1125, 1125, 1125, 1125, 204, 1125, 1125, 146, - /* 1940 */ 1125, 1125, 1125, 1125, 1125, 1125, 202, 1125, 1125, 1125, - /* 1950 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, - /* 1960 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, - /* 1970 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, - /* 1980 */ 371, 1125, 1125, 1125, 1125, 274, 506, 1125, 1125, 1125, - /* 1990 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, - /* 2000 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 409, + /* 0 */ 112, 109, 209, 112, 109, 209, 1160, 1, 1, 539, + /* 10 */ 2, 1164, 490, 1193, 1293, 534, 289, 1196, 134, 383, + /* 20 */ 1485, 1428, 1164, 1229, 1208, 1242, 1195, 289, 491, 134, + /* 30 */ 373, 915, 1229, 443, 16, 16, 1242, 70, 70, 916, + /* 40 */ 242, 1292, 296, 119, 120, 110, 1136, 1136, 981, 984, + /* 50 */ 974, 974, 117, 117, 118, 118, 118, 118, 264, 264, + /* 60 */ 190, 264, 264, 264, 264, 112, 109, 209, 362, 264, + /* 70 */ 264, 531, 376, 497, 531, 1134, 531, 1501, 239, 206, + /* 80 */ 338, 9, 531, 242, 219, 1203, 118, 118, 118, 118, + /* 90 */ 111, 439, 112, 109, 209, 219, 116, 116, 116, 116, + /* 100 */ 115, 115, 114, 114, 114, 113, 414, 115, 115, 114, + /* 110 */ 114, 114, 113, 414, 418, 12, 383, 400, 1134, 114, + /* 120 */ 114, 114, 113, 414, 1115, 418, 1134, 1392, 116, 116, + /* 130 */ 116, 116, 115, 115, 114, 114, 114, 113, 414, 961, + /* 140 */ 119, 120, 110, 1136, 1136, 981, 984, 974, 974, 117, + /* 150 */ 117, 118, 118, 118, 118, 952, 534, 414, 941, 951, + /* 160 */ 1481, 539, 2, 1164, 1505, 534, 160, 175, 289, 1134, + /* 170 */ 134, 434, 312, 297, 1115, 1116, 1117, 1242, 70, 70, + /* 180 */ 1089, 338, 1089, 118, 118, 118, 118, 42, 42, 448, + /* 190 */ 951, 951, 953, 116, 116, 116, 116, 115, 115, 114, + /* 200 */ 114, 114, 113, 414, 1115, 311, 264, 264, 82, 441, + /* 210 */ 264, 264, 190, 383, 284, 12, 288, 525, 407, 531, + /* 220 */ 96, 159, 458, 531, 371, 116, 116, 116, 116, 115, + /* 230 */ 115, 114, 114, 114, 113, 414, 219, 119, 120, 110, + /* 240 */ 1136, 1136, 981, 984, 974, 974, 117, 117, 118, 118, + /* 250 */ 118, 118, 511, 1477, 1115, 1116, 1117, 113, 414, 534, + /* 260 */ 528, 528, 528, 121, 534, 1427, 418, 116, 116, 116, + /* 270 */ 116, 115, 115, 114, 114, 114, 113, 414, 1464, 351, + /* 280 */ 270, 42, 42, 383, 187, 1115, 70, 70, 533, 433, + /* 290 */ 116, 116, 116, 116, 115, 115, 114, 114, 114, 113, + /* 300 */ 414, 534, 1339, 405, 159, 411, 410, 119, 120, 110, + /* 310 */ 1136, 1136, 981, 984, 974, 974, 117, 117, 118, 118, + /* 320 */ 118, 118, 285, 42, 42, 349, 411, 410, 514, 479, + /* 330 */ 1458, 79, 1084, 6, 1140, 1115, 1116, 1117, 480, 1142, + /* 340 */ 501, 1115, 1084, 123, 238, 1084, 136, 1141, 1234, 1234, + /* 350 */ 1143, 383, 1143, 1115, 167, 426, 80, 447, 512, 1451, + /* 360 */ 116, 116, 116, 116, 115, 115, 114, 114, 114, 113, + /* 370 */ 414, 1143, 1466, 1143, 350, 119, 120, 110, 1136, 1136, + /* 380 */ 981, 984, 974, 974, 117, 117, 118, 118, 118, 118, + /* 390 */ 402, 1115, 1116, 1117, 500, 534, 250, 267, 336, 474, + /* 400 */ 331, 473, 236, 1115, 1116, 1117, 231, 1115, 329, 471, + /* 410 */ 468, 467, 509, 1458, 1464, 505, 6, 70, 70, 466, + /* 420 */ 181, 380, 379, 534, 971, 971, 982, 985, 116, 116, + /* 430 */ 116, 116, 115, 115, 114, 114, 114, 113, 414, 1115, + /* 440 */ 412, 412, 412, 496, 1115, 69, 69, 235, 383, 288, + /* 450 */ 525, 273, 326, 516, 337, 458, 1084, 1115, 1116, 1117, + /* 460 */ 1232, 1232, 492, 160, 508, 441, 1084, 1067, 1531, 1084, + /* 470 */ 207, 1531, 119, 120, 110, 1136, 1136, 981, 984, 974, + /* 480 */ 974, 117, 117, 118, 118, 118, 118, 881, 534, 1115, + /* 490 */ 1116, 1117, 975, 534, 1115, 1116, 1117, 534, 421, 534, + /* 500 */ 141, 534, 176, 356, 517, 1119, 32, 511, 482, 388, + /* 510 */ 70, 70, 818, 288, 525, 70, 70, 441, 499, 50, + /* 520 */ 50, 70, 70, 70, 70, 116, 116, 116, 116, 115, + /* 530 */ 115, 114, 114, 114, 113, 414, 274, 264, 264, 1115, + /* 540 */ 1065, 264, 264, 1115, 355, 383, 409, 961, 1439, 822, + /* 550 */ 531, 516, 190, 419, 531, 483, 1119, 516, 337, 516, + /* 560 */ 518, 1115, 818, 952, 382, 458, 515, 951, 481, 119, + /* 570 */ 120, 110, 1136, 1136, 981, 984, 974, 974, 117, 117, + /* 580 */ 118, 118, 118, 118, 1338, 278, 1045, 278, 275, 1115, + /* 590 */ 1116, 1117, 259, 1115, 1116, 1117, 534, 5, 951, 951, + /* 600 */ 953, 1046, 231, 3, 143, 471, 468, 467, 1391, 463, + /* 610 */ 1115, 1115, 1116, 1117, 1452, 466, 1047, 836, 70, 70, + /* 620 */ 480, 534, 116, 116, 116, 116, 115, 115, 114, 114, + /* 630 */ 114, 113, 414, 95, 1115, 287, 235, 856, 902, 420, + /* 640 */ 1115, 534, 383, 13, 13, 381, 815, 857, 472, 112, + /* 650 */ 109, 209, 1115, 337, 413, 309, 837, 394, 1436, 534, + /* 660 */ 1115, 1116, 1117, 54, 54, 291, 119, 120, 110, 1136, + /* 670 */ 1136, 981, 984, 974, 974, 117, 117, 118, 118, 118, + /* 680 */ 118, 13, 13, 1084, 1115, 1116, 1117, 901, 264, 264, + /* 690 */ 1115, 1116, 1117, 1084, 292, 399, 1084, 800, 388, 140, + /* 700 */ 295, 531, 1115, 1116, 1117, 403, 447, 532, 534, 870, + /* 710 */ 870, 534, 1240, 534, 329, 534, 1185, 389, 534, 116, + /* 720 */ 116, 116, 116, 115, 115, 114, 114, 114, 113, 414, + /* 730 */ 13, 13, 1024, 13, 13, 13, 13, 13, 13, 383, + /* 740 */ 13, 13, 424, 1100, 401, 264, 264, 277, 160, 184, + /* 750 */ 1182, 185, 1533, 369, 513, 484, 432, 487, 531, 424, + /* 760 */ 423, 1397, 941, 119, 120, 110, 1136, 1136, 981, 984, + /* 770 */ 974, 974, 117, 117, 118, 118, 118, 118, 1397, 1399, + /* 780 */ 425, 519, 392, 264, 264, 1029, 1029, 455, 264, 264, + /* 790 */ 264, 264, 1004, 304, 261, 1278, 531, 900, 288, 525, + /* 800 */ 310, 531, 493, 531, 1067, 1532, 458, 387, 1532, 311, + /* 810 */ 429, 299, 534, 107, 264, 264, 116, 116, 116, 116, + /* 820 */ 115, 115, 114, 114, 114, 113, 414, 531, 424, 1384, + /* 830 */ 507, 258, 258, 1246, 55, 55, 383, 1277, 265, 265, + /* 840 */ 962, 324, 434, 312, 531, 531, 506, 1397, 1026, 1241, + /* 850 */ 298, 531, 1026, 445, 301, 1095, 303, 534, 368, 1156, + /* 860 */ 119, 120, 110, 1136, 1136, 981, 984, 974, 974, 117, + /* 870 */ 117, 118, 118, 118, 118, 1045, 534, 1065, 534, 15, + /* 880 */ 15, 1084, 208, 1324, 453, 452, 534, 1324, 534, 449, + /* 890 */ 1046, 1084, 494, 458, 1084, 234, 233, 232, 44, 44, + /* 900 */ 56, 56, 319, 1095, 322, 1047, 534, 900, 57, 57, + /* 910 */ 58, 58, 534, 116, 116, 116, 116, 115, 115, 114, + /* 920 */ 114, 114, 113, 414, 534, 514, 522, 534, 59, 59, + /* 930 */ 302, 1157, 534, 383, 60, 60, 1237, 946, 788, 789, + /* 940 */ 790, 1459, 1456, 446, 6, 6, 61, 61, 1212, 45, + /* 950 */ 45, 534, 396, 383, 46, 46, 397, 119, 120, 110, + /* 960 */ 1136, 1136, 981, 984, 974, 974, 117, 117, 118, 118, + /* 970 */ 118, 118, 428, 48, 48, 534, 392, 119, 120, 110, + /* 980 */ 1136, 1136, 981, 984, 974, 974, 117, 117, 118, 118, + /* 990 */ 118, 118, 1324, 368, 1066, 447, 825, 49, 49, 534, + /* 1000 */ 458, 357, 534, 353, 534, 138, 534, 337, 1478, 478, + /* 1010 */ 116, 116, 116, 116, 115, 115, 114, 114, 114, 113, + /* 1020 */ 414, 62, 62, 392, 63, 63, 64, 64, 14, 14, + /* 1030 */ 116, 116, 116, 116, 115, 115, 114, 114, 114, 113, + /* 1040 */ 414, 534, 810, 317, 271, 534, 1457, 825, 534, 6, + /* 1050 */ 534, 1324, 534, 142, 534, 1442, 534, 212, 534, 1324, + /* 1060 */ 534, 398, 305, 65, 65, 534, 1157, 125, 125, 476, + /* 1070 */ 66, 66, 51, 51, 67, 67, 68, 68, 52, 52, + /* 1080 */ 147, 147, 148, 148, 534, 98, 534, 75, 75, 276, + /* 1090 */ 534, 272, 534, 810, 534, 876, 534, 527, 389, 534, + /* 1100 */ 875, 534, 1151, 202, 534, 383, 53, 53, 71, 71, + /* 1110 */ 288, 525, 126, 126, 72, 72, 127, 127, 128, 128, + /* 1120 */ 454, 124, 124, 146, 146, 383, 145, 145, 408, 119, + /* 1130 */ 120, 110, 1136, 1136, 981, 984, 974, 974, 117, 117, + /* 1140 */ 118, 118, 118, 118, 534, 900, 534, 95, 534, 119, + /* 1150 */ 120, 110, 1136, 1136, 981, 984, 974, 974, 117, 117, + /* 1160 */ 118, 118, 118, 118, 390, 161, 132, 132, 131, 131, + /* 1170 */ 129, 129, 534, 915, 534, 1455, 534, 1454, 6, 1416, + /* 1180 */ 6, 916, 116, 116, 116, 116, 115, 115, 114, 114, + /* 1190 */ 114, 113, 414, 1415, 130, 130, 74, 74, 76, 76, + /* 1200 */ 534, 30, 116, 116, 116, 116, 115, 115, 114, 114, + /* 1210 */ 114, 113, 414, 534, 263, 206, 534, 1133, 1504, 93, + /* 1220 */ 876, 845, 73, 73, 102, 875, 100, 139, 17, 38, + /* 1230 */ 208, 1062, 31, 450, 370, 43, 43, 101, 47, 47, + /* 1240 */ 827, 216, 436, 308, 943, 440, 95, 241, 241, 442, + /* 1250 */ 313, 464, 241, 95, 237, 900, 327, 383, 266, 95, + /* 1260 */ 835, 834, 193, 335, 938, 314, 1011, 435, 842, 843, + /* 1270 */ 955, 1007, 909, 334, 237, 241, 873, 383, 1023, 107, + /* 1280 */ 1023, 119, 120, 110, 1136, 1136, 981, 984, 974, 974, + /* 1290 */ 117, 117, 118, 118, 118, 118, 1022, 808, 1022, 1274, + /* 1300 */ 137, 119, 108, 110, 1136, 1136, 981, 984, 974, 974, + /* 1310 */ 117, 117, 118, 118, 118, 118, 874, 1011, 318, 107, + /* 1320 */ 321, 955, 323, 325, 1225, 1211, 197, 1210, 1209, 330, + /* 1330 */ 339, 1265, 340, 283, 116, 116, 116, 116, 115, 115, + /* 1340 */ 114, 114, 114, 113, 414, 1286, 1323, 1261, 1471, 1272, + /* 1350 */ 520, 218, 521, 1329, 116, 116, 116, 116, 115, 115, + /* 1360 */ 114, 114, 114, 113, 414, 1192, 1184, 1173, 1172, 1174, + /* 1370 */ 1494, 1488, 459, 256, 383, 1258, 342, 199, 367, 344, + /* 1380 */ 211, 195, 307, 444, 11, 346, 469, 333, 1308, 1316, + /* 1390 */ 375, 427, 203, 360, 383, 1388, 188, 1387, 189, 120, + /* 1400 */ 110, 1136, 1136, 981, 984, 974, 974, 117, 117, 118, + /* 1410 */ 118, 118, 118, 1208, 1151, 300, 348, 1491, 245, 1148, + /* 1420 */ 110, 1136, 1136, 981, 984, 974, 974, 117, 117, 118, + /* 1430 */ 118, 118, 118, 198, 1435, 1433, 524, 78, 391, 163, + /* 1440 */ 82, 1393, 438, 173, 81, 105, 526, 1313, 4, 35, + /* 1450 */ 157, 116, 116, 116, 116, 115, 115, 114, 114, 114, + /* 1460 */ 113, 414, 529, 165, 93, 430, 1305, 168, 169, 431, + /* 1470 */ 462, 116, 116, 116, 116, 115, 115, 114, 114, 114, + /* 1480 */ 113, 414, 170, 171, 221, 415, 372, 437, 1319, 177, + /* 1490 */ 374, 36, 451, 225, 1382, 87, 457, 523, 257, 1404, + /* 1500 */ 316, 105, 526, 227, 4, 182, 460, 160, 320, 228, + /* 1510 */ 377, 1175, 475, 229, 1228, 404, 1227, 1226, 529, 827, + /* 1520 */ 961, 1219, 378, 1200, 1199, 406, 103, 103, 1218, 332, + /* 1530 */ 8, 281, 1198, 104, 1503, 415, 536, 535, 486, 282, + /* 1540 */ 951, 415, 489, 495, 92, 244, 1269, 341, 243, 122, + /* 1550 */ 1270, 343, 514, 523, 1268, 1462, 10, 288, 525, 345, + /* 1560 */ 1461, 354, 99, 352, 503, 94, 1267, 347, 1251, 502, + /* 1570 */ 498, 951, 951, 953, 954, 27, 961, 1250, 194, 358, + /* 1580 */ 251, 359, 103, 103, 1181, 34, 537, 1110, 252, 104, + /* 1590 */ 254, 415, 536, 535, 255, 1368, 951, 1420, 286, 538, + /* 1600 */ 1170, 1165, 1421, 135, 1419, 1418, 149, 150, 279, 784, + /* 1610 */ 416, 196, 151, 290, 210, 200, 77, 385, 269, 386, + /* 1620 */ 133, 162, 935, 1021, 201, 1019, 153, 951, 951, 953, + /* 1630 */ 954, 27, 1480, 1104, 417, 164, 217, 268, 859, 166, + /* 1640 */ 306, 1035, 366, 366, 365, 253, 363, 220, 172, 797, + /* 1650 */ 939, 155, 105, 526, 393, 4, 395, 174, 156, 83, + /* 1660 */ 1038, 84, 213, 85, 294, 222, 86, 223, 1034, 529, + /* 1670 */ 144, 18, 293, 224, 315, 456, 241, 1027, 1145, 178, + /* 1680 */ 226, 179, 37, 799, 334, 461, 230, 465, 470, 838, + /* 1690 */ 180, 88, 415, 19, 280, 328, 20, 89, 90, 158, + /* 1700 */ 191, 477, 215, 1097, 523, 204, 192, 987, 91, 1070, + /* 1710 */ 152, 39, 485, 154, 1071, 503, 40, 488, 205, 260, + /* 1720 */ 504, 262, 105, 526, 214, 4, 908, 961, 183, 240, + /* 1730 */ 903, 107, 1086, 103, 103, 21, 22, 1088, 23, 529, + /* 1740 */ 104, 24, 415, 536, 535, 1090, 1093, 951, 1094, 25, + /* 1750 */ 1074, 33, 7, 26, 510, 1002, 247, 186, 384, 95, + /* 1760 */ 988, 986, 415, 288, 525, 990, 1044, 246, 1043, 991, + /* 1770 */ 28, 41, 530, 956, 523, 809, 106, 29, 951, 951, + /* 1780 */ 953, 954, 27, 869, 361, 503, 422, 248, 364, 1105, + /* 1790 */ 502, 249, 1161, 1496, 1495, 1161, 1161, 961, 1161, 1161, + /* 1800 */ 1161, 1161, 1161, 103, 103, 1161, 1161, 1161, 1161, 1161, + /* 1810 */ 104, 1161, 415, 536, 535, 1104, 417, 951, 1161, 268, + /* 1820 */ 1161, 1161, 1161, 1161, 366, 366, 365, 253, 363, 1161, + /* 1830 */ 1161, 797, 1161, 1161, 1161, 1161, 105, 526, 1161, 4, + /* 1840 */ 1161, 1161, 1161, 1161, 213, 1161, 294, 1161, 951, 951, + /* 1850 */ 953, 954, 27, 529, 293, 1161, 1161, 1161, 1161, 1161, + /* 1860 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, + /* 1870 */ 1161, 1161, 1161, 1161, 1161, 1161, 415, 1161, 1161, 1161, + /* 1880 */ 1161, 1161, 1161, 1161, 215, 1161, 1161, 1161, 523, 1161, + /* 1890 */ 1161, 1161, 152, 1161, 1161, 154, 105, 526, 1161, 4, + /* 1900 */ 1161, 1161, 1161, 1161, 1161, 1161, 214, 1161, 1161, 1161, + /* 1910 */ 1161, 961, 1161, 529, 1161, 1161, 1161, 103, 103, 880, + /* 1920 */ 1161, 1161, 1161, 1161, 104, 1161, 415, 536, 535, 1161, + /* 1930 */ 1161, 951, 1161, 1161, 1161, 1161, 415, 1161, 1161, 1161, + /* 1940 */ 384, 1161, 1161, 1161, 1161, 288, 525, 1161, 523, 1161, + /* 1950 */ 1161, 1161, 1161, 1161, 1161, 1161, 97, 526, 1161, 4, + /* 1960 */ 1161, 1161, 951, 951, 953, 954, 27, 1161, 422, 1161, + /* 1970 */ 1161, 961, 1161, 529, 1161, 1161, 1161, 103, 103, 1161, + /* 1980 */ 1161, 1161, 1161, 1161, 104, 1161, 415, 536, 535, 1161, + /* 1990 */ 1161, 951, 268, 1161, 1161, 1161, 415, 366, 366, 365, + /* 2000 */ 253, 363, 1161, 1161, 797, 1161, 1161, 1161, 523, 1161, + /* 2010 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 213, 1161, 294, + /* 2020 */ 1161, 1161, 951, 951, 953, 954, 27, 293, 1161, 1161, + /* 2030 */ 1161, 961, 1161, 1161, 1161, 1161, 1161, 103, 103, 1161, + /* 2040 */ 1161, 1161, 1161, 1161, 104, 1161, 415, 536, 535, 1161, + /* 2050 */ 1161, 951, 1161, 1161, 1161, 1161, 1161, 215, 1161, 1161, + /* 2060 */ 1161, 1161, 1161, 1161, 1161, 152, 1161, 1161, 154, 1161, + /* 2070 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 214, + /* 2080 */ 1161, 1161, 951, 951, 953, 954, 27, 1161, 1161, 1161, + /* 2090 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, + /* 2100 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, + /* 2110 */ 1161, 1161, 1161, 384, 1161, 1161, 1161, 1161, 288, 525, + /* 2120 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, + /* 2130 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, + /* 2140 */ 1161, 422, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 184, 238, 239, 240, 238, 239, 240, 163, 155, 156, - /* 10 */ 157, 158, 159, 160, 163, 191, 192, 183, 165, 19, - /* 20 */ 167, 258, 202, 203, 200, 191, 163, 174, 184, 185, - /* 30 */ 174, 31, 163, 163, 171, 184, 185, 35, 175, 39, - /* 40 */ 179, 180, 181, 43, 44, 45, 46, 47, 48, 49, - /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 184, 206, - /* 60 */ 207, 163, 206, 207, 220, 163, 16, 163, 66, 163, - /* 70 */ 59, 270, 219, 229, 273, 219, 74, 208, 174, 223, - /* 80 */ 224, 163, 184, 185, 163, 232, 184, 185, 184, 185, - /* 90 */ 184, 185, 92, 93, 94, 95, 96, 97, 98, 99, - /* 100 */ 100, 101, 102, 233, 198, 184, 185, 96, 97, 163, - /* 110 */ 206, 207, 19, 163, 261, 104, 105, 106, 107, 198, - /* 120 */ 109, 119, 220, 219, 220, 274, 275, 77, 117, 79, - /* 130 */ 187, 229, 19, 229, 184, 185, 43, 44, 45, 46, - /* 140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 150 */ 57, 233, 141, 134, 143, 102, 43, 44, 45, 46, - /* 160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 170 */ 57, 152, 274, 216, 276, 218, 83, 163, 85, 233, - /* 180 */ 67, 238, 239, 240, 11, 92, 93, 94, 95, 96, - /* 190 */ 97, 98, 99, 100, 101, 102, 19, 54, 55, 56, - /* 200 */ 57, 58, 163, 26, 163, 92, 93, 94, 95, 96, - /* 210 */ 97, 98, 99, 100, 101, 102, 54, 55, 56, 57, - /* 220 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 230 */ 53, 54, 55, 56, 57, 92, 93, 94, 95, 96, - /* 240 */ 97, 98, 99, 100, 101, 102, 69, 96, 97, 98, - /* 250 */ 99, 100, 101, 102, 92, 93, 94, 95, 96, 97, - /* 260 */ 98, 99, 100, 101, 102, 81, 179, 180, 181, 92, - /* 270 */ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - /* 280 */ 163, 267, 268, 163, 22, 23, 59, 163, 26, 19, - /* 290 */ 117, 118, 175, 109, 24, 59, 92, 93, 94, 95, - /* 300 */ 96, 97, 98, 99, 100, 101, 102, 268, 184, 185, - /* 310 */ 269, 127, 128, 43, 44, 45, 46, 47, 48, 49, - /* 320 */ 50, 51, 52, 53, 54, 55, 56, 57, 157, 158, - /* 330 */ 159, 160, 105, 106, 107, 163, 165, 59, 167, 184, - /* 340 */ 90, 105, 106, 107, 108, 174, 73, 111, 112, 113, - /* 350 */ 19, 22, 163, 91, 81, 163, 106, 121, 81, 132, - /* 360 */ 110, 16, 92, 93, 94, 95, 96, 97, 98, 99, - /* 370 */ 100, 101, 102, 184, 185, 255, 98, 206, 207, 26, - /* 380 */ 101, 102, 19, 105, 106, 107, 23, 198, 59, 116, - /* 390 */ 219, 141, 142, 143, 24, 163, 187, 205, 274, 275, - /* 400 */ 127, 128, 182, 232, 127, 128, 43, 44, 45, 46, - /* 410 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 420 */ 57, 158, 77, 160, 79, 59, 26, 182, 165, 59, - /* 430 */ 167, 199, 261, 102, 105, 106, 107, 174, 72, 108, - /* 440 */ 109, 110, 111, 112, 113, 114, 59, 238, 239, 240, - /* 450 */ 123, 120, 125, 126, 163, 92, 93, 94, 95, 96, - /* 460 */ 97, 98, 99, 100, 101, 102, 163, 163, 163, 206, - /* 470 */ 207, 105, 106, 107, 254, 19, 106, 90, 197, 23, - /* 480 */ 127, 128, 219, 238, 239, 240, 22, 184, 185, 184, - /* 490 */ 185, 22, 105, 106, 149, 232, 205, 110, 163, 43, - /* 500 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 510 */ 54, 55, 56, 57, 98, 99, 100, 101, 102, 184, - /* 520 */ 185, 163, 53, 59, 261, 220, 117, 118, 141, 142, - /* 530 */ 143, 131, 174, 59, 229, 116, 117, 118, 163, 59, - /* 540 */ 163, 163, 184, 185, 59, 242, 72, 22, 92, 93, - /* 550 */ 94, 95, 96, 97, 98, 99, 100, 101, 102, 184, - /* 560 */ 185, 24, 184, 185, 206, 207, 202, 203, 19, 105, - /* 570 */ 106, 107, 23, 198, 22, 174, 198, 219, 220, 105, - /* 580 */ 106, 107, 96, 97, 59, 105, 106, 107, 22, 174, - /* 590 */ 59, 106, 43, 44, 45, 46, 47, 48, 49, 50, - /* 600 */ 51, 52, 53, 54, 55, 56, 57, 206, 207, 12, - /* 610 */ 108, 59, 132, 111, 112, 113, 46, 47, 48, 49, - /* 620 */ 219, 206, 207, 121, 27, 59, 163, 141, 207, 143, - /* 630 */ 105, 106, 107, 163, 219, 234, 105, 106, 107, 42, - /* 640 */ 219, 92, 93, 94, 95, 96, 97, 98, 99, 100, - /* 650 */ 101, 102, 76, 163, 184, 185, 163, 105, 106, 107, - /* 660 */ 63, 19, 86, 163, 163, 23, 163, 130, 205, 21, - /* 670 */ 73, 105, 106, 107, 184, 185, 163, 184, 185, 237, - /* 680 */ 110, 180, 181, 180, 181, 43, 44, 45, 46, 47, - /* 690 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 700 */ 174, 163, 163, 22, 23, 163, 163, 26, 22, 23, - /* 710 */ 220, 29, 73, 220, 272, 33, 22, 163, 24, 19, - /* 720 */ 174, 208, 259, 184, 185, 19, 184, 185, 80, 175, - /* 730 */ 230, 174, 206, 207, 92, 93, 94, 95, 96, 97, - /* 740 */ 98, 99, 100, 101, 102, 219, 46, 65, 247, 195, - /* 750 */ 247, 197, 206, 207, 19, 116, 117, 118, 23, 220, - /* 760 */ 112, 174, 220, 206, 207, 219, 22, 174, 24, 174, - /* 770 */ 22, 23, 91, 264, 265, 168, 219, 91, 43, 44, - /* 780 */ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - /* 790 */ 55, 56, 57, 206, 207, 12, 163, 149, 255, 206, - /* 800 */ 207, 206, 207, 59, 104, 23, 219, 163, 26, 163, - /* 810 */ 27, 105, 219, 163, 219, 163, 211, 184, 185, 163, - /* 820 */ 120, 163, 146, 163, 148, 42, 221, 92, 93, 94, - /* 830 */ 95, 96, 97, 98, 99, 100, 101, 102, 163, 91, - /* 840 */ 184, 185, 184, 185, 184, 185, 63, 19, 163, 205, - /* 850 */ 106, 23, 245, 163, 208, 248, 116, 117, 118, 184, - /* 860 */ 185, 163, 163, 7, 8, 9, 163, 19, 26, 184, - /* 870 */ 185, 43, 44, 45, 46, 47, 48, 49, 50, 51, - /* 880 */ 52, 53, 54, 55, 56, 57, 163, 184, 185, 107, - /* 890 */ 163, 43, 44, 45, 46, 47, 48, 49, 50, 51, - /* 900 */ 52, 53, 54, 55, 56, 57, 208, 255, 177, 178, - /* 910 */ 163, 184, 185, 163, 132, 163, 141, 163, 143, 22, - /* 920 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - /* 930 */ 102, 184, 185, 163, 184, 185, 184, 185, 184, 185, - /* 940 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - /* 950 */ 102, 163, 163, 163, 184, 185, 163, 115, 163, 163, - /* 960 */ 163, 163, 15, 163, 163, 163, 163, 163, 23, 163, - /* 970 */ 163, 26, 184, 185, 184, 185, 163, 184, 185, 184, - /* 980 */ 185, 184, 185, 163, 184, 185, 184, 185, 184, 185, - /* 990 */ 184, 185, 163, 96, 97, 147, 163, 184, 185, 163, - /* 1000 */ 199, 163, 163, 205, 184, 185, 163, 60, 163, 141, - /* 1010 */ 163, 143, 163, 184, 185, 19, 163, 184, 185, 230, - /* 1020 */ 184, 185, 184, 185, 206, 207, 230, 184, 185, 184, - /* 1030 */ 185, 184, 185, 184, 185, 19, 163, 219, 231, 43, - /* 1040 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 1050 */ 54, 55, 56, 57, 163, 26, 163, 184, 185, 43, - /* 1060 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 1070 */ 54, 55, 56, 57, 163, 184, 185, 184, 185, 163, - /* 1080 */ 182, 163, 163, 163, 163, 163, 22, 163, 92, 93, - /* 1090 */ 94, 95, 96, 97, 98, 99, 100, 101, 102, 163, - /* 1100 */ 184, 185, 184, 185, 163, 184, 185, 163, 92, 93, - /* 1110 */ 94, 95, 96, 97, 98, 99, 100, 101, 102, 163, - /* 1120 */ 184, 185, 98, 59, 163, 184, 185, 205, 184, 185, - /* 1130 */ 23, 206, 207, 26, 163, 26, 107, 153, 154, 237, - /* 1140 */ 184, 185, 231, 147, 219, 184, 185, 249, 124, 127, - /* 1150 */ 128, 231, 254, 129, 163, 231, 177, 178, 262, 263, - /* 1160 */ 118, 132, 19, 19, 46, 223, 224, 31, 24, 23, - /* 1170 */ 106, 124, 26, 22, 272, 39, 129, 23, 109, 110, - /* 1180 */ 26, 163, 140, 19, 22, 234, 59, 43, 44, 45, - /* 1190 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - /* 1200 */ 56, 57, 231, 7, 8, 193, 59, 43, 44, 45, - /* 1210 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - /* 1220 */ 56, 57, 104, 61, 23, 23, 23, 26, 26, 26, - /* 1230 */ 163, 23, 23, 106, 26, 26, 92, 93, 94, 95, - /* 1240 */ 96, 97, 98, 99, 100, 101, 102, 138, 105, 23, - /* 1250 */ 59, 23, 26, 106, 26, 163, 92, 93, 94, 95, - /* 1260 */ 96, 97, 98, 99, 100, 101, 102, 110, 23, 23, - /* 1270 */ 23, 26, 26, 26, 163, 163, 19, 120, 163, 163, - /* 1280 */ 163, 130, 163, 163, 163, 163, 163, 163, 163, 193, - /* 1290 */ 193, 163, 163, 163, 163, 225, 19, 106, 163, 222, - /* 1300 */ 163, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 1310 */ 53, 54, 55, 56, 57, 163, 163, 203, 163, 163, - /* 1320 */ 222, 163, 45, 46, 47, 48, 49, 50, 51, 52, - /* 1330 */ 53, 54, 55, 56, 57, 163, 163, 163, 163, 163, - /* 1340 */ 251, 250, 209, 19, 20, 182, 22, 161, 222, 92, - /* 1350 */ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - /* 1360 */ 36, 222, 222, 260, 226, 188, 256, 226, 187, 92, - /* 1370 */ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - /* 1380 */ 210, 213, 213, 59, 213, 196, 192, 187, 256, 244, - /* 1390 */ 212, 187, 226, 19, 20, 71, 22, 210, 166, 60, - /* 1400 */ 130, 170, 260, 170, 38, 81, 257, 257, 170, 104, - /* 1410 */ 36, 22, 43, 201, 90, 236, 138, 235, 213, 18, - /* 1420 */ 96, 97, 48, 204, 204, 204, 204, 103, 170, 105, - /* 1430 */ 106, 107, 18, 59, 110, 169, 213, 213, 201, 170, - /* 1440 */ 201, 169, 236, 213, 146, 71, 235, 62, 253, 252, - /* 1450 */ 170, 127, 128, 169, 22, 170, 82, 189, 169, 104, - /* 1460 */ 170, 87, 169, 189, 90, 141, 142, 143, 144, 145, - /* 1470 */ 96, 97, 186, 186, 186, 64, 194, 103, 186, 105, - /* 1480 */ 106, 107, 115, 189, 110, 188, 186, 186, 19, 20, - /* 1490 */ 194, 22, 186, 189, 102, 246, 246, 189, 133, 228, - /* 1500 */ 104, 228, 227, 227, 170, 36, 134, 228, 227, 19, - /* 1510 */ 20, 228, 22, 84, 271, 141, 142, 143, 144, 145, - /* 1520 */ 0, 1, 2, 216, 22, 5, 36, 137, 59, 227, - /* 1530 */ 10, 11, 12, 13, 14, 217, 269, 17, 216, 22, - /* 1540 */ 71, 170, 243, 146, 241, 217, 136, 215, 135, 59, - /* 1550 */ 30, 82, 32, 25, 214, 213, 87, 173, 26, 90, - /* 1560 */ 40, 71, 13, 172, 164, 96, 97, 164, 6, 162, - /* 1570 */ 162, 162, 103, 263, 105, 106, 107, 266, 266, 110, - /* 1580 */ 90, 176, 176, 190, 182, 190, 96, 97, 98, 4, - /* 1590 */ 70, 176, 3, 103, 182, 105, 106, 107, 78, 182, - /* 1600 */ 110, 81, 182, 182, 182, 182, 182, 151, 88, 22, - /* 1610 */ 141, 142, 143, 144, 145, 15, 89, 16, 23, 23, - /* 1620 */ 128, 19, 20, 139, 22, 119, 131, 24, 20, 133, - /* 1630 */ 16, 141, 142, 143, 144, 145, 1, 140, 36, 131, - /* 1640 */ 119, 61, 122, 37, 139, 53, 53, 127, 128, 119, - /* 1650 */ 53, 53, 105, 34, 130, 1, 5, 104, 22, 149, - /* 1660 */ 26, 59, 68, 75, 41, 130, 24, 68, 104, 20, - /* 1670 */ 150, 19, 120, 71, 114, 22, 67, 22, 22, 67, - /* 1680 */ 23, 22, 22, 67, 82, 37, 28, 23, 138, 87, - /* 1690 */ 22, 153, 90, 23, 23, 26, 23, 22, 96, 97, - /* 1700 */ 24, 23, 22, 24, 130, 103, 23, 105, 106, 107, - /* 1710 */ 1, 2, 110, 23, 5, 105, 34, 22, 132, 10, - /* 1720 */ 11, 12, 13, 14, 26, 34, 17, 34, 85, 83, - /* 1730 */ 44, 19, 20, 23, 22, 24, 75, 34, 23, 30, - /* 1740 */ 26, 32, 26, 141, 142, 143, 144, 145, 36, 40, - /* 1750 */ 23, 23, 23, 23, 11, 23, 22, 26, 22, 22, - /* 1760 */ 22, 19, 20, 23, 22, 26, 15, 23, 22, 124, - /* 1770 */ 130, 59, 23, 1, 130, 277, 277, 130, 36, 70, - /* 1780 */ 130, 277, 277, 71, 277, 277, 277, 78, 277, 277, - /* 1790 */ 81, 277, 277, 277, 277, 277, 277, 88, 277, 277, - /* 1800 */ 277, 59, 90, 277, 277, 277, 277, 277, 96, 97, - /* 1810 */ 277, 277, 277, 71, 277, 103, 277, 105, 106, 107, - /* 1820 */ 277, 277, 110, 277, 277, 277, 277, 277, 277, 277, - /* 1830 */ 277, 122, 90, 277, 277, 277, 127, 128, 96, 97, - /* 1840 */ 277, 277, 277, 277, 277, 103, 277, 105, 106, 107, - /* 1850 */ 277, 277, 110, 141, 142, 143, 144, 145, 277, 150, - /* 1860 */ 277, 277, 277, 5, 277, 277, 277, 277, 10, 11, - /* 1870 */ 12, 13, 14, 277, 277, 17, 277, 277, 277, 277, - /* 1880 */ 277, 277, 277, 141, 142, 143, 144, 145, 30, 277, - /* 1890 */ 32, 277, 277, 277, 277, 277, 277, 277, 40, 277, - /* 1900 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - /* 1910 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - /* 1920 */ 277, 277, 277, 277, 277, 277, 277, 277, 70, 277, - /* 1930 */ 277, 277, 277, 277, 277, 277, 78, 277, 277, 81, - /* 1940 */ 277, 277, 277, 277, 277, 277, 88, 277, 277, 277, - /* 1950 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - /* 1960 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - /* 1970 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - /* 1980 */ 122, 277, 277, 277, 277, 127, 128, 277, 277, 277, - /* 1990 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - /* 2000 */ 277, 277, 277, 277, 277, 277, 277, 277, 150, 277, - /* 2010 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, + /* 0 */ 260, 261, 262, 260, 261, 262, 176, 177, 178, 179, + /* 10 */ 180, 181, 184, 206, 209, 184, 186, 206, 188, 19, + /* 20 */ 179, 281, 181, 213, 214, 195, 206, 186, 195, 188, + /* 30 */ 195, 31, 222, 184, 206, 207, 195, 206, 207, 39, + /* 40 */ 24, 209, 184, 43, 44, 45, 46, 47, 48, 49, + /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 228, 229, + /* 60 */ 184, 228, 229, 228, 229, 260, 261, 262, 192, 228, + /* 70 */ 229, 241, 196, 242, 241, 59, 241, 205, 245, 246, + /* 80 */ 184, 22, 241, 24, 254, 213, 54, 55, 56, 57, + /* 90 */ 58, 256, 260, 261, 262, 254, 96, 97, 98, 99, + /* 100 */ 100, 101, 102, 103, 104, 105, 106, 100, 101, 102, + /* 110 */ 103, 104, 105, 106, 284, 203, 19, 221, 59, 102, + /* 120 */ 103, 104, 105, 106, 59, 284, 110, 269, 96, 97, + /* 130 */ 98, 99, 100, 101, 102, 103, 104, 105, 106, 94, + /* 140 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 150 */ 53, 54, 55, 56, 57, 110, 184, 106, 73, 114, + /* 160 */ 178, 179, 180, 181, 219, 184, 81, 22, 186, 110, + /* 170 */ 188, 121, 122, 195, 109, 110, 111, 195, 206, 207, + /* 180 */ 83, 184, 85, 54, 55, 56, 57, 206, 207, 277, + /* 190 */ 145, 146, 147, 96, 97, 98, 99, 100, 101, 102, + /* 200 */ 103, 104, 105, 106, 59, 120, 228, 229, 143, 184, + /* 210 */ 228, 229, 184, 19, 242, 203, 131, 132, 221, 241, + /* 220 */ 26, 184, 184, 241, 196, 96, 97, 98, 99, 100, + /* 230 */ 101, 102, 103, 104, 105, 106, 254, 43, 44, 45, + /* 240 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 250 */ 56, 57, 184, 184, 109, 110, 111, 105, 106, 184, + /* 260 */ 200, 201, 202, 69, 184, 227, 284, 96, 97, 98, + /* 270 */ 99, 100, 101, 102, 103, 104, 105, 106, 297, 298, + /* 280 */ 255, 206, 207, 19, 272, 59, 206, 207, 184, 277, + /* 290 */ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + /* 300 */ 106, 184, 259, 19, 184, 100, 101, 43, 44, 45, + /* 310 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 320 */ 56, 57, 242, 206, 207, 184, 100, 101, 138, 292, + /* 330 */ 293, 67, 76, 296, 108, 109, 110, 111, 295, 113, + /* 340 */ 84, 59, 86, 22, 26, 89, 156, 121, 224, 225, + /* 350 */ 145, 19, 147, 59, 72, 256, 24, 184, 290, 291, + /* 360 */ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + /* 370 */ 106, 145, 297, 147, 299, 43, 44, 45, 46, 47, + /* 380 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 390 */ 106, 109, 110, 111, 138, 184, 112, 113, 114, 115, + /* 400 */ 116, 117, 118, 109, 110, 111, 112, 59, 124, 115, + /* 410 */ 116, 117, 292, 293, 297, 298, 296, 206, 207, 125, + /* 420 */ 72, 100, 101, 184, 46, 47, 48, 49, 96, 97, + /* 430 */ 98, 99, 100, 101, 102, 103, 104, 105, 106, 59, + /* 440 */ 200, 201, 202, 184, 59, 206, 207, 46, 19, 131, + /* 450 */ 132, 278, 23, 242, 184, 184, 76, 109, 110, 111, + /* 460 */ 224, 225, 251, 81, 84, 184, 86, 22, 23, 89, + /* 470 */ 184, 26, 43, 44, 45, 46, 47, 48, 49, 50, + /* 480 */ 51, 52, 53, 54, 55, 56, 57, 102, 184, 109, + /* 490 */ 110, 111, 114, 184, 109, 110, 111, 184, 227, 184, + /* 500 */ 230, 184, 22, 264, 195, 59, 22, 184, 195, 108, + /* 510 */ 206, 207, 59, 131, 132, 206, 207, 184, 138, 206, + /* 520 */ 207, 206, 207, 206, 207, 96, 97, 98, 99, 100, + /* 530 */ 101, 102, 103, 104, 105, 106, 255, 228, 229, 59, + /* 540 */ 95, 228, 229, 59, 184, 19, 242, 94, 184, 23, + /* 550 */ 241, 242, 184, 282, 241, 242, 110, 242, 184, 242, + /* 560 */ 251, 59, 109, 110, 196, 184, 251, 114, 251, 43, + /* 570 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 580 */ 54, 55, 56, 57, 259, 217, 12, 219, 255, 109, + /* 590 */ 110, 111, 203, 109, 110, 111, 184, 22, 145, 146, + /* 600 */ 147, 27, 112, 22, 230, 115, 116, 117, 227, 19, + /* 610 */ 59, 109, 110, 111, 291, 125, 42, 35, 206, 207, + /* 620 */ 295, 184, 96, 97, 98, 99, 100, 101, 102, 103, + /* 630 */ 104, 105, 106, 26, 59, 233, 46, 63, 136, 184, + /* 640 */ 59, 184, 19, 206, 207, 243, 23, 73, 66, 260, + /* 650 */ 261, 262, 59, 184, 242, 195, 74, 220, 184, 184, + /* 660 */ 109, 110, 111, 206, 207, 184, 43, 44, 45, 46, + /* 670 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 680 */ 57, 206, 207, 76, 109, 110, 111, 136, 228, 229, + /* 690 */ 109, 110, 111, 86, 184, 220, 89, 21, 108, 230, + /* 700 */ 184, 241, 109, 110, 111, 123, 184, 127, 184, 129, + /* 710 */ 130, 184, 195, 184, 124, 184, 198, 199, 184, 96, + /* 720 */ 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + /* 730 */ 206, 207, 11, 206, 207, 206, 207, 206, 207, 19, + /* 740 */ 206, 207, 184, 23, 220, 228, 229, 220, 81, 220, + /* 750 */ 195, 220, 287, 288, 220, 195, 80, 195, 241, 201, + /* 760 */ 202, 184, 73, 43, 44, 45, 46, 47, 48, 49, + /* 770 */ 50, 51, 52, 53, 54, 55, 56, 57, 201, 202, + /* 780 */ 113, 195, 184, 228, 229, 120, 121, 122, 228, 229, + /* 790 */ 228, 229, 116, 16, 23, 184, 241, 26, 131, 132, + /* 800 */ 278, 241, 19, 241, 22, 23, 184, 189, 26, 120, + /* 810 */ 121, 122, 184, 26, 228, 229, 96, 97, 98, 99, + /* 820 */ 100, 101, 102, 103, 104, 105, 106, 241, 270, 153, + /* 830 */ 66, 228, 229, 229, 206, 207, 19, 184, 228, 229, + /* 840 */ 23, 16, 121, 122, 241, 241, 82, 270, 29, 227, + /* 850 */ 252, 241, 33, 19, 77, 91, 79, 184, 22, 23, + /* 860 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 870 */ 53, 54, 55, 56, 57, 12, 184, 95, 184, 206, + /* 880 */ 207, 76, 111, 184, 65, 267, 184, 184, 184, 271, + /* 890 */ 27, 86, 109, 184, 89, 120, 121, 122, 206, 207, + /* 900 */ 206, 207, 77, 139, 79, 42, 184, 136, 206, 207, + /* 910 */ 206, 207, 184, 96, 97, 98, 99, 100, 101, 102, + /* 920 */ 103, 104, 105, 106, 184, 138, 63, 184, 206, 207, + /* 930 */ 153, 95, 184, 19, 206, 207, 227, 23, 7, 8, + /* 940 */ 9, 293, 293, 109, 296, 296, 206, 207, 215, 206, + /* 950 */ 207, 184, 253, 19, 206, 207, 253, 43, 44, 45, + /* 960 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 970 */ 56, 57, 184, 206, 207, 184, 184, 43, 44, 45, + /* 980 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 990 */ 56, 57, 184, 22, 23, 184, 59, 206, 207, 184, + /* 1000 */ 184, 238, 184, 240, 184, 22, 184, 184, 157, 158, + /* 1010 */ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + /* 1020 */ 106, 206, 207, 184, 206, 207, 206, 207, 206, 207, + /* 1030 */ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + /* 1040 */ 106, 184, 59, 227, 252, 184, 293, 110, 184, 296, + /* 1050 */ 184, 184, 184, 230, 184, 184, 184, 15, 184, 184, + /* 1060 */ 184, 253, 184, 206, 207, 184, 95, 206, 207, 102, + /* 1070 */ 206, 207, 206, 207, 206, 207, 206, 207, 206, 207, + /* 1080 */ 206, 207, 206, 207, 184, 151, 184, 206, 207, 278, + /* 1090 */ 184, 252, 184, 110, 184, 128, 184, 198, 199, 184, + /* 1100 */ 133, 184, 60, 26, 184, 19, 206, 207, 206, 207, + /* 1110 */ 131, 132, 206, 207, 206, 207, 206, 207, 206, 207, + /* 1120 */ 253, 206, 207, 206, 207, 19, 206, 207, 253, 43, + /* 1130 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 1140 */ 54, 55, 56, 57, 184, 26, 184, 26, 184, 43, + /* 1150 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 1160 */ 54, 55, 56, 57, 285, 286, 206, 207, 206, 207, + /* 1170 */ 206, 207, 184, 31, 184, 293, 184, 293, 296, 184, + /* 1180 */ 296, 39, 96, 97, 98, 99, 100, 101, 102, 103, + /* 1190 */ 104, 105, 106, 184, 206, 207, 206, 207, 206, 207, + /* 1200 */ 184, 22, 96, 97, 98, 99, 100, 101, 102, 103, + /* 1210 */ 104, 105, 106, 184, 245, 246, 184, 26, 23, 142, + /* 1220 */ 128, 26, 206, 207, 150, 133, 152, 22, 22, 24, + /* 1230 */ 111, 23, 53, 184, 26, 206, 207, 151, 206, 207, + /* 1240 */ 119, 24, 122, 23, 23, 23, 26, 26, 26, 23, + /* 1250 */ 23, 23, 26, 26, 26, 136, 23, 19, 22, 26, + /* 1260 */ 113, 114, 24, 114, 144, 184, 59, 61, 7, 8, + /* 1270 */ 59, 23, 23, 124, 26, 26, 23, 19, 145, 26, + /* 1280 */ 147, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 1290 */ 52, 53, 54, 55, 56, 57, 145, 23, 147, 184, + /* 1300 */ 26, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 1310 */ 52, 53, 54, 55, 56, 57, 23, 110, 184, 26, + /* 1320 */ 184, 110, 184, 184, 184, 215, 135, 215, 184, 184, + /* 1330 */ 184, 247, 184, 244, 96, 97, 98, 99, 100, 101, + /* 1340 */ 102, 103, 104, 105, 106, 184, 184, 184, 301, 184, + /* 1350 */ 184, 134, 225, 184, 96, 97, 98, 99, 100, 101, + /* 1360 */ 102, 103, 104, 105, 106, 184, 184, 184, 184, 184, + /* 1370 */ 134, 184, 274, 273, 19, 244, 244, 204, 182, 244, + /* 1380 */ 283, 231, 279, 279, 232, 244, 210, 209, 235, 235, + /* 1390 */ 235, 248, 218, 234, 19, 209, 238, 209, 238, 44, + /* 1400 */ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + /* 1410 */ 55, 56, 57, 214, 60, 248, 248, 187, 134, 38, + /* 1420 */ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + /* 1430 */ 55, 56, 57, 232, 191, 191, 266, 280, 191, 283, + /* 1440 */ 143, 269, 108, 22, 280, 19, 20, 258, 22, 257, + /* 1450 */ 43, 96, 97, 98, 99, 100, 101, 102, 103, 104, + /* 1460 */ 105, 106, 36, 223, 142, 18, 235, 226, 226, 191, + /* 1470 */ 18, 96, 97, 98, 99, 100, 101, 102, 103, 104, + /* 1480 */ 105, 106, 226, 226, 190, 59, 235, 235, 223, 223, + /* 1490 */ 258, 257, 191, 190, 235, 150, 62, 71, 191, 276, + /* 1500 */ 275, 19, 20, 190, 22, 22, 211, 81, 191, 190, + /* 1510 */ 211, 191, 108, 190, 208, 64, 208, 208, 36, 119, + /* 1520 */ 94, 216, 211, 208, 210, 106, 100, 101, 216, 208, + /* 1530 */ 48, 268, 208, 107, 208, 109, 110, 111, 211, 268, + /* 1540 */ 114, 59, 211, 137, 108, 88, 250, 249, 191, 141, + /* 1550 */ 250, 249, 138, 71, 250, 300, 22, 131, 132, 249, + /* 1560 */ 300, 191, 150, 238, 82, 140, 250, 249, 239, 87, + /* 1570 */ 139, 145, 146, 147, 148, 149, 94, 239, 237, 236, + /* 1580 */ 25, 235, 100, 101, 194, 26, 193, 13, 185, 107, + /* 1590 */ 185, 109, 110, 111, 6, 263, 114, 203, 265, 183, + /* 1600 */ 183, 183, 203, 212, 203, 203, 197, 197, 212, 4, + /* 1610 */ 3, 22, 197, 155, 15, 204, 203, 289, 93, 289, + /* 1620 */ 16, 286, 132, 23, 204, 23, 123, 145, 146, 147, + /* 1630 */ 148, 149, 0, 1, 2, 143, 24, 5, 20, 135, + /* 1640 */ 16, 1, 10, 11, 12, 13, 14, 137, 135, 17, + /* 1650 */ 144, 123, 19, 20, 61, 22, 37, 143, 123, 53, + /* 1660 */ 109, 53, 30, 53, 32, 34, 53, 134, 1, 36, + /* 1670 */ 5, 22, 40, 108, 153, 41, 26, 68, 75, 68, + /* 1680 */ 134, 108, 24, 20, 124, 19, 118, 67, 67, 28, + /* 1690 */ 22, 22, 59, 22, 67, 23, 22, 22, 142, 37, + /* 1700 */ 23, 22, 70, 23, 71, 157, 23, 23, 26, 23, + /* 1710 */ 78, 22, 24, 81, 23, 82, 22, 24, 134, 23, + /* 1720 */ 87, 23, 19, 20, 92, 22, 109, 94, 22, 34, + /* 1730 */ 136, 26, 85, 100, 101, 34, 34, 83, 34, 36, + /* 1740 */ 107, 34, 109, 110, 111, 75, 90, 114, 75, 34, + /* 1750 */ 23, 22, 44, 34, 24, 23, 22, 26, 126, 26, + /* 1760 */ 23, 23, 59, 131, 132, 23, 23, 26, 23, 11, + /* 1770 */ 22, 22, 26, 23, 71, 23, 22, 22, 145, 146, + /* 1780 */ 147, 148, 149, 128, 23, 82, 154, 134, 15, 1, + /* 1790 */ 87, 134, 302, 134, 134, 302, 302, 94, 302, 302, + /* 1800 */ 302, 302, 302, 100, 101, 302, 302, 302, 302, 302, + /* 1810 */ 107, 302, 109, 110, 111, 1, 2, 114, 302, 5, + /* 1820 */ 302, 302, 302, 302, 10, 11, 12, 13, 14, 302, + /* 1830 */ 302, 17, 302, 302, 302, 302, 19, 20, 302, 22, + /* 1840 */ 302, 302, 302, 302, 30, 302, 32, 302, 145, 146, + /* 1850 */ 147, 148, 149, 36, 40, 302, 302, 302, 302, 302, + /* 1860 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 1870 */ 302, 302, 302, 302, 302, 302, 59, 302, 302, 302, + /* 1880 */ 302, 302, 302, 302, 70, 302, 302, 302, 71, 302, + /* 1890 */ 302, 302, 78, 302, 302, 81, 19, 20, 302, 22, + /* 1900 */ 302, 302, 302, 302, 302, 302, 92, 302, 302, 302, + /* 1910 */ 302, 94, 302, 36, 302, 302, 302, 100, 101, 102, + /* 1920 */ 302, 302, 302, 302, 107, 302, 109, 110, 111, 302, + /* 1930 */ 302, 114, 302, 302, 302, 302, 59, 302, 302, 302, + /* 1940 */ 126, 302, 302, 302, 302, 131, 132, 302, 71, 302, + /* 1950 */ 302, 302, 302, 302, 302, 302, 19, 20, 302, 22, + /* 1960 */ 302, 302, 145, 146, 147, 148, 149, 302, 154, 302, + /* 1970 */ 302, 94, 302, 36, 302, 302, 302, 100, 101, 302, + /* 1980 */ 302, 302, 302, 302, 107, 302, 109, 110, 111, 302, + /* 1990 */ 302, 114, 5, 302, 302, 302, 59, 10, 11, 12, + /* 2000 */ 13, 14, 302, 302, 17, 302, 302, 302, 71, 302, + /* 2010 */ 302, 302, 302, 302, 302, 302, 302, 30, 302, 32, + /* 2020 */ 302, 302, 145, 146, 147, 148, 149, 40, 302, 302, + /* 2030 */ 302, 94, 302, 302, 302, 302, 302, 100, 101, 302, + /* 2040 */ 302, 302, 302, 302, 107, 302, 109, 110, 111, 302, + /* 2050 */ 302, 114, 302, 302, 302, 302, 302, 70, 302, 302, + /* 2060 */ 302, 302, 302, 302, 302, 78, 302, 302, 81, 302, + /* 2070 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 92, + /* 2080 */ 302, 302, 145, 146, 147, 148, 149, 302, 302, 302, + /* 2090 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2100 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2110 */ 302, 302, 302, 126, 302, 302, 302, 302, 131, 132, + /* 2120 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2130 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2140 */ 302, 154, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2150 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2160 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, }; -#define YY_SHIFT_COUNT (520) +#define YY_SHIFT_COUNT (539) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (1858) +#define YY_SHIFT_MAX (1987) static const unsigned short int yy_shift_ofst[] = { - /* 0 */ 1709, 1520, 1858, 1324, 1324, 277, 1374, 1469, 1602, 1712, - /* 10 */ 1712, 1712, 273, 0, 0, 113, 1016, 1712, 1712, 1712, - /* 20 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 11, 11, 236, - /* 30 */ 184, 277, 277, 277, 277, 277, 277, 93, 177, 270, - /* 40 */ 363, 456, 549, 642, 735, 828, 848, 996, 1144, 1016, - /* 50 */ 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016, - /* 60 */ 1016, 1016, 1016, 1016, 1016, 1016, 1164, 1016, 1257, 1277, - /* 70 */ 1277, 1490, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, - /* 80 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, - /* 90 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, - /* 100 */ 1712, 1712, 1712, 1742, 1712, 1712, 1712, 1712, 1712, 1712, - /* 110 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 143, 162, 162, - /* 120 */ 162, 162, 162, 204, 151, 416, 531, 648, 700, 531, - /* 130 */ 486, 486, 531, 353, 353, 353, 353, 409, 279, 53, - /* 140 */ 2009, 2009, 331, 331, 331, 329, 366, 329, 329, 597, - /* 150 */ 597, 464, 474, 262, 681, 531, 531, 531, 531, 531, - /* 160 */ 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, - /* 170 */ 531, 531, 531, 531, 531, 531, 531, 173, 485, 984, - /* 180 */ 984, 576, 485, 19, 1022, 2009, 2009, 2009, 387, 250, - /* 190 */ 250, 525, 502, 278, 552, 227, 480, 566, 531, 531, - /* 200 */ 531, 531, 531, 531, 531, 531, 531, 531, 639, 531, - /* 210 */ 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, - /* 220 */ 531, 2, 2, 2, 531, 531, 531, 531, 782, 531, - /* 230 */ 531, 531, 744, 531, 531, 783, 531, 531, 531, 531, - /* 240 */ 531, 531, 531, 531, 419, 682, 327, 370, 370, 370, - /* 250 */ 370, 1029, 327, 327, 1024, 897, 856, 947, 1109, 706, - /* 260 */ 706, 1143, 1109, 1109, 1143, 842, 945, 1118, 1136, 1136, - /* 270 */ 1136, 706, 676, 400, 1047, 694, 1339, 1270, 1270, 1366, - /* 280 */ 1366, 1270, 1305, 1389, 1369, 1278, 1401, 1401, 1401, 1401, - /* 290 */ 1270, 1414, 1278, 1278, 1305, 1389, 1369, 1369, 1278, 1270, - /* 300 */ 1414, 1298, 1385, 1270, 1414, 1432, 1270, 1414, 1270, 1414, - /* 310 */ 1432, 1355, 1355, 1355, 1411, 1432, 1355, 1367, 1355, 1411, - /* 320 */ 1355, 1355, 1432, 1392, 1392, 1432, 1365, 1396, 1365, 1396, - /* 330 */ 1365, 1396, 1365, 1396, 1270, 1372, 1429, 1502, 1390, 1372, - /* 340 */ 1517, 1270, 1397, 1390, 1410, 1413, 1278, 1528, 1532, 1549, - /* 350 */ 1549, 1562, 1562, 1562, 2009, 2009, 2009, 2009, 2009, 2009, - /* 360 */ 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, - /* 370 */ 570, 345, 686, 748, 50, 740, 1064, 1107, 469, 537, - /* 380 */ 1042, 1146, 1162, 1154, 1201, 1202, 1203, 1208, 1209, 1127, - /* 390 */ 1069, 1196, 1157, 1147, 1226, 1228, 1245, 775, 868, 1246, - /* 400 */ 1247, 1191, 1151, 1585, 1589, 1587, 1456, 1600, 1527, 1601, - /* 410 */ 1595, 1596, 1492, 1484, 1506, 1603, 1495, 1608, 1496, 1614, - /* 420 */ 1635, 1508, 1497, 1521, 1580, 1606, 1505, 1592, 1593, 1597, - /* 430 */ 1598, 1530, 1547, 1619, 1524, 1654, 1651, 1636, 1553, 1510, - /* 440 */ 1594, 1634, 1599, 1588, 1623, 1535, 1564, 1642, 1649, 1652, - /* 450 */ 1552, 1560, 1653, 1609, 1655, 1656, 1657, 1659, 1612, 1658, - /* 460 */ 1660, 1616, 1648, 1664, 1550, 1668, 1538, 1670, 1671, 1669, - /* 470 */ 1673, 1675, 1676, 1678, 1680, 1679, 1574, 1683, 1690, 1610, - /* 480 */ 1682, 1695, 1586, 1698, 1691, 1698, 1693, 1643, 1661, 1646, - /* 490 */ 1686, 1710, 1711, 1714, 1716, 1703, 1715, 1698, 1727, 1728, - /* 500 */ 1729, 1730, 1731, 1732, 1734, 1743, 1736, 1737, 1740, 1744, - /* 510 */ 1738, 1746, 1739, 1645, 1640, 1644, 1647, 1650, 1749, 1751, - /* 520 */ 1772, + /* 0 */ 1814, 1632, 1987, 1426, 1426, 382, 1482, 1633, 1703, 1877, + /* 10 */ 1877, 1877, 85, 0, 0, 264, 1106, 1877, 1877, 1877, + /* 20 */ 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + /* 30 */ 226, 226, 380, 380, 294, 667, 382, 382, 382, 382, + /* 40 */ 382, 382, 97, 194, 332, 429, 526, 623, 720, 817, + /* 50 */ 914, 934, 1086, 1238, 1106, 1106, 1106, 1106, 1106, 1106, + /* 60 */ 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, + /* 70 */ 1106, 1106, 1258, 1106, 1355, 1375, 1375, 1817, 1877, 1877, + /* 80 */ 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + /* 90 */ 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + /* 100 */ 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + /* 110 */ 1937, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + /* 120 */ 1877, 1877, 1877, 1877, 32, 129, 129, 129, 129, 129, + /* 130 */ 171, 7, 17, 593, 676, 590, 593, 205, 205, 593, + /* 140 */ 318, 318, 318, 318, 50, 152, 51, 2142, 2142, 284, + /* 150 */ 284, 284, 65, 145, 282, 145, 145, 574, 574, 256, + /* 160 */ 348, 445, 782, 593, 593, 593, 593, 593, 593, 593, + /* 170 */ 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, + /* 180 */ 593, 593, 593, 593, 607, 607, 593, 721, 805, 805, + /* 190 */ 446, 851, 851, 446, 190, 979, 2142, 2142, 2142, 453, + /* 200 */ 45, 45, 480, 490, 484, 385, 575, 502, 551, 581, + /* 210 */ 593, 593, 593, 593, 593, 593, 593, 593, 593, 689, + /* 220 */ 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, + /* 230 */ 593, 593, 582, 582, 582, 593, 593, 593, 593, 771, + /* 240 */ 593, 593, 593, 59, 764, 593, 593, 863, 593, 593, + /* 250 */ 593, 593, 593, 593, 593, 593, 665, 819, 580, 16, + /* 260 */ 16, 16, 16, 1119, 580, 580, 967, 321, 931, 1042, + /* 270 */ 1077, 783, 783, 834, 1077, 1077, 834, 1121, 1195, 401, + /* 280 */ 1142, 1142, 1142, 783, 787, 787, 1074, 1191, 1092, 1205, + /* 290 */ 1354, 1284, 1284, 1381, 1381, 1284, 1297, 1334, 1421, 1407, + /* 300 */ 1322, 1447, 1447, 1447, 1447, 1284, 1452, 1322, 1322, 1334, + /* 310 */ 1421, 1407, 1407, 1322, 1284, 1452, 1345, 1434, 1284, 1452, + /* 320 */ 1483, 1284, 1452, 1284, 1452, 1483, 1404, 1404, 1404, 1451, + /* 330 */ 1483, 1404, 1400, 1404, 1451, 1404, 1404, 1483, 1419, 1419, + /* 340 */ 1483, 1406, 1436, 1406, 1436, 1406, 1436, 1406, 1436, 1284, + /* 350 */ 1457, 1457, 1408, 1414, 1534, 1284, 1412, 1408, 1425, 1431, + /* 360 */ 1322, 1555, 1559, 1574, 1574, 1588, 1588, 1588, 2142, 2142, + /* 370 */ 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, + /* 380 */ 2142, 2142, 2142, 378, 777, 836, 971, 825, 775, 983, + /* 390 */ 1208, 1179, 1217, 1120, 1220, 1206, 1221, 1222, 1226, 1227, + /* 400 */ 1228, 1233, 937, 1147, 1261, 1149, 1207, 1248, 1249, 1253, + /* 410 */ 1133, 1151, 1274, 1293, 1211, 1236, 1605, 1607, 1589, 1458, + /* 420 */ 1599, 1525, 1604, 1600, 1602, 1490, 1492, 1503, 1612, 1504, + /* 430 */ 1618, 1510, 1624, 1640, 1513, 1506, 1528, 1593, 1619, 1514, + /* 440 */ 1606, 1608, 1610, 1613, 1535, 1551, 1631, 1533, 1667, 1665, + /* 450 */ 1649, 1565, 1521, 1609, 1650, 1611, 1603, 1634, 1546, 1573, + /* 460 */ 1658, 1663, 1666, 1560, 1568, 1668, 1620, 1669, 1671, 1672, + /* 470 */ 1674, 1621, 1661, 1675, 1627, 1662, 1677, 1556, 1679, 1680, + /* 480 */ 1548, 1683, 1684, 1682, 1686, 1689, 1688, 1691, 1694, 1693, + /* 490 */ 1584, 1696, 1698, 1617, 1695, 1706, 1594, 1705, 1701, 1702, + /* 500 */ 1704, 1707, 1647, 1670, 1654, 1708, 1673, 1656, 1715, 1727, + /* 510 */ 1729, 1730, 1731, 1733, 1719, 1732, 1705, 1737, 1738, 1742, + /* 520 */ 1743, 1741, 1745, 1734, 1758, 1748, 1749, 1750, 1752, 1754, + /* 530 */ 1755, 1746, 1655, 1653, 1657, 1659, 1660, 1761, 1773, 1788, }; -#define YY_REDUCE_COUNT (369) -#define YY_REDUCE_MIN (-237) -#define YY_REDUCE_MAX (1424) +#define YY_REDUCE_COUNT (382) +#define YY_REDUCE_MIN (-260) +#define YY_REDUCE_MAX (1420) static const short yy_reduce_ofst[] = { - /* 0 */ -147, 171, 263, -96, 358, -144, -149, -102, 124, -156, - /* 10 */ -98, 305, 401, -57, 209, -237, 245, -94, -79, 189, - /* 20 */ 375, 490, 493, 378, 303, 539, 542, 501, 503, 554, - /* 30 */ 415, 526, 546, 557, 587, 593, 595, -234, -234, -234, - /* 40 */ -234, -234, -234, -234, -234, -234, -234, -234, -234, -234, - /* 50 */ -234, -234, -234, -234, -234, -234, -234, -234, -234, -234, - /* 60 */ -234, -234, -234, -234, -234, -234, -234, -234, -234, -234, - /* 70 */ -234, -50, 335, 470, 633, 656, 658, 660, 675, 685, - /* 80 */ 703, 727, 747, 750, 752, 754, 770, 788, 790, 793, - /* 90 */ 795, 797, 800, 802, 804, 806, 813, 820, 829, 833, - /* 100 */ 836, 838, 843, 845, 847, 849, 873, 891, 893, 916, - /* 110 */ 918, 921, 936, 941, 944, 956, 961, -234, -234, -234, - /* 120 */ -234, -234, -234, -234, -234, -234, 463, 607, -176, 14, - /* 130 */ -139, 87, -137, 818, 925, 818, 925, 898, -234, -234, - /* 140 */ -234, -234, -166, -166, -166, -130, -131, -82, -54, -180, - /* 150 */ 364, 41, 513, 509, 509, 117, 500, 789, 796, 646, - /* 160 */ 192, 291, 644, 798, 120, 807, 543, 911, 920, 652, - /* 170 */ 924, 922, 232, 698, 801, 971, 39, 220, 731, 442, - /* 180 */ 902, -199, 979, -43, 421, 896, 942, 605, -184, -126, - /* 190 */ 155, 172, 281, 304, 377, 538, 650, 690, 699, 723, - /* 200 */ 803, 839, 853, 919, 991, 1018, 1067, 1092, 951, 1111, - /* 210 */ 1112, 1115, 1116, 1117, 1119, 1120, 1121, 1122, 1123, 1124, - /* 220 */ 1125, 1012, 1096, 1097, 1128, 1129, 1130, 1131, 1070, 1135, - /* 230 */ 1137, 1152, 1077, 1153, 1155, 1114, 1156, 304, 1158, 1172, - /* 240 */ 1173, 1174, 1175, 1176, 1089, 1091, 1133, 1098, 1126, 1139, - /* 250 */ 1140, 1070, 1133, 1133, 1170, 1163, 1186, 1103, 1168, 1138, - /* 260 */ 1141, 1110, 1169, 1171, 1132, 1177, 1189, 1194, 1181, 1200, - /* 270 */ 1204, 1166, 1145, 1178, 1187, 1232, 1142, 1231, 1233, 1149, - /* 280 */ 1150, 1238, 1179, 1182, 1212, 1205, 1219, 1220, 1221, 1222, - /* 290 */ 1258, 1266, 1223, 1224, 1206, 1211, 1237, 1239, 1230, 1269, - /* 300 */ 1272, 1195, 1197, 1280, 1284, 1268, 1285, 1289, 1290, 1293, - /* 310 */ 1274, 1286, 1287, 1288, 1282, 1294, 1292, 1297, 1300, 1296, - /* 320 */ 1301, 1306, 1304, 1249, 1250, 1308, 1271, 1275, 1273, 1276, - /* 330 */ 1279, 1281, 1283, 1302, 1334, 1307, 1243, 1267, 1318, 1322, - /* 340 */ 1303, 1371, 1299, 1328, 1332, 1340, 1342, 1384, 1391, 1400, - /* 350 */ 1403, 1407, 1408, 1409, 1311, 1312, 1310, 1405, 1402, 1412, - /* 360 */ 1417, 1420, 1406, 1393, 1395, 1421, 1422, 1423, 1424, 1415, + /* 0 */ -170, -18, -159, 309, 313, -167, -19, 75, 117, 211, + /* 10 */ 315, 317, -165, -195, -168, -260, 389, 437, 475, 524, + /* 20 */ 527, -169, 529, 531, -28, 80, 534, 239, 304, 412, + /* 30 */ 558, 577, 37, 120, 368, -22, 460, 517, 555, 560, + /* 40 */ 562, 586, -257, -257, -257, -257, -257, -257, -257, -257, + /* 50 */ -257, -257, -257, -257, -257, -257, -257, -257, -257, -257, + /* 60 */ -257, -257, -257, -257, -257, -257, -257, -257, -257, -257, + /* 70 */ -257, -257, -257, -257, -257, -257, -257, -172, 457, 628, + /* 80 */ 673, 692, 694, 702, 704, 722, 728, 740, 743, 748, + /* 90 */ 767, 791, 815, 818, 820, 822, 857, 861, 864, 866, + /* 100 */ 868, 870, 872, 874, 876, 881, 900, 902, 906, 908, + /* 110 */ 910, 912, 915, 917, 920, 960, 962, 964, 988, 990, + /* 120 */ 992, 1016, 1029, 1032, -257, -257, -257, -257, -257, -257, + /* 130 */ -257, -257, -257, 271, 618, -190, 68, 60, 240, -124, + /* 140 */ 603, 610, 603, 610, 12, -257, -257, -257, -257, -128, + /* 150 */ -128, -128, -142, 25, 270, 281, 333, 124, 236, 648, + /* 160 */ 374, 465, 465, 28, 598, 792, 839, 469, 38, 381, + /* 170 */ 622, 709, 173, 699, 522, 703, 808, 811, 867, 816, + /* 180 */ -104, 823, -3, 875, 649, 753, 323, -88, 882, 884, + /* 190 */ 518, 43, 325, 899, 763, 604, 879, 969, 402, -193, + /* 200 */ -189, -180, -151, -55, 69, 104, 141, 259, 286, 360, + /* 210 */ 364, 455, 474, 481, 510, 516, 611, 653, 788, 99, + /* 220 */ 871, 878, 995, 1009, 1049, 1081, 1115, 1134, 1136, 1138, + /* 230 */ 1139, 1140, 733, 1110, 1112, 1144, 1145, 1146, 1148, 1084, + /* 240 */ 1161, 1162, 1163, 1089, 1047, 1165, 1166, 1127, 1169, 104, + /* 250 */ 1181, 1182, 1183, 1184, 1185, 1187, 1098, 1100, 1150, 1131, + /* 260 */ 1132, 1135, 1141, 1084, 1150, 1150, 1152, 1173, 1196, 1097, + /* 270 */ 1153, 1143, 1167, 1103, 1154, 1155, 1104, 1176, 1174, 1199, + /* 280 */ 1178, 1186, 1188, 1168, 1158, 1160, 1170, 1159, 1201, 1230, + /* 290 */ 1156, 1243, 1244, 1157, 1164, 1247, 1172, 1189, 1192, 1240, + /* 300 */ 1231, 1241, 1242, 1256, 1257, 1278, 1294, 1251, 1252, 1232, + /* 310 */ 1234, 1265, 1266, 1259, 1301, 1303, 1223, 1225, 1307, 1313, + /* 320 */ 1295, 1317, 1319, 1320, 1323, 1299, 1306, 1308, 1309, 1305, + /* 330 */ 1311, 1315, 1314, 1321, 1312, 1324, 1326, 1327, 1263, 1271, + /* 340 */ 1331, 1296, 1298, 1300, 1302, 1304, 1310, 1316, 1318, 1357, + /* 350 */ 1255, 1260, 1329, 1325, 1332, 1370, 1333, 1338, 1341, 1343, + /* 360 */ 1346, 1390, 1393, 1403, 1405, 1416, 1417, 1418, 1328, 1330, + /* 370 */ 1335, 1409, 1394, 1399, 1401, 1402, 1410, 1391, 1396, 1411, + /* 380 */ 1420, 1413, 1415, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1492, 1492, 1492, 1340, 1123, 1229, 1123, 1123, 1123, 1340, - /* 10 */ 1340, 1340, 1123, 1259, 1259, 1391, 1154, 1123, 1123, 1123, - /* 20 */ 1123, 1123, 1123, 1123, 1339, 1123, 1123, 1123, 1123, 1123, - /* 30 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1265, 1123, - /* 40 */ 1123, 1123, 1123, 1123, 1341, 1342, 1123, 1123, 1123, 1390, - /* 50 */ 1392, 1275, 1274, 1273, 1272, 1373, 1246, 1270, 1263, 1267, - /* 60 */ 1335, 1336, 1334, 1338, 1342, 1341, 1123, 1266, 1306, 1320, - /* 70 */ 1305, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 80 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 90 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 100 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 110 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1314, 1319, 1325, - /* 120 */ 1318, 1315, 1308, 1307, 1309, 1310, 1123, 1144, 1193, 1123, - /* 130 */ 1123, 1123, 1123, 1409, 1408, 1123, 1123, 1154, 1311, 1312, - /* 140 */ 1322, 1321, 1398, 1448, 1447, 1123, 1123, 1123, 1123, 1123, - /* 150 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 160 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 170 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1154, 1150, 1300, - /* 180 */ 1299, 1418, 1150, 1253, 1123, 1404, 1229, 1220, 1123, 1123, - /* 190 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 200 */ 1123, 1395, 1393, 1123, 1355, 1123, 1123, 1123, 1123, 1123, - /* 210 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 220 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 230 */ 1123, 1123, 1225, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 240 */ 1123, 1123, 1123, 1442, 1123, 1368, 1207, 1225, 1225, 1225, - /* 250 */ 1225, 1227, 1208, 1206, 1219, 1154, 1130, 1484, 1269, 1248, - /* 260 */ 1248, 1481, 1269, 1269, 1481, 1168, 1462, 1165, 1259, 1259, - /* 270 */ 1259, 1248, 1337, 1226, 1219, 1123, 1484, 1234, 1234, 1483, - /* 280 */ 1483, 1234, 1278, 1284, 1196, 1269, 1202, 1202, 1202, 1202, - /* 290 */ 1234, 1141, 1269, 1269, 1278, 1284, 1196, 1196, 1269, 1234, - /* 300 */ 1141, 1372, 1478, 1234, 1141, 1348, 1234, 1141, 1234, 1141, - /* 310 */ 1348, 1194, 1194, 1194, 1183, 1348, 1194, 1168, 1194, 1183, - /* 320 */ 1194, 1194, 1348, 1352, 1352, 1348, 1252, 1247, 1252, 1247, - /* 330 */ 1252, 1247, 1252, 1247, 1234, 1253, 1417, 1123, 1264, 1253, - /* 340 */ 1343, 1234, 1123, 1264, 1262, 1260, 1269, 1147, 1186, 1445, - /* 350 */ 1445, 1441, 1441, 1441, 1489, 1489, 1404, 1457, 1154, 1154, - /* 360 */ 1154, 1154, 1457, 1170, 1170, 1154, 1154, 1154, 1154, 1457, - /* 370 */ 1123, 1123, 1123, 1123, 1123, 1123, 1452, 1123, 1357, 1238, - /* 380 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 390 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 400 */ 1123, 1123, 1289, 1123, 1126, 1401, 1123, 1123, 1399, 1123, - /* 410 */ 1123, 1123, 1123, 1123, 1123, 1239, 1123, 1123, 1123, 1123, - /* 420 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 430 */ 1123, 1123, 1123, 1123, 1480, 1123, 1123, 1123, 1123, 1123, - /* 440 */ 1123, 1371, 1370, 1123, 1123, 1236, 1123, 1123, 1123, 1123, - /* 450 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 460 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 470 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 480 */ 1123, 1123, 1123, 1261, 1123, 1416, 1123, 1123, 1123, 1123, - /* 490 */ 1123, 1123, 1123, 1430, 1254, 1123, 1123, 1471, 1123, 1123, - /* 500 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, - /* 510 */ 1123, 1123, 1466, 1210, 1291, 1123, 1290, 1294, 1123, 1135, - /* 520 */ 1123, + /* 0 */ 1537, 1537, 1537, 1377, 1159, 1266, 1159, 1159, 1159, 1377, + /* 10 */ 1377, 1377, 1159, 1296, 1296, 1430, 1190, 1159, 1159, 1159, + /* 20 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1376, 1159, 1159, + /* 30 */ 1159, 1159, 1460, 1460, 1159, 1159, 1159, 1159, 1159, 1159, + /* 40 */ 1159, 1159, 1159, 1302, 1159, 1159, 1159, 1159, 1159, 1378, + /* 50 */ 1379, 1159, 1159, 1159, 1429, 1431, 1394, 1312, 1311, 1310, + /* 60 */ 1309, 1412, 1283, 1307, 1300, 1304, 1372, 1373, 1371, 1375, + /* 70 */ 1379, 1378, 1159, 1303, 1343, 1357, 1342, 1159, 1159, 1159, + /* 80 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 90 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 100 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 110 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 120 */ 1159, 1159, 1159, 1159, 1351, 1356, 1362, 1355, 1352, 1345, + /* 130 */ 1344, 1346, 1347, 1159, 1180, 1230, 1159, 1159, 1159, 1159, + /* 140 */ 1448, 1447, 1159, 1159, 1190, 1348, 1349, 1359, 1358, 1437, + /* 150 */ 1493, 1492, 1395, 1159, 1159, 1159, 1159, 1159, 1159, 1460, + /* 160 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 170 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 180 */ 1159, 1159, 1159, 1159, 1460, 1460, 1159, 1190, 1460, 1460, + /* 190 */ 1186, 1337, 1336, 1186, 1290, 1159, 1443, 1266, 1257, 1159, + /* 200 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 210 */ 1159, 1159, 1159, 1434, 1432, 1159, 1159, 1159, 1159, 1159, + /* 220 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 230 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 240 */ 1159, 1159, 1159, 1262, 1159, 1159, 1159, 1159, 1159, 1159, + /* 250 */ 1159, 1159, 1159, 1159, 1159, 1487, 1159, 1407, 1244, 1262, + /* 260 */ 1262, 1262, 1262, 1264, 1245, 1243, 1256, 1191, 1166, 1529, + /* 270 */ 1306, 1285, 1285, 1526, 1306, 1306, 1526, 1205, 1507, 1202, + /* 280 */ 1296, 1296, 1296, 1285, 1290, 1290, 1374, 1263, 1256, 1159, + /* 290 */ 1529, 1271, 1271, 1528, 1528, 1271, 1395, 1315, 1321, 1233, + /* 300 */ 1306, 1239, 1239, 1239, 1239, 1271, 1177, 1306, 1306, 1315, + /* 310 */ 1321, 1233, 1233, 1306, 1271, 1177, 1411, 1523, 1271, 1177, + /* 320 */ 1385, 1271, 1177, 1271, 1177, 1385, 1231, 1231, 1231, 1220, + /* 330 */ 1385, 1231, 1205, 1231, 1220, 1231, 1231, 1385, 1389, 1389, + /* 340 */ 1385, 1289, 1284, 1289, 1284, 1289, 1284, 1289, 1284, 1271, + /* 350 */ 1470, 1470, 1301, 1290, 1380, 1271, 1159, 1301, 1299, 1297, + /* 360 */ 1306, 1183, 1223, 1490, 1490, 1486, 1486, 1486, 1534, 1534, + /* 370 */ 1443, 1502, 1190, 1190, 1190, 1190, 1502, 1207, 1207, 1191, + /* 380 */ 1191, 1190, 1502, 1159, 1159, 1159, 1159, 1159, 1159, 1497, + /* 390 */ 1159, 1396, 1275, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 400 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 410 */ 1159, 1159, 1159, 1159, 1159, 1326, 1159, 1162, 1440, 1159, + /* 420 */ 1159, 1438, 1159, 1159, 1159, 1159, 1159, 1159, 1276, 1159, + /* 430 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 440 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1525, 1159, 1159, + /* 450 */ 1159, 1159, 1159, 1159, 1410, 1409, 1159, 1159, 1273, 1159, + /* 460 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 470 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 480 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 490 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1298, 1159, 1159, + /* 500 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 510 */ 1159, 1159, 1475, 1291, 1159, 1159, 1516, 1159, 1159, 1159, + /* 520 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 530 */ 1159, 1511, 1247, 1328, 1159, 1327, 1331, 1159, 1171, 1159, }; /********** End of lemon-generated parsing tables *****************************/ @@ -146935,6 +149758,10 @@ static const YYCODETYPE yyFallback[] = { 59, /* PRECEDING => ID */ 59, /* RANGE => ID */ 59, /* UNBOUNDED => ID */ + 59, /* EXCLUDE => ID */ + 59, /* GROUPS => ID */ + 59, /* OTHERS => ID */ + 59, /* TIES => ID */ 59, /* REINDEX => ID */ 59, /* RENAME => ID */ 59, /* CTIME_KW => ID */ @@ -147113,195 +149940,220 @@ static const char *const yyTokenName[] = { /* 85 */ "PRECEDING", /* 86 */ "RANGE", /* 87 */ "UNBOUNDED", - /* 88 */ "REINDEX", - /* 89 */ "RENAME", - /* 90 */ "CTIME_KW", - /* 91 */ "ANY", - /* 92 */ "BITAND", - /* 93 */ "BITOR", - /* 94 */ "LSHIFT", - /* 95 */ "RSHIFT", - /* 96 */ "PLUS", - /* 97 */ "MINUS", - /* 98 */ "STAR", - /* 99 */ "SLASH", - /* 100 */ "REM", - /* 101 */ "CONCAT", - /* 102 */ "COLLATE", - /* 103 */ "BITNOT", - /* 104 */ "ON", - /* 105 */ "INDEXED", - /* 106 */ "STRING", - /* 107 */ "JOIN_KW", - /* 108 */ "CONSTRAINT", - /* 109 */ "DEFAULT", - /* 110 */ "NULL", - /* 111 */ "PRIMARY", - /* 112 */ "UNIQUE", - /* 113 */ "CHECK", - /* 114 */ "REFERENCES", - /* 115 */ "AUTOINCR", - /* 116 */ "INSERT", - /* 117 */ "DELETE", - /* 118 */ "UPDATE", - /* 119 */ "SET", - /* 120 */ "DEFERRABLE", - /* 121 */ "FOREIGN", - /* 122 */ "DROP", - /* 123 */ "UNION", - /* 124 */ "ALL", - /* 125 */ "EXCEPT", - /* 126 */ "INTERSECT", - /* 127 */ "SELECT", - /* 128 */ "VALUES", - /* 129 */ "DISTINCT", - /* 130 */ "DOT", - /* 131 */ "FROM", - /* 132 */ "JOIN", - /* 133 */ "USING", - /* 134 */ "ORDER", - /* 135 */ "GROUP", - /* 136 */ "HAVING", - /* 137 */ "LIMIT", - /* 138 */ "WHERE", - /* 139 */ "INTO", - /* 140 */ "NOTHING", - /* 141 */ "FLOAT", - /* 142 */ "BLOB", - /* 143 */ "INTEGER", - /* 144 */ "VARIABLE", - /* 145 */ "CASE", - /* 146 */ "WHEN", - /* 147 */ "THEN", - /* 148 */ "ELSE", - /* 149 */ "INDEX", - /* 150 */ "ALTER", - /* 151 */ "ADD", - /* 152 */ "WINDOW", - /* 153 */ "OVER", - /* 154 */ "FILTER", - /* 155 */ "input", - /* 156 */ "cmdlist", - /* 157 */ "ecmd", - /* 158 */ "cmdx", - /* 159 */ "explain", - /* 160 */ "cmd", - /* 161 */ "transtype", - /* 162 */ "trans_opt", - /* 163 */ "nm", - /* 164 */ "savepoint_opt", - /* 165 */ "create_table", - /* 166 */ "create_table_args", - /* 167 */ "createkw", - /* 168 */ "temp", - /* 169 */ "ifnotexists", - /* 170 */ "dbnm", - /* 171 */ "columnlist", - /* 172 */ "conslist_opt", - /* 173 */ "table_options", - /* 174 */ "select", - /* 175 */ "columnname", - /* 176 */ "carglist", - /* 177 */ "typetoken", - /* 178 */ "typename", - /* 179 */ "signed", - /* 180 */ "plus_num", - /* 181 */ "minus_num", - /* 182 */ "scanpt", - /* 183 */ "ccons", - /* 184 */ "term", - /* 185 */ "expr", - /* 186 */ "onconf", - /* 187 */ "sortorder", - /* 188 */ "autoinc", - /* 189 */ "eidlist_opt", - /* 190 */ "refargs", - /* 191 */ "defer_subclause", - /* 192 */ "refarg", - /* 193 */ "refact", - /* 194 */ "init_deferred_pred_opt", - /* 195 */ "conslist", - /* 196 */ "tconscomma", - /* 197 */ "tcons", - /* 198 */ "sortlist", - /* 199 */ "eidlist", - /* 200 */ "defer_subclause_opt", - /* 201 */ "orconf", - /* 202 */ "resolvetype", - /* 203 */ "raisetype", - /* 204 */ "ifexists", - /* 205 */ "fullname", - /* 206 */ "selectnowith", - /* 207 */ "oneselect", - /* 208 */ "wqlist", - /* 209 */ "multiselect_op", - /* 210 */ "distinct", - /* 211 */ "selcollist", - /* 212 */ "from", - /* 213 */ "where_opt", - /* 214 */ "groupby_opt", - /* 215 */ "having_opt", - /* 216 */ "orderby_opt", - /* 217 */ "limit_opt", - /* 218 */ "window_clause", - /* 219 */ "values", - /* 220 */ "nexprlist", - /* 221 */ "sclp", - /* 222 */ "as", - /* 223 */ "seltablist", - /* 224 */ "stl_prefix", - /* 225 */ "joinop", - /* 226 */ "indexed_opt", - /* 227 */ "on_opt", - /* 228 */ "using_opt", - /* 229 */ "exprlist", - /* 230 */ "xfullname", - /* 231 */ "idlist", - /* 232 */ "with", - /* 233 */ "setlist", - /* 234 */ "insert_cmd", - /* 235 */ "idlist_opt", - /* 236 */ "upsert", - /* 237 */ "over_clause", - /* 238 */ "likeop", - /* 239 */ "between_op", - /* 240 */ "in_op", - /* 241 */ "paren_exprlist", - /* 242 */ "case_operand", - /* 243 */ "case_exprlist", - /* 244 */ "case_else", - /* 245 */ "uniqueflag", - /* 246 */ "collate", - /* 247 */ "nmnum", - /* 248 */ "trigger_decl", - /* 249 */ "trigger_cmd_list", - /* 250 */ "trigger_time", - /* 251 */ "trigger_event", - /* 252 */ "foreach_clause", - /* 253 */ "when_clause", - /* 254 */ "trigger_cmd", - /* 255 */ "trnm", - /* 256 */ "tridxby", - /* 257 */ "database_kw_opt", - /* 258 */ "key_opt", - /* 259 */ "add_column_fullname", - /* 260 */ "kwcolumn_opt", - /* 261 */ "create_vtab", - /* 262 */ "vtabarglist", - /* 263 */ "vtabarg", - /* 264 */ "vtabargtoken", - /* 265 */ "lp", - /* 266 */ "anylist", - /* 267 */ "windowdefn_list", - /* 268 */ "windowdefn", - /* 269 */ "window", - /* 270 */ "frame_opt", - /* 271 */ "part_opt", - /* 272 */ "filter_opt", - /* 273 */ "range_or_rows", - /* 274 */ "frame_bound", - /* 275 */ "frame_bound_s", - /* 276 */ "frame_bound_e", + /* 88 */ "EXCLUDE", + /* 89 */ "GROUPS", + /* 90 */ "OTHERS", + /* 91 */ "TIES", + /* 92 */ "REINDEX", + /* 93 */ "RENAME", + /* 94 */ "CTIME_KW", + /* 95 */ "ANY", + /* 96 */ "BITAND", + /* 97 */ "BITOR", + /* 98 */ "LSHIFT", + /* 99 */ "RSHIFT", + /* 100 */ "PLUS", + /* 101 */ "MINUS", + /* 102 */ "STAR", + /* 103 */ "SLASH", + /* 104 */ "REM", + /* 105 */ "CONCAT", + /* 106 */ "COLLATE", + /* 107 */ "BITNOT", + /* 108 */ "ON", + /* 109 */ "INDEXED", + /* 110 */ "STRING", + /* 111 */ "JOIN_KW", + /* 112 */ "CONSTRAINT", + /* 113 */ "DEFAULT", + /* 114 */ "NULL", + /* 115 */ "PRIMARY", + /* 116 */ "UNIQUE", + /* 117 */ "CHECK", + /* 118 */ "REFERENCES", + /* 119 */ "AUTOINCR", + /* 120 */ "INSERT", + /* 121 */ "DELETE", + /* 122 */ "UPDATE", + /* 123 */ "SET", + /* 124 */ "DEFERRABLE", + /* 125 */ "FOREIGN", + /* 126 */ "DROP", + /* 127 */ "UNION", + /* 128 */ "ALL", + /* 129 */ "EXCEPT", + /* 130 */ "INTERSECT", + /* 131 */ "SELECT", + /* 132 */ "VALUES", + /* 133 */ "DISTINCT", + /* 134 */ "DOT", + /* 135 */ "FROM", + /* 136 */ "JOIN", + /* 137 */ "USING", + /* 138 */ "ORDER", + /* 139 */ "GROUP", + /* 140 */ "HAVING", + /* 141 */ "LIMIT", + /* 142 */ "WHERE", + /* 143 */ "INTO", + /* 144 */ "NOTHING", + /* 145 */ "FLOAT", + /* 146 */ "BLOB", + /* 147 */ "INTEGER", + /* 148 */ "VARIABLE", + /* 149 */ "CASE", + /* 150 */ "WHEN", + /* 151 */ "THEN", + /* 152 */ "ELSE", + /* 153 */ "INDEX", + /* 154 */ "ALTER", + /* 155 */ "ADD", + /* 156 */ "WINDOW", + /* 157 */ "OVER", + /* 158 */ "FILTER", + /* 159 */ "TRUEFALSE", + /* 160 */ "ISNOT", + /* 161 */ "FUNCTION", + /* 162 */ "COLUMN", + /* 163 */ "AGG_FUNCTION", + /* 164 */ "AGG_COLUMN", + /* 165 */ "UMINUS", + /* 166 */ "UPLUS", + /* 167 */ "TRUTH", + /* 168 */ "REGISTER", + /* 169 */ "VECTOR", + /* 170 */ "SELECT_COLUMN", + /* 171 */ "IF_NULL_ROW", + /* 172 */ "ASTERISK", + /* 173 */ "SPAN", + /* 174 */ "SPACE", + /* 175 */ "ILLEGAL", + /* 176 */ "input", + /* 177 */ "cmdlist", + /* 178 */ "ecmd", + /* 179 */ "cmdx", + /* 180 */ "explain", + /* 181 */ "cmd", + /* 182 */ "transtype", + /* 183 */ "trans_opt", + /* 184 */ "nm", + /* 185 */ "savepoint_opt", + /* 186 */ "create_table", + /* 187 */ "create_table_args", + /* 188 */ "createkw", + /* 189 */ "temp", + /* 190 */ "ifnotexists", + /* 191 */ "dbnm", + /* 192 */ "columnlist", + /* 193 */ "conslist_opt", + /* 194 */ "table_options", + /* 195 */ "select", + /* 196 */ "columnname", + /* 197 */ "carglist", + /* 198 */ "typetoken", + /* 199 */ "typename", + /* 200 */ "signed", + /* 201 */ "plus_num", + /* 202 */ "minus_num", + /* 203 */ "scanpt", + /* 204 */ "scantok", + /* 205 */ "ccons", + /* 206 */ "term", + /* 207 */ "expr", + /* 208 */ "onconf", + /* 209 */ "sortorder", + /* 210 */ "autoinc", + /* 211 */ "eidlist_opt", + /* 212 */ "refargs", + /* 213 */ "defer_subclause", + /* 214 */ "refarg", + /* 215 */ "refact", + /* 216 */ "init_deferred_pred_opt", + /* 217 */ "conslist", + /* 218 */ "tconscomma", + /* 219 */ "tcons", + /* 220 */ "sortlist", + /* 221 */ "eidlist", + /* 222 */ "defer_subclause_opt", + /* 223 */ "orconf", + /* 224 */ "resolvetype", + /* 225 */ "raisetype", + /* 226 */ "ifexists", + /* 227 */ "fullname", + /* 228 */ "selectnowith", + /* 229 */ "oneselect", + /* 230 */ "wqlist", + /* 231 */ "multiselect_op", + /* 232 */ "distinct", + /* 233 */ "selcollist", + /* 234 */ "from", + /* 235 */ "where_opt", + /* 236 */ "groupby_opt", + /* 237 */ "having_opt", + /* 238 */ "orderby_opt", + /* 239 */ "limit_opt", + /* 240 */ "window_clause", + /* 241 */ "values", + /* 242 */ "nexprlist", + /* 243 */ "sclp", + /* 244 */ "as", + /* 245 */ "seltablist", + /* 246 */ "stl_prefix", + /* 247 */ "joinop", + /* 248 */ "indexed_opt", + /* 249 */ "on_opt", + /* 250 */ "using_opt", + /* 251 */ "exprlist", + /* 252 */ "xfullname", + /* 253 */ "idlist", + /* 254 */ "with", + /* 255 */ "setlist", + /* 256 */ "insert_cmd", + /* 257 */ "idlist_opt", + /* 258 */ "upsert", + /* 259 */ "over_clause", + /* 260 */ "likeop", + /* 261 */ "between_op", + /* 262 */ "in_op", + /* 263 */ "paren_exprlist", + /* 264 */ "case_operand", + /* 265 */ "case_exprlist", + /* 266 */ "case_else", + /* 267 */ "uniqueflag", + /* 268 */ "collate", + /* 269 */ "vinto", + /* 270 */ "nmnum", + /* 271 */ "trigger_decl", + /* 272 */ "trigger_cmd_list", + /* 273 */ "trigger_time", + /* 274 */ "trigger_event", + /* 275 */ "foreach_clause", + /* 276 */ "when_clause", + /* 277 */ "trigger_cmd", + /* 278 */ "trnm", + /* 279 */ "tridxby", + /* 280 */ "database_kw_opt", + /* 281 */ "key_opt", + /* 282 */ "add_column_fullname", + /* 283 */ "kwcolumn_opt", + /* 284 */ "create_vtab", + /* 285 */ "vtabarglist", + /* 286 */ "vtabarg", + /* 287 */ "vtabargtoken", + /* 288 */ "lp", + /* 289 */ "anylist", + /* 290 */ "windowdefn_list", + /* 291 */ "windowdefn", + /* 292 */ "window", + /* 293 */ "frame_opt", + /* 294 */ "part_opt", + /* 295 */ "filter_opt", + /* 296 */ "range_or_rows", + /* 297 */ "frame_bound", + /* 298 */ "frame_bound_s", + /* 299 */ "frame_bound_e", + /* 300 */ "frame_exclude_opt", + /* 301 */ "frame_exclude", }; #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ @@ -147338,344 +150190,353 @@ static const char *const yyRuleName[] = { /* 26 */ "typetoken ::= typename LP signed COMMA signed RP", /* 27 */ "typename ::= typename ID|STRING", /* 28 */ "scanpt ::=", - /* 29 */ "ccons ::= CONSTRAINT nm", - /* 30 */ "ccons ::= DEFAULT scanpt term scanpt", - /* 31 */ "ccons ::= DEFAULT LP expr RP", - /* 32 */ "ccons ::= DEFAULT PLUS term scanpt", - /* 33 */ "ccons ::= DEFAULT MINUS term scanpt", - /* 34 */ "ccons ::= DEFAULT scanpt ID|INDEXED", - /* 35 */ "ccons ::= NOT NULL onconf", - /* 36 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", - /* 37 */ "ccons ::= UNIQUE onconf", - /* 38 */ "ccons ::= CHECK LP expr RP", - /* 39 */ "ccons ::= REFERENCES nm eidlist_opt refargs", - /* 40 */ "ccons ::= defer_subclause", - /* 41 */ "ccons ::= COLLATE ID|STRING", - /* 42 */ "autoinc ::=", - /* 43 */ "autoinc ::= AUTOINCR", - /* 44 */ "refargs ::=", - /* 45 */ "refargs ::= refargs refarg", - /* 46 */ "refarg ::= MATCH nm", - /* 47 */ "refarg ::= ON INSERT refact", - /* 48 */ "refarg ::= ON DELETE refact", - /* 49 */ "refarg ::= ON UPDATE refact", - /* 50 */ "refact ::= SET NULL", - /* 51 */ "refact ::= SET DEFAULT", - /* 52 */ "refact ::= CASCADE", - /* 53 */ "refact ::= RESTRICT", - /* 54 */ "refact ::= NO ACTION", - /* 55 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", - /* 56 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", - /* 57 */ "init_deferred_pred_opt ::=", - /* 58 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", - /* 59 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", - /* 60 */ "conslist_opt ::=", - /* 61 */ "tconscomma ::= COMMA", - /* 62 */ "tcons ::= CONSTRAINT nm", - /* 63 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", - /* 64 */ "tcons ::= UNIQUE LP sortlist RP onconf", - /* 65 */ "tcons ::= CHECK LP expr RP onconf", - /* 66 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", - /* 67 */ "defer_subclause_opt ::=", - /* 68 */ "onconf ::=", - /* 69 */ "onconf ::= ON CONFLICT resolvetype", - /* 70 */ "orconf ::=", - /* 71 */ "orconf ::= OR resolvetype", - /* 72 */ "resolvetype ::= IGNORE", - /* 73 */ "resolvetype ::= REPLACE", - /* 74 */ "cmd ::= DROP TABLE ifexists fullname", - /* 75 */ "ifexists ::= IF EXISTS", - /* 76 */ "ifexists ::=", - /* 77 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", - /* 78 */ "cmd ::= DROP VIEW ifexists fullname", - /* 79 */ "cmd ::= select", - /* 80 */ "select ::= WITH wqlist selectnowith", - /* 81 */ "select ::= WITH RECURSIVE wqlist selectnowith", - /* 82 */ "select ::= selectnowith", - /* 83 */ "selectnowith ::= selectnowith multiselect_op oneselect", - /* 84 */ "multiselect_op ::= UNION", - /* 85 */ "multiselect_op ::= UNION ALL", - /* 86 */ "multiselect_op ::= EXCEPT|INTERSECT", - /* 87 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 88 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", - /* 89 */ "values ::= VALUES LP nexprlist RP", - /* 90 */ "values ::= values COMMA LP nexprlist RP", - /* 91 */ "distinct ::= DISTINCT", - /* 92 */ "distinct ::= ALL", - /* 93 */ "distinct ::=", - /* 94 */ "sclp ::=", - /* 95 */ "selcollist ::= sclp scanpt expr scanpt as", - /* 96 */ "selcollist ::= sclp scanpt STAR", - /* 97 */ "selcollist ::= sclp scanpt nm DOT STAR", - /* 98 */ "as ::= AS nm", - /* 99 */ "as ::=", - /* 100 */ "from ::=", - /* 101 */ "from ::= FROM seltablist", - /* 102 */ "stl_prefix ::= seltablist joinop", - /* 103 */ "stl_prefix ::=", - /* 104 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", - /* 105 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", - /* 106 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", - /* 107 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", - /* 108 */ "dbnm ::=", - /* 109 */ "dbnm ::= DOT nm", - /* 110 */ "fullname ::= nm", - /* 111 */ "fullname ::= nm DOT nm", - /* 112 */ "xfullname ::= nm", - /* 113 */ "xfullname ::= nm DOT nm", - /* 114 */ "xfullname ::= nm DOT nm AS nm", - /* 115 */ "xfullname ::= nm AS nm", - /* 116 */ "joinop ::= COMMA|JOIN", - /* 117 */ "joinop ::= JOIN_KW JOIN", - /* 118 */ "joinop ::= JOIN_KW nm JOIN", - /* 119 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 120 */ "on_opt ::= ON expr", - /* 121 */ "on_opt ::=", - /* 122 */ "indexed_opt ::=", - /* 123 */ "indexed_opt ::= INDEXED BY nm", - /* 124 */ "indexed_opt ::= NOT INDEXED", - /* 125 */ "using_opt ::= USING LP idlist RP", - /* 126 */ "using_opt ::=", - /* 127 */ "orderby_opt ::=", - /* 128 */ "orderby_opt ::= ORDER BY sortlist", - /* 129 */ "sortlist ::= sortlist COMMA expr sortorder", - /* 130 */ "sortlist ::= expr sortorder", - /* 131 */ "sortorder ::= ASC", - /* 132 */ "sortorder ::= DESC", - /* 133 */ "sortorder ::=", - /* 134 */ "groupby_opt ::=", - /* 135 */ "groupby_opt ::= GROUP BY nexprlist", - /* 136 */ "having_opt ::=", - /* 137 */ "having_opt ::= HAVING expr", - /* 138 */ "limit_opt ::=", - /* 139 */ "limit_opt ::= LIMIT expr", - /* 140 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 141 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 142 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt", - /* 143 */ "where_opt ::=", - /* 144 */ "where_opt ::= WHERE expr", - /* 145 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt", - /* 146 */ "setlist ::= setlist COMMA nm EQ expr", - /* 147 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", - /* 148 */ "setlist ::= nm EQ expr", - /* 149 */ "setlist ::= LP idlist RP EQ expr", - /* 150 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", - /* 151 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES", - /* 152 */ "upsert ::=", - /* 153 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt", - /* 154 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING", - /* 155 */ "upsert ::= ON CONFLICT DO NOTHING", - /* 156 */ "insert_cmd ::= INSERT orconf", - /* 157 */ "insert_cmd ::= REPLACE", - /* 158 */ "idlist_opt ::=", - /* 159 */ "idlist_opt ::= LP idlist RP", - /* 160 */ "idlist ::= idlist COMMA nm", - /* 161 */ "idlist ::= nm", - /* 162 */ "expr ::= LP expr RP", - /* 163 */ "expr ::= ID|INDEXED", - /* 164 */ "expr ::= JOIN_KW", - /* 165 */ "expr ::= nm DOT nm", - /* 166 */ "expr ::= nm DOT nm DOT nm", - /* 167 */ "term ::= NULL|FLOAT|BLOB", - /* 168 */ "term ::= STRING", - /* 169 */ "term ::= INTEGER", - /* 170 */ "expr ::= VARIABLE", - /* 171 */ "expr ::= expr COLLATE ID|STRING", - /* 172 */ "expr ::= CAST LP expr AS typetoken RP", - /* 173 */ "expr ::= ID|INDEXED LP distinct exprlist RP", - /* 174 */ "expr ::= ID|INDEXED LP STAR RP", - /* 175 */ "expr ::= ID|INDEXED LP distinct exprlist RP over_clause", - /* 176 */ "expr ::= ID|INDEXED LP STAR RP over_clause", - /* 177 */ "term ::= CTIME_KW", - /* 178 */ "expr ::= LP nexprlist COMMA expr RP", - /* 179 */ "expr ::= expr AND expr", - /* 180 */ "expr ::= expr OR expr", - /* 181 */ "expr ::= expr LT|GT|GE|LE expr", - /* 182 */ "expr ::= expr EQ|NE expr", - /* 183 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 184 */ "expr ::= expr PLUS|MINUS expr", - /* 185 */ "expr ::= expr STAR|SLASH|REM expr", - /* 186 */ "expr ::= expr CONCAT expr", - /* 187 */ "likeop ::= NOT LIKE_KW|MATCH", - /* 188 */ "expr ::= expr likeop expr", - /* 189 */ "expr ::= expr likeop expr ESCAPE expr", - /* 190 */ "expr ::= expr ISNULL|NOTNULL", - /* 191 */ "expr ::= expr NOT NULL", - /* 192 */ "expr ::= expr IS expr", - /* 193 */ "expr ::= expr IS NOT expr", - /* 194 */ "expr ::= NOT expr", - /* 195 */ "expr ::= BITNOT expr", - /* 196 */ "expr ::= PLUS|MINUS expr", - /* 197 */ "between_op ::= BETWEEN", - /* 198 */ "between_op ::= NOT BETWEEN", - /* 199 */ "expr ::= expr between_op expr AND expr", - /* 200 */ "in_op ::= IN", - /* 201 */ "in_op ::= NOT IN", - /* 202 */ "expr ::= expr in_op LP exprlist RP", - /* 203 */ "expr ::= LP select RP", - /* 204 */ "expr ::= expr in_op LP select RP", - /* 205 */ "expr ::= expr in_op nm dbnm paren_exprlist", - /* 206 */ "expr ::= EXISTS LP select RP", - /* 207 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 208 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 209 */ "case_exprlist ::= WHEN expr THEN expr", - /* 210 */ "case_else ::= ELSE expr", - /* 211 */ "case_else ::=", - /* 212 */ "case_operand ::= expr", - /* 213 */ "case_operand ::=", - /* 214 */ "exprlist ::=", - /* 215 */ "nexprlist ::= nexprlist COMMA expr", - /* 216 */ "nexprlist ::= expr", - /* 217 */ "paren_exprlist ::=", - /* 218 */ "paren_exprlist ::= LP exprlist RP", - /* 219 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 220 */ "uniqueflag ::= UNIQUE", - /* 221 */ "uniqueflag ::=", - /* 222 */ "eidlist_opt ::=", - /* 223 */ "eidlist_opt ::= LP eidlist RP", - /* 224 */ "eidlist ::= eidlist COMMA nm collate sortorder", - /* 225 */ "eidlist ::= nm collate sortorder", - /* 226 */ "collate ::=", - /* 227 */ "collate ::= COLLATE ID|STRING", - /* 228 */ "cmd ::= DROP INDEX ifexists fullname", - /* 229 */ "cmd ::= VACUUM", - /* 230 */ "cmd ::= VACUUM nm", - /* 231 */ "cmd ::= PRAGMA nm dbnm", - /* 232 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 233 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 234 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 235 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 236 */ "plus_num ::= PLUS INTEGER|FLOAT", - /* 237 */ "minus_num ::= MINUS INTEGER|FLOAT", - /* 238 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", - /* 239 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 240 */ "trigger_time ::= BEFORE|AFTER", - /* 241 */ "trigger_time ::= INSTEAD OF", - /* 242 */ "trigger_time ::=", - /* 243 */ "trigger_event ::= DELETE|INSERT", - /* 244 */ "trigger_event ::= UPDATE", - /* 245 */ "trigger_event ::= UPDATE OF idlist", - /* 246 */ "when_clause ::=", - /* 247 */ "when_clause ::= WHEN expr", - /* 248 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 249 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 250 */ "trnm ::= nm DOT nm", - /* 251 */ "tridxby ::= INDEXED BY nm", - /* 252 */ "tridxby ::= NOT INDEXED", - /* 253 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt", - /* 254 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", - /* 255 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", - /* 256 */ "trigger_cmd ::= scanpt select scanpt", - /* 257 */ "expr ::= RAISE LP IGNORE RP", - /* 258 */ "expr ::= RAISE LP raisetype COMMA nm RP", - /* 259 */ "raisetype ::= ROLLBACK", - /* 260 */ "raisetype ::= ABORT", - /* 261 */ "raisetype ::= FAIL", - /* 262 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 263 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 264 */ "cmd ::= DETACH database_kw_opt expr", - /* 265 */ "key_opt ::=", - /* 266 */ "key_opt ::= KEY expr", - /* 267 */ "cmd ::= REINDEX", - /* 268 */ "cmd ::= REINDEX nm dbnm", - /* 269 */ "cmd ::= ANALYZE", - /* 270 */ "cmd ::= ANALYZE nm dbnm", - /* 271 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 272 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", - /* 273 */ "add_column_fullname ::= fullname", - /* 274 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", - /* 275 */ "cmd ::= create_vtab", - /* 276 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 277 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 278 */ "vtabarg ::=", - /* 279 */ "vtabargtoken ::= ANY", - /* 280 */ "vtabargtoken ::= lp anylist RP", - /* 281 */ "lp ::= LP", - /* 282 */ "with ::= WITH wqlist", - /* 283 */ "with ::= WITH RECURSIVE wqlist", - /* 284 */ "wqlist ::= nm eidlist_opt AS LP select RP", - /* 285 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", - /* 286 */ "windowdefn_list ::= windowdefn", - /* 287 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", - /* 288 */ "windowdefn ::= nm AS window", - /* 289 */ "window ::= LP part_opt orderby_opt frame_opt RP", - /* 290 */ "part_opt ::= PARTITION BY nexprlist", - /* 291 */ "part_opt ::=", - /* 292 */ "frame_opt ::=", - /* 293 */ "frame_opt ::= range_or_rows frame_bound_s", - /* 294 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e", - /* 295 */ "range_or_rows ::= RANGE", - /* 296 */ "range_or_rows ::= ROWS", - /* 297 */ "frame_bound_s ::= frame_bound", - /* 298 */ "frame_bound_s ::= UNBOUNDED PRECEDING", - /* 299 */ "frame_bound_e ::= frame_bound", - /* 300 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", - /* 301 */ "frame_bound ::= expr PRECEDING", - /* 302 */ "frame_bound ::= CURRENT ROW", - /* 303 */ "frame_bound ::= expr FOLLOWING", - /* 304 */ "window_clause ::= WINDOW windowdefn_list", - /* 305 */ "over_clause ::= filter_opt OVER window", - /* 306 */ "over_clause ::= filter_opt OVER nm", - /* 307 */ "filter_opt ::=", - /* 308 */ "filter_opt ::= FILTER LP WHERE expr RP", - /* 309 */ "input ::= cmdlist", - /* 310 */ "cmdlist ::= cmdlist ecmd", - /* 311 */ "cmdlist ::= ecmd", - /* 312 */ "ecmd ::= SEMI", - /* 313 */ "ecmd ::= cmdx SEMI", - /* 314 */ "ecmd ::= explain cmdx", - /* 315 */ "trans_opt ::=", - /* 316 */ "trans_opt ::= TRANSACTION", - /* 317 */ "trans_opt ::= TRANSACTION nm", - /* 318 */ "savepoint_opt ::= SAVEPOINT", - /* 319 */ "savepoint_opt ::=", - /* 320 */ "cmd ::= create_table create_table_args", - /* 321 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 322 */ "columnlist ::= columnname carglist", - /* 323 */ "nm ::= ID|INDEXED", - /* 324 */ "nm ::= STRING", - /* 325 */ "nm ::= JOIN_KW", - /* 326 */ "typetoken ::= typename", - /* 327 */ "typename ::= ID|STRING", - /* 328 */ "signed ::= plus_num", - /* 329 */ "signed ::= minus_num", - /* 330 */ "carglist ::= carglist ccons", - /* 331 */ "carglist ::=", - /* 332 */ "ccons ::= NULL onconf", - /* 333 */ "conslist_opt ::= COMMA conslist", - /* 334 */ "conslist ::= conslist tconscomma tcons", - /* 335 */ "conslist ::= tcons", - /* 336 */ "tconscomma ::=", - /* 337 */ "defer_subclause_opt ::= defer_subclause", - /* 338 */ "resolvetype ::= raisetype", - /* 339 */ "selectnowith ::= oneselect", - /* 340 */ "oneselect ::= values", - /* 341 */ "sclp ::= selcollist COMMA", - /* 342 */ "as ::= ID|STRING", - /* 343 */ "expr ::= term", - /* 344 */ "likeop ::= LIKE_KW|MATCH", - /* 345 */ "exprlist ::= nexprlist", - /* 346 */ "nmnum ::= plus_num", - /* 347 */ "nmnum ::= nm", - /* 348 */ "nmnum ::= ON", - /* 349 */ "nmnum ::= DELETE", - /* 350 */ "nmnum ::= DEFAULT", - /* 351 */ "plus_num ::= INTEGER|FLOAT", - /* 352 */ "foreach_clause ::=", - /* 353 */ "foreach_clause ::= FOR EACH ROW", - /* 354 */ "trnm ::= nm", - /* 355 */ "tridxby ::=", - /* 356 */ "database_kw_opt ::= DATABASE", - /* 357 */ "database_kw_opt ::=", - /* 358 */ "kwcolumn_opt ::=", - /* 359 */ "kwcolumn_opt ::= COLUMNKW", - /* 360 */ "vtabarglist ::= vtabarg", - /* 361 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 362 */ "vtabarg ::= vtabarg vtabargtoken", - /* 363 */ "anylist ::=", - /* 364 */ "anylist ::= anylist LP anylist RP", - /* 365 */ "anylist ::= anylist ANY", - /* 366 */ "with ::=", + /* 29 */ "scantok ::=", + /* 30 */ "ccons ::= CONSTRAINT nm", + /* 31 */ "ccons ::= DEFAULT scantok term", + /* 32 */ "ccons ::= DEFAULT LP expr RP", + /* 33 */ "ccons ::= DEFAULT PLUS scantok term", + /* 34 */ "ccons ::= DEFAULT MINUS scantok term", + /* 35 */ "ccons ::= DEFAULT scantok ID|INDEXED", + /* 36 */ "ccons ::= NOT NULL onconf", + /* 37 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", + /* 38 */ "ccons ::= UNIQUE onconf", + /* 39 */ "ccons ::= CHECK LP expr RP", + /* 40 */ "ccons ::= REFERENCES nm eidlist_opt refargs", + /* 41 */ "ccons ::= defer_subclause", + /* 42 */ "ccons ::= COLLATE ID|STRING", + /* 43 */ "autoinc ::=", + /* 44 */ "autoinc ::= AUTOINCR", + /* 45 */ "refargs ::=", + /* 46 */ "refargs ::= refargs refarg", + /* 47 */ "refarg ::= MATCH nm", + /* 48 */ "refarg ::= ON INSERT refact", + /* 49 */ "refarg ::= ON DELETE refact", + /* 50 */ "refarg ::= ON UPDATE refact", + /* 51 */ "refact ::= SET NULL", + /* 52 */ "refact ::= SET DEFAULT", + /* 53 */ "refact ::= CASCADE", + /* 54 */ "refact ::= RESTRICT", + /* 55 */ "refact ::= NO ACTION", + /* 56 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 57 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 58 */ "init_deferred_pred_opt ::=", + /* 59 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 60 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 61 */ "conslist_opt ::=", + /* 62 */ "tconscomma ::= COMMA", + /* 63 */ "tcons ::= CONSTRAINT nm", + /* 64 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", + /* 65 */ "tcons ::= UNIQUE LP sortlist RP onconf", + /* 66 */ "tcons ::= CHECK LP expr RP onconf", + /* 67 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", + /* 68 */ "defer_subclause_opt ::=", + /* 69 */ "onconf ::=", + /* 70 */ "onconf ::= ON CONFLICT resolvetype", + /* 71 */ "orconf ::=", + /* 72 */ "orconf ::= OR resolvetype", + /* 73 */ "resolvetype ::= IGNORE", + /* 74 */ "resolvetype ::= REPLACE", + /* 75 */ "cmd ::= DROP TABLE ifexists fullname", + /* 76 */ "ifexists ::= IF EXISTS", + /* 77 */ "ifexists ::=", + /* 78 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", + /* 79 */ "cmd ::= DROP VIEW ifexists fullname", + /* 80 */ "cmd ::= select", + /* 81 */ "select ::= WITH wqlist selectnowith", + /* 82 */ "select ::= WITH RECURSIVE wqlist selectnowith", + /* 83 */ "select ::= selectnowith", + /* 84 */ "selectnowith ::= selectnowith multiselect_op oneselect", + /* 85 */ "multiselect_op ::= UNION", + /* 86 */ "multiselect_op ::= UNION ALL", + /* 87 */ "multiselect_op ::= EXCEPT|INTERSECT", + /* 88 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 89 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", + /* 90 */ "values ::= VALUES LP nexprlist RP", + /* 91 */ "values ::= values COMMA LP nexprlist RP", + /* 92 */ "distinct ::= DISTINCT", + /* 93 */ "distinct ::= ALL", + /* 94 */ "distinct ::=", + /* 95 */ "sclp ::=", + /* 96 */ "selcollist ::= sclp scanpt expr scanpt as", + /* 97 */ "selcollist ::= sclp scanpt STAR", + /* 98 */ "selcollist ::= sclp scanpt nm DOT STAR", + /* 99 */ "as ::= AS nm", + /* 100 */ "as ::=", + /* 101 */ "from ::=", + /* 102 */ "from ::= FROM seltablist", + /* 103 */ "stl_prefix ::= seltablist joinop", + /* 104 */ "stl_prefix ::=", + /* 105 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", + /* 106 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", + /* 107 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", + /* 108 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", + /* 109 */ "dbnm ::=", + /* 110 */ "dbnm ::= DOT nm", + /* 111 */ "fullname ::= nm", + /* 112 */ "fullname ::= nm DOT nm", + /* 113 */ "xfullname ::= nm", + /* 114 */ "xfullname ::= nm DOT nm", + /* 115 */ "xfullname ::= nm DOT nm AS nm", + /* 116 */ "xfullname ::= nm AS nm", + /* 117 */ "joinop ::= COMMA|JOIN", + /* 118 */ "joinop ::= JOIN_KW JOIN", + /* 119 */ "joinop ::= JOIN_KW nm JOIN", + /* 120 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 121 */ "on_opt ::= ON expr", + /* 122 */ "on_opt ::=", + /* 123 */ "indexed_opt ::=", + /* 124 */ "indexed_opt ::= INDEXED BY nm", + /* 125 */ "indexed_opt ::= NOT INDEXED", + /* 126 */ "using_opt ::= USING LP idlist RP", + /* 127 */ "using_opt ::=", + /* 128 */ "orderby_opt ::=", + /* 129 */ "orderby_opt ::= ORDER BY sortlist", + /* 130 */ "sortlist ::= sortlist COMMA expr sortorder", + /* 131 */ "sortlist ::= expr sortorder", + /* 132 */ "sortorder ::= ASC", + /* 133 */ "sortorder ::= DESC", + /* 134 */ "sortorder ::=", + /* 135 */ "groupby_opt ::=", + /* 136 */ "groupby_opt ::= GROUP BY nexprlist", + /* 137 */ "having_opt ::=", + /* 138 */ "having_opt ::= HAVING expr", + /* 139 */ "limit_opt ::=", + /* 140 */ "limit_opt ::= LIMIT expr", + /* 141 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 142 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 143 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt", + /* 144 */ "where_opt ::=", + /* 145 */ "where_opt ::= WHERE expr", + /* 146 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt", + /* 147 */ "setlist ::= setlist COMMA nm EQ expr", + /* 148 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 149 */ "setlist ::= nm EQ expr", + /* 150 */ "setlist ::= LP idlist RP EQ expr", + /* 151 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", + /* 152 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES", + /* 153 */ "upsert ::=", + /* 154 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt", + /* 155 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING", + /* 156 */ "upsert ::= ON CONFLICT DO NOTHING", + /* 157 */ "insert_cmd ::= INSERT orconf", + /* 158 */ "insert_cmd ::= REPLACE", + /* 159 */ "idlist_opt ::=", + /* 160 */ "idlist_opt ::= LP idlist RP", + /* 161 */ "idlist ::= idlist COMMA nm", + /* 162 */ "idlist ::= nm", + /* 163 */ "expr ::= LP expr RP", + /* 164 */ "expr ::= ID|INDEXED", + /* 165 */ "expr ::= JOIN_KW", + /* 166 */ "expr ::= nm DOT nm", + /* 167 */ "expr ::= nm DOT nm DOT nm", + /* 168 */ "term ::= NULL|FLOAT|BLOB", + /* 169 */ "term ::= STRING", + /* 170 */ "term ::= INTEGER", + /* 171 */ "expr ::= VARIABLE", + /* 172 */ "expr ::= expr COLLATE ID|STRING", + /* 173 */ "expr ::= CAST LP expr AS typetoken RP", + /* 174 */ "expr ::= ID|INDEXED LP distinct exprlist RP", + /* 175 */ "expr ::= ID|INDEXED LP STAR RP", + /* 176 */ "expr ::= ID|INDEXED LP distinct exprlist RP over_clause", + /* 177 */ "expr ::= ID|INDEXED LP STAR RP over_clause", + /* 178 */ "term ::= CTIME_KW", + /* 179 */ "expr ::= LP nexprlist COMMA expr RP", + /* 180 */ "expr ::= expr AND expr", + /* 181 */ "expr ::= expr OR expr", + /* 182 */ "expr ::= expr LT|GT|GE|LE expr", + /* 183 */ "expr ::= expr EQ|NE expr", + /* 184 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 185 */ "expr ::= expr PLUS|MINUS expr", + /* 186 */ "expr ::= expr STAR|SLASH|REM expr", + /* 187 */ "expr ::= expr CONCAT expr", + /* 188 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 189 */ "expr ::= expr likeop expr", + /* 190 */ "expr ::= expr likeop expr ESCAPE expr", + /* 191 */ "expr ::= expr ISNULL|NOTNULL", + /* 192 */ "expr ::= expr NOT NULL", + /* 193 */ "expr ::= expr IS expr", + /* 194 */ "expr ::= expr IS NOT expr", + /* 195 */ "expr ::= NOT expr", + /* 196 */ "expr ::= BITNOT expr", + /* 197 */ "expr ::= PLUS|MINUS expr", + /* 198 */ "between_op ::= BETWEEN", + /* 199 */ "between_op ::= NOT BETWEEN", + /* 200 */ "expr ::= expr between_op expr AND expr", + /* 201 */ "in_op ::= IN", + /* 202 */ "in_op ::= NOT IN", + /* 203 */ "expr ::= expr in_op LP exprlist RP", + /* 204 */ "expr ::= LP select RP", + /* 205 */ "expr ::= expr in_op LP select RP", + /* 206 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 207 */ "expr ::= EXISTS LP select RP", + /* 208 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 209 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 210 */ "case_exprlist ::= WHEN expr THEN expr", + /* 211 */ "case_else ::= ELSE expr", + /* 212 */ "case_else ::=", + /* 213 */ "case_operand ::= expr", + /* 214 */ "case_operand ::=", + /* 215 */ "exprlist ::=", + /* 216 */ "nexprlist ::= nexprlist COMMA expr", + /* 217 */ "nexprlist ::= expr", + /* 218 */ "paren_exprlist ::=", + /* 219 */ "paren_exprlist ::= LP exprlist RP", + /* 220 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 221 */ "uniqueflag ::= UNIQUE", + /* 222 */ "uniqueflag ::=", + /* 223 */ "eidlist_opt ::=", + /* 224 */ "eidlist_opt ::= LP eidlist RP", + /* 225 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 226 */ "eidlist ::= nm collate sortorder", + /* 227 */ "collate ::=", + /* 228 */ "collate ::= COLLATE ID|STRING", + /* 229 */ "cmd ::= DROP INDEX ifexists fullname", + /* 230 */ "cmd ::= VACUUM vinto", + /* 231 */ "cmd ::= VACUUM nm vinto", + /* 232 */ "vinto ::= INTO expr", + /* 233 */ "vinto ::=", + /* 234 */ "cmd ::= PRAGMA nm dbnm", + /* 235 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 236 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 237 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 238 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 239 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 240 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 241 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 242 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 243 */ "trigger_time ::= BEFORE|AFTER", + /* 244 */ "trigger_time ::= INSTEAD OF", + /* 245 */ "trigger_time ::=", + /* 246 */ "trigger_event ::= DELETE|INSERT", + /* 247 */ "trigger_event ::= UPDATE", + /* 248 */ "trigger_event ::= UPDATE OF idlist", + /* 249 */ "when_clause ::=", + /* 250 */ "when_clause ::= WHEN expr", + /* 251 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 252 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 253 */ "trnm ::= nm DOT nm", + /* 254 */ "tridxby ::= INDEXED BY nm", + /* 255 */ "tridxby ::= NOT INDEXED", + /* 256 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt", + /* 257 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", + /* 258 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", + /* 259 */ "trigger_cmd ::= scanpt select scanpt", + /* 260 */ "expr ::= RAISE LP IGNORE RP", + /* 261 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 262 */ "raisetype ::= ROLLBACK", + /* 263 */ "raisetype ::= ABORT", + /* 264 */ "raisetype ::= FAIL", + /* 265 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 266 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 267 */ "cmd ::= DETACH database_kw_opt expr", + /* 268 */ "key_opt ::=", + /* 269 */ "key_opt ::= KEY expr", + /* 270 */ "cmd ::= REINDEX", + /* 271 */ "cmd ::= REINDEX nm dbnm", + /* 272 */ "cmd ::= ANALYZE", + /* 273 */ "cmd ::= ANALYZE nm dbnm", + /* 274 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 275 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 276 */ "add_column_fullname ::= fullname", + /* 277 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", + /* 278 */ "cmd ::= create_vtab", + /* 279 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 280 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 281 */ "vtabarg ::=", + /* 282 */ "vtabargtoken ::= ANY", + /* 283 */ "vtabargtoken ::= lp anylist RP", + /* 284 */ "lp ::= LP", + /* 285 */ "with ::= WITH wqlist", + /* 286 */ "with ::= WITH RECURSIVE wqlist", + /* 287 */ "wqlist ::= nm eidlist_opt AS LP select RP", + /* 288 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", + /* 289 */ "windowdefn_list ::= windowdefn", + /* 290 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", + /* 291 */ "windowdefn ::= nm AS LP window RP", + /* 292 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", + /* 293 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", + /* 294 */ "window ::= ORDER BY sortlist frame_opt", + /* 295 */ "window ::= nm ORDER BY sortlist frame_opt", + /* 296 */ "window ::= frame_opt", + /* 297 */ "window ::= nm frame_opt", + /* 298 */ "frame_opt ::=", + /* 299 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", + /* 300 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", + /* 301 */ "range_or_rows ::= RANGE|ROWS|GROUPS", + /* 302 */ "frame_bound_s ::= frame_bound", + /* 303 */ "frame_bound_s ::= UNBOUNDED PRECEDING", + /* 304 */ "frame_bound_e ::= frame_bound", + /* 305 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", + /* 306 */ "frame_bound ::= expr PRECEDING|FOLLOWING", + /* 307 */ "frame_bound ::= CURRENT ROW", + /* 308 */ "frame_exclude_opt ::=", + /* 309 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", + /* 310 */ "frame_exclude ::= NO OTHERS", + /* 311 */ "frame_exclude ::= CURRENT ROW", + /* 312 */ "frame_exclude ::= GROUP|TIES", + /* 313 */ "window_clause ::= WINDOW windowdefn_list", + /* 314 */ "over_clause ::= filter_opt OVER LP window RP", + /* 315 */ "over_clause ::= filter_opt OVER nm", + /* 316 */ "filter_opt ::=", + /* 317 */ "filter_opt ::= FILTER LP WHERE expr RP", + /* 318 */ "input ::= cmdlist", + /* 319 */ "cmdlist ::= cmdlist ecmd", + /* 320 */ "cmdlist ::= ecmd", + /* 321 */ "ecmd ::= SEMI", + /* 322 */ "ecmd ::= cmdx SEMI", + /* 323 */ "ecmd ::= explain cmdx", + /* 324 */ "trans_opt ::=", + /* 325 */ "trans_opt ::= TRANSACTION", + /* 326 */ "trans_opt ::= TRANSACTION nm", + /* 327 */ "savepoint_opt ::= SAVEPOINT", + /* 328 */ "savepoint_opt ::=", + /* 329 */ "cmd ::= create_table create_table_args", + /* 330 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 331 */ "columnlist ::= columnname carglist", + /* 332 */ "nm ::= ID|INDEXED", + /* 333 */ "nm ::= STRING", + /* 334 */ "nm ::= JOIN_KW", + /* 335 */ "typetoken ::= typename", + /* 336 */ "typename ::= ID|STRING", + /* 337 */ "signed ::= plus_num", + /* 338 */ "signed ::= minus_num", + /* 339 */ "carglist ::= carglist ccons", + /* 340 */ "carglist ::=", + /* 341 */ "ccons ::= NULL onconf", + /* 342 */ "conslist_opt ::= COMMA conslist", + /* 343 */ "conslist ::= conslist tconscomma tcons", + /* 344 */ "conslist ::= tcons", + /* 345 */ "tconscomma ::=", + /* 346 */ "defer_subclause_opt ::= defer_subclause", + /* 347 */ "resolvetype ::= raisetype", + /* 348 */ "selectnowith ::= oneselect", + /* 349 */ "oneselect ::= values", + /* 350 */ "sclp ::= selcollist COMMA", + /* 351 */ "as ::= ID|STRING", + /* 352 */ "expr ::= term", + /* 353 */ "likeop ::= LIKE_KW|MATCH", + /* 354 */ "exprlist ::= nexprlist", + /* 355 */ "nmnum ::= plus_num", + /* 356 */ "nmnum ::= nm", + /* 357 */ "nmnum ::= ON", + /* 358 */ "nmnum ::= DELETE", + /* 359 */ "nmnum ::= DEFAULT", + /* 360 */ "plus_num ::= INTEGER|FLOAT", + /* 361 */ "foreach_clause ::=", + /* 362 */ "foreach_clause ::= FOR EACH ROW", + /* 363 */ "trnm ::= nm", + /* 364 */ "tridxby ::=", + /* 365 */ "database_kw_opt ::= DATABASE", + /* 366 */ "database_kw_opt ::=", + /* 367 */ "kwcolumn_opt ::=", + /* 368 */ "kwcolumn_opt ::= COLUMNKW", + /* 369 */ "vtabarglist ::= vtabarg", + /* 370 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 371 */ "vtabarg ::= vtabarg vtabargtoken", + /* 372 */ "anylist ::=", + /* 373 */ "anylist ::= anylist LP anylist RP", + /* 374 */ "anylist ::= anylist ANY", + /* 375 */ "with ::=", }; #endif /* NDEBUG */ @@ -147801,96 +150662,97 @@ static void yy_destructor( ** inside the C code. */ /********* Begin destructor definitions ***************************************/ - case 174: /* select */ - case 206: /* selectnowith */ - case 207: /* oneselect */ - case 219: /* values */ + case 195: /* select */ + case 228: /* selectnowith */ + case 229: /* oneselect */ + case 241: /* values */ { -sqlite3SelectDelete(pParse->db, (yypminor->yy489)); +sqlite3SelectDelete(pParse->db, (yypminor->yy391)); } break; - case 184: /* term */ - case 185: /* expr */ - case 213: /* where_opt */ - case 215: /* having_opt */ - case 227: /* on_opt */ - case 242: /* case_operand */ - case 244: /* case_else */ - case 253: /* when_clause */ - case 258: /* key_opt */ - case 272: /* filter_opt */ + case 206: /* term */ + case 207: /* expr */ + case 235: /* where_opt */ + case 237: /* having_opt */ + case 249: /* on_opt */ + case 264: /* case_operand */ + case 266: /* case_else */ + case 269: /* vinto */ + case 276: /* when_clause */ + case 281: /* key_opt */ + case 295: /* filter_opt */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy18)); +sqlite3ExprDelete(pParse->db, (yypminor->yy102)); } break; - case 189: /* eidlist_opt */ - case 198: /* sortlist */ - case 199: /* eidlist */ - case 211: /* selcollist */ - case 214: /* groupby_opt */ - case 216: /* orderby_opt */ - case 220: /* nexprlist */ - case 221: /* sclp */ - case 229: /* exprlist */ - case 233: /* setlist */ - case 241: /* paren_exprlist */ - case 243: /* case_exprlist */ - case 271: /* part_opt */ + case 211: /* eidlist_opt */ + case 220: /* sortlist */ + case 221: /* eidlist */ + case 233: /* selcollist */ + case 236: /* groupby_opt */ + case 238: /* orderby_opt */ + case 242: /* nexprlist */ + case 243: /* sclp */ + case 251: /* exprlist */ + case 255: /* setlist */ + case 263: /* paren_exprlist */ + case 265: /* case_exprlist */ + case 294: /* part_opt */ { -sqlite3ExprListDelete(pParse->db, (yypminor->yy420)); +sqlite3ExprListDelete(pParse->db, (yypminor->yy94)); } break; - case 205: /* fullname */ - case 212: /* from */ - case 223: /* seltablist */ - case 224: /* stl_prefix */ - case 230: /* xfullname */ + case 227: /* fullname */ + case 234: /* from */ + case 245: /* seltablist */ + case 246: /* stl_prefix */ + case 252: /* xfullname */ { -sqlite3SrcListDelete(pParse->db, (yypminor->yy135)); +sqlite3SrcListDelete(pParse->db, (yypminor->yy407)); } break; - case 208: /* wqlist */ + case 230: /* wqlist */ { -sqlite3WithDelete(pParse->db, (yypminor->yy449)); +sqlite3WithDelete(pParse->db, (yypminor->yy243)); } break; - case 218: /* window_clause */ - case 267: /* windowdefn_list */ + case 240: /* window_clause */ + case 290: /* windowdefn_list */ { -sqlite3WindowListDelete(pParse->db, (yypminor->yy327)); +sqlite3WindowListDelete(pParse->db, (yypminor->yy379)); } break; - case 228: /* using_opt */ - case 231: /* idlist */ - case 235: /* idlist_opt */ + case 250: /* using_opt */ + case 253: /* idlist */ + case 257: /* idlist_opt */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy48)); +sqlite3IdListDelete(pParse->db, (yypminor->yy76)); } break; - case 237: /* over_clause */ - case 268: /* windowdefn */ - case 269: /* window */ - case 270: /* frame_opt */ + case 259: /* over_clause */ + case 291: /* windowdefn */ + case 292: /* window */ + case 293: /* frame_opt */ { -sqlite3WindowDelete(pParse->db, (yypminor->yy327)); +sqlite3WindowDelete(pParse->db, (yypminor->yy379)); } break; - case 249: /* trigger_cmd_list */ - case 254: /* trigger_cmd */ + case 272: /* trigger_cmd_list */ + case 277: /* trigger_cmd */ { -sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy207)); +sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy11)); } break; - case 251: /* trigger_event */ + case 274: /* trigger_event */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy34).b); +sqlite3IdListDelete(pParse->db, (yypminor->yy298).b); } break; - case 274: /* frame_bound */ - case 275: /* frame_bound_s */ - case 276: /* frame_bound_e */ + case 297: /* frame_bound */ + case 298: /* frame_bound_s */ + case 299: /* frame_bound_e */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy119).pExpr); +sqlite3ExprDelete(pParse->db, (yypminor->yy389).pExpr); } break; /********* End destructor definitions *****************************************/ @@ -148182,380 +151044,766 @@ static void yy_shift( yyTraceShift(yypParser, yyNewState, "Shift"); } -/* The following table contains information about every rule that -** is used during the reduce. -*/ -static const struct { - YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ - signed char nrhs; /* Negative of the number of RHS symbols in the rule */ -} yyRuleInfo[] = { - { 159, -1 }, /* (0) explain ::= EXPLAIN */ - { 159, -3 }, /* (1) explain ::= EXPLAIN QUERY PLAN */ - { 158, -1 }, /* (2) cmdx ::= cmd */ - { 160, -3 }, /* (3) cmd ::= BEGIN transtype trans_opt */ - { 161, 0 }, /* (4) transtype ::= */ - { 161, -1 }, /* (5) transtype ::= DEFERRED */ - { 161, -1 }, /* (6) transtype ::= IMMEDIATE */ - { 161, -1 }, /* (7) transtype ::= EXCLUSIVE */ - { 160, -2 }, /* (8) cmd ::= COMMIT|END trans_opt */ - { 160, -2 }, /* (9) cmd ::= ROLLBACK trans_opt */ - { 160, -2 }, /* (10) cmd ::= SAVEPOINT nm */ - { 160, -3 }, /* (11) cmd ::= RELEASE savepoint_opt nm */ - { 160, -5 }, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ - { 165, -6 }, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ - { 167, -1 }, /* (14) createkw ::= CREATE */ - { 169, 0 }, /* (15) ifnotexists ::= */ - { 169, -3 }, /* (16) ifnotexists ::= IF NOT EXISTS */ - { 168, -1 }, /* (17) temp ::= TEMP */ - { 168, 0 }, /* (18) temp ::= */ - { 166, -5 }, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */ - { 166, -2 }, /* (20) create_table_args ::= AS select */ - { 173, 0 }, /* (21) table_options ::= */ - { 173, -2 }, /* (22) table_options ::= WITHOUT nm */ - { 175, -2 }, /* (23) columnname ::= nm typetoken */ - { 177, 0 }, /* (24) typetoken ::= */ - { 177, -4 }, /* (25) typetoken ::= typename LP signed RP */ - { 177, -6 }, /* (26) typetoken ::= typename LP signed COMMA signed RP */ - { 178, -2 }, /* (27) typename ::= typename ID|STRING */ - { 182, 0 }, /* (28) scanpt ::= */ - { 183, -2 }, /* (29) ccons ::= CONSTRAINT nm */ - { 183, -4 }, /* (30) ccons ::= DEFAULT scanpt term scanpt */ - { 183, -4 }, /* (31) ccons ::= DEFAULT LP expr RP */ - { 183, -4 }, /* (32) ccons ::= DEFAULT PLUS term scanpt */ - { 183, -4 }, /* (33) ccons ::= DEFAULT MINUS term scanpt */ - { 183, -3 }, /* (34) ccons ::= DEFAULT scanpt ID|INDEXED */ - { 183, -3 }, /* (35) ccons ::= NOT NULL onconf */ - { 183, -5 }, /* (36) ccons ::= PRIMARY KEY sortorder onconf autoinc */ - { 183, -2 }, /* (37) ccons ::= UNIQUE onconf */ - { 183, -4 }, /* (38) ccons ::= CHECK LP expr RP */ - { 183, -4 }, /* (39) ccons ::= REFERENCES nm eidlist_opt refargs */ - { 183, -1 }, /* (40) ccons ::= defer_subclause */ - { 183, -2 }, /* (41) ccons ::= COLLATE ID|STRING */ - { 188, 0 }, /* (42) autoinc ::= */ - { 188, -1 }, /* (43) autoinc ::= AUTOINCR */ - { 190, 0 }, /* (44) refargs ::= */ - { 190, -2 }, /* (45) refargs ::= refargs refarg */ - { 192, -2 }, /* (46) refarg ::= MATCH nm */ - { 192, -3 }, /* (47) refarg ::= ON INSERT refact */ - { 192, -3 }, /* (48) refarg ::= ON DELETE refact */ - { 192, -3 }, /* (49) refarg ::= ON UPDATE refact */ - { 193, -2 }, /* (50) refact ::= SET NULL */ - { 193, -2 }, /* (51) refact ::= SET DEFAULT */ - { 193, -1 }, /* (52) refact ::= CASCADE */ - { 193, -1 }, /* (53) refact ::= RESTRICT */ - { 193, -2 }, /* (54) refact ::= NO ACTION */ - { 191, -3 }, /* (55) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ - { 191, -2 }, /* (56) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - { 194, 0 }, /* (57) init_deferred_pred_opt ::= */ - { 194, -2 }, /* (58) init_deferred_pred_opt ::= INITIALLY DEFERRED */ - { 194, -2 }, /* (59) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ - { 172, 0 }, /* (60) conslist_opt ::= */ - { 196, -1 }, /* (61) tconscomma ::= COMMA */ - { 197, -2 }, /* (62) tcons ::= CONSTRAINT nm */ - { 197, -7 }, /* (63) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ - { 197, -5 }, /* (64) tcons ::= UNIQUE LP sortlist RP onconf */ - { 197, -5 }, /* (65) tcons ::= CHECK LP expr RP onconf */ - { 197, -10 }, /* (66) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ - { 200, 0 }, /* (67) defer_subclause_opt ::= */ - { 186, 0 }, /* (68) onconf ::= */ - { 186, -3 }, /* (69) onconf ::= ON CONFLICT resolvetype */ - { 201, 0 }, /* (70) orconf ::= */ - { 201, -2 }, /* (71) orconf ::= OR resolvetype */ - { 202, -1 }, /* (72) resolvetype ::= IGNORE */ - { 202, -1 }, /* (73) resolvetype ::= REPLACE */ - { 160, -4 }, /* (74) cmd ::= DROP TABLE ifexists fullname */ - { 204, -2 }, /* (75) ifexists ::= IF EXISTS */ - { 204, 0 }, /* (76) ifexists ::= */ - { 160, -9 }, /* (77) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ - { 160, -4 }, /* (78) cmd ::= DROP VIEW ifexists fullname */ - { 160, -1 }, /* (79) cmd ::= select */ - { 174, -3 }, /* (80) select ::= WITH wqlist selectnowith */ - { 174, -4 }, /* (81) select ::= WITH RECURSIVE wqlist selectnowith */ - { 174, -1 }, /* (82) select ::= selectnowith */ - { 206, -3 }, /* (83) selectnowith ::= selectnowith multiselect_op oneselect */ - { 209, -1 }, /* (84) multiselect_op ::= UNION */ - { 209, -2 }, /* (85) multiselect_op ::= UNION ALL */ - { 209, -1 }, /* (86) multiselect_op ::= EXCEPT|INTERSECT */ - { 207, -9 }, /* (87) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ - { 207, -10 }, /* (88) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ - { 219, -4 }, /* (89) values ::= VALUES LP nexprlist RP */ - { 219, -5 }, /* (90) values ::= values COMMA LP nexprlist RP */ - { 210, -1 }, /* (91) distinct ::= DISTINCT */ - { 210, -1 }, /* (92) distinct ::= ALL */ - { 210, 0 }, /* (93) distinct ::= */ - { 221, 0 }, /* (94) sclp ::= */ - { 211, -5 }, /* (95) selcollist ::= sclp scanpt expr scanpt as */ - { 211, -3 }, /* (96) selcollist ::= sclp scanpt STAR */ - { 211, -5 }, /* (97) selcollist ::= sclp scanpt nm DOT STAR */ - { 222, -2 }, /* (98) as ::= AS nm */ - { 222, 0 }, /* (99) as ::= */ - { 212, 0 }, /* (100) from ::= */ - { 212, -2 }, /* (101) from ::= FROM seltablist */ - { 224, -2 }, /* (102) stl_prefix ::= seltablist joinop */ - { 224, 0 }, /* (103) stl_prefix ::= */ - { 223, -7 }, /* (104) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ - { 223, -9 }, /* (105) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ - { 223, -7 }, /* (106) seltablist ::= stl_prefix LP select RP as on_opt using_opt */ - { 223, -7 }, /* (107) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ - { 170, 0 }, /* (108) dbnm ::= */ - { 170, -2 }, /* (109) dbnm ::= DOT nm */ - { 205, -1 }, /* (110) fullname ::= nm */ - { 205, -3 }, /* (111) fullname ::= nm DOT nm */ - { 230, -1 }, /* (112) xfullname ::= nm */ - { 230, -3 }, /* (113) xfullname ::= nm DOT nm */ - { 230, -5 }, /* (114) xfullname ::= nm DOT nm AS nm */ - { 230, -3 }, /* (115) xfullname ::= nm AS nm */ - { 225, -1 }, /* (116) joinop ::= COMMA|JOIN */ - { 225, -2 }, /* (117) joinop ::= JOIN_KW JOIN */ - { 225, -3 }, /* (118) joinop ::= JOIN_KW nm JOIN */ - { 225, -4 }, /* (119) joinop ::= JOIN_KW nm nm JOIN */ - { 227, -2 }, /* (120) on_opt ::= ON expr */ - { 227, 0 }, /* (121) on_opt ::= */ - { 226, 0 }, /* (122) indexed_opt ::= */ - { 226, -3 }, /* (123) indexed_opt ::= INDEXED BY nm */ - { 226, -2 }, /* (124) indexed_opt ::= NOT INDEXED */ - { 228, -4 }, /* (125) using_opt ::= USING LP idlist RP */ - { 228, 0 }, /* (126) using_opt ::= */ - { 216, 0 }, /* (127) orderby_opt ::= */ - { 216, -3 }, /* (128) orderby_opt ::= ORDER BY sortlist */ - { 198, -4 }, /* (129) sortlist ::= sortlist COMMA expr sortorder */ - { 198, -2 }, /* (130) sortlist ::= expr sortorder */ - { 187, -1 }, /* (131) sortorder ::= ASC */ - { 187, -1 }, /* (132) sortorder ::= DESC */ - { 187, 0 }, /* (133) sortorder ::= */ - { 214, 0 }, /* (134) groupby_opt ::= */ - { 214, -3 }, /* (135) groupby_opt ::= GROUP BY nexprlist */ - { 215, 0 }, /* (136) having_opt ::= */ - { 215, -2 }, /* (137) having_opt ::= HAVING expr */ - { 217, 0 }, /* (138) limit_opt ::= */ - { 217, -2 }, /* (139) limit_opt ::= LIMIT expr */ - { 217, -4 }, /* (140) limit_opt ::= LIMIT expr OFFSET expr */ - { 217, -4 }, /* (141) limit_opt ::= LIMIT expr COMMA expr */ - { 160, -6 }, /* (142) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ - { 213, 0 }, /* (143) where_opt ::= */ - { 213, -2 }, /* (144) where_opt ::= WHERE expr */ - { 160, -8 }, /* (145) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ - { 233, -5 }, /* (146) setlist ::= setlist COMMA nm EQ expr */ - { 233, -7 }, /* (147) setlist ::= setlist COMMA LP idlist RP EQ expr */ - { 233, -3 }, /* (148) setlist ::= nm EQ expr */ - { 233, -5 }, /* (149) setlist ::= LP idlist RP EQ expr */ - { 160, -7 }, /* (150) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ - { 160, -7 }, /* (151) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ - { 236, 0 }, /* (152) upsert ::= */ - { 236, -11 }, /* (153) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ - { 236, -8 }, /* (154) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ - { 236, -4 }, /* (155) upsert ::= ON CONFLICT DO NOTHING */ - { 234, -2 }, /* (156) insert_cmd ::= INSERT orconf */ - { 234, -1 }, /* (157) insert_cmd ::= REPLACE */ - { 235, 0 }, /* (158) idlist_opt ::= */ - { 235, -3 }, /* (159) idlist_opt ::= LP idlist RP */ - { 231, -3 }, /* (160) idlist ::= idlist COMMA nm */ - { 231, -1 }, /* (161) idlist ::= nm */ - { 185, -3 }, /* (162) expr ::= LP expr RP */ - { 185, -1 }, /* (163) expr ::= ID|INDEXED */ - { 185, -1 }, /* (164) expr ::= JOIN_KW */ - { 185, -3 }, /* (165) expr ::= nm DOT nm */ - { 185, -5 }, /* (166) expr ::= nm DOT nm DOT nm */ - { 184, -1 }, /* (167) term ::= NULL|FLOAT|BLOB */ - { 184, -1 }, /* (168) term ::= STRING */ - { 184, -1 }, /* (169) term ::= INTEGER */ - { 185, -1 }, /* (170) expr ::= VARIABLE */ - { 185, -3 }, /* (171) expr ::= expr COLLATE ID|STRING */ - { 185, -6 }, /* (172) expr ::= CAST LP expr AS typetoken RP */ - { 185, -5 }, /* (173) expr ::= ID|INDEXED LP distinct exprlist RP */ - { 185, -4 }, /* (174) expr ::= ID|INDEXED LP STAR RP */ - { 185, -6 }, /* (175) expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ - { 185, -5 }, /* (176) expr ::= ID|INDEXED LP STAR RP over_clause */ - { 184, -1 }, /* (177) term ::= CTIME_KW */ - { 185, -5 }, /* (178) expr ::= LP nexprlist COMMA expr RP */ - { 185, -3 }, /* (179) expr ::= expr AND expr */ - { 185, -3 }, /* (180) expr ::= expr OR expr */ - { 185, -3 }, /* (181) expr ::= expr LT|GT|GE|LE expr */ - { 185, -3 }, /* (182) expr ::= expr EQ|NE expr */ - { 185, -3 }, /* (183) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - { 185, -3 }, /* (184) expr ::= expr PLUS|MINUS expr */ - { 185, -3 }, /* (185) expr ::= expr STAR|SLASH|REM expr */ - { 185, -3 }, /* (186) expr ::= expr CONCAT expr */ - { 238, -2 }, /* (187) likeop ::= NOT LIKE_KW|MATCH */ - { 185, -3 }, /* (188) expr ::= expr likeop expr */ - { 185, -5 }, /* (189) expr ::= expr likeop expr ESCAPE expr */ - { 185, -2 }, /* (190) expr ::= expr ISNULL|NOTNULL */ - { 185, -3 }, /* (191) expr ::= expr NOT NULL */ - { 185, -3 }, /* (192) expr ::= expr IS expr */ - { 185, -4 }, /* (193) expr ::= expr IS NOT expr */ - { 185, -2 }, /* (194) expr ::= NOT expr */ - { 185, -2 }, /* (195) expr ::= BITNOT expr */ - { 185, -2 }, /* (196) expr ::= PLUS|MINUS expr */ - { 239, -1 }, /* (197) between_op ::= BETWEEN */ - { 239, -2 }, /* (198) between_op ::= NOT BETWEEN */ - { 185, -5 }, /* (199) expr ::= expr between_op expr AND expr */ - { 240, -1 }, /* (200) in_op ::= IN */ - { 240, -2 }, /* (201) in_op ::= NOT IN */ - { 185, -5 }, /* (202) expr ::= expr in_op LP exprlist RP */ - { 185, -3 }, /* (203) expr ::= LP select RP */ - { 185, -5 }, /* (204) expr ::= expr in_op LP select RP */ - { 185, -5 }, /* (205) expr ::= expr in_op nm dbnm paren_exprlist */ - { 185, -4 }, /* (206) expr ::= EXISTS LP select RP */ - { 185, -5 }, /* (207) expr ::= CASE case_operand case_exprlist case_else END */ - { 243, -5 }, /* (208) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - { 243, -4 }, /* (209) case_exprlist ::= WHEN expr THEN expr */ - { 244, -2 }, /* (210) case_else ::= ELSE expr */ - { 244, 0 }, /* (211) case_else ::= */ - { 242, -1 }, /* (212) case_operand ::= expr */ - { 242, 0 }, /* (213) case_operand ::= */ - { 229, 0 }, /* (214) exprlist ::= */ - { 220, -3 }, /* (215) nexprlist ::= nexprlist COMMA expr */ - { 220, -1 }, /* (216) nexprlist ::= expr */ - { 241, 0 }, /* (217) paren_exprlist ::= */ - { 241, -3 }, /* (218) paren_exprlist ::= LP exprlist RP */ - { 160, -12 }, /* (219) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - { 245, -1 }, /* (220) uniqueflag ::= UNIQUE */ - { 245, 0 }, /* (221) uniqueflag ::= */ - { 189, 0 }, /* (222) eidlist_opt ::= */ - { 189, -3 }, /* (223) eidlist_opt ::= LP eidlist RP */ - { 199, -5 }, /* (224) eidlist ::= eidlist COMMA nm collate sortorder */ - { 199, -3 }, /* (225) eidlist ::= nm collate sortorder */ - { 246, 0 }, /* (226) collate ::= */ - { 246, -2 }, /* (227) collate ::= COLLATE ID|STRING */ - { 160, -4 }, /* (228) cmd ::= DROP INDEX ifexists fullname */ - { 160, -1 }, /* (229) cmd ::= VACUUM */ - { 160, -2 }, /* (230) cmd ::= VACUUM nm */ - { 160, -3 }, /* (231) cmd ::= PRAGMA nm dbnm */ - { 160, -5 }, /* (232) cmd ::= PRAGMA nm dbnm EQ nmnum */ - { 160, -6 }, /* (233) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - { 160, -5 }, /* (234) cmd ::= PRAGMA nm dbnm EQ minus_num */ - { 160, -6 }, /* (235) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - { 180, -2 }, /* (236) plus_num ::= PLUS INTEGER|FLOAT */ - { 181, -2 }, /* (237) minus_num ::= MINUS INTEGER|FLOAT */ - { 160, -5 }, /* (238) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - { 248, -11 }, /* (239) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - { 250, -1 }, /* (240) trigger_time ::= BEFORE|AFTER */ - { 250, -2 }, /* (241) trigger_time ::= INSTEAD OF */ - { 250, 0 }, /* (242) trigger_time ::= */ - { 251, -1 }, /* (243) trigger_event ::= DELETE|INSERT */ - { 251, -1 }, /* (244) trigger_event ::= UPDATE */ - { 251, -3 }, /* (245) trigger_event ::= UPDATE OF idlist */ - { 253, 0 }, /* (246) when_clause ::= */ - { 253, -2 }, /* (247) when_clause ::= WHEN expr */ - { 249, -3 }, /* (248) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - { 249, -2 }, /* (249) trigger_cmd_list ::= trigger_cmd SEMI */ - { 255, -3 }, /* (250) trnm ::= nm DOT nm */ - { 256, -3 }, /* (251) tridxby ::= INDEXED BY nm */ - { 256, -2 }, /* (252) tridxby ::= NOT INDEXED */ - { 254, -8 }, /* (253) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ - { 254, -8 }, /* (254) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - { 254, -6 }, /* (255) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - { 254, -3 }, /* (256) trigger_cmd ::= scanpt select scanpt */ - { 185, -4 }, /* (257) expr ::= RAISE LP IGNORE RP */ - { 185, -6 }, /* (258) expr ::= RAISE LP raisetype COMMA nm RP */ - { 203, -1 }, /* (259) raisetype ::= ROLLBACK */ - { 203, -1 }, /* (260) raisetype ::= ABORT */ - { 203, -1 }, /* (261) raisetype ::= FAIL */ - { 160, -4 }, /* (262) cmd ::= DROP TRIGGER ifexists fullname */ - { 160, -6 }, /* (263) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - { 160, -3 }, /* (264) cmd ::= DETACH database_kw_opt expr */ - { 258, 0 }, /* (265) key_opt ::= */ - { 258, -2 }, /* (266) key_opt ::= KEY expr */ - { 160, -1 }, /* (267) cmd ::= REINDEX */ - { 160, -3 }, /* (268) cmd ::= REINDEX nm dbnm */ - { 160, -1 }, /* (269) cmd ::= ANALYZE */ - { 160, -3 }, /* (270) cmd ::= ANALYZE nm dbnm */ - { 160, -6 }, /* (271) cmd ::= ALTER TABLE fullname RENAME TO nm */ - { 160, -7 }, /* (272) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - { 259, -1 }, /* (273) add_column_fullname ::= fullname */ - { 160, -8 }, /* (274) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - { 160, -1 }, /* (275) cmd ::= create_vtab */ - { 160, -4 }, /* (276) cmd ::= create_vtab LP vtabarglist RP */ - { 261, -8 }, /* (277) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - { 263, 0 }, /* (278) vtabarg ::= */ - { 264, -1 }, /* (279) vtabargtoken ::= ANY */ - { 264, -3 }, /* (280) vtabargtoken ::= lp anylist RP */ - { 265, -1 }, /* (281) lp ::= LP */ - { 232, -2 }, /* (282) with ::= WITH wqlist */ - { 232, -3 }, /* (283) with ::= WITH RECURSIVE wqlist */ - { 208, -6 }, /* (284) wqlist ::= nm eidlist_opt AS LP select RP */ - { 208, -8 }, /* (285) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ - { 267, -1 }, /* (286) windowdefn_list ::= windowdefn */ - { 267, -3 }, /* (287) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - { 268, -3 }, /* (288) windowdefn ::= nm AS window */ - { 269, -5 }, /* (289) window ::= LP part_opt orderby_opt frame_opt RP */ - { 271, -3 }, /* (290) part_opt ::= PARTITION BY nexprlist */ - { 271, 0 }, /* (291) part_opt ::= */ - { 270, 0 }, /* (292) frame_opt ::= */ - { 270, -2 }, /* (293) frame_opt ::= range_or_rows frame_bound_s */ - { 270, -5 }, /* (294) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e */ - { 273, -1 }, /* (295) range_or_rows ::= RANGE */ - { 273, -1 }, /* (296) range_or_rows ::= ROWS */ - { 275, -1 }, /* (297) frame_bound_s ::= frame_bound */ - { 275, -2 }, /* (298) frame_bound_s ::= UNBOUNDED PRECEDING */ - { 276, -1 }, /* (299) frame_bound_e ::= frame_bound */ - { 276, -2 }, /* (300) frame_bound_e ::= UNBOUNDED FOLLOWING */ - { 274, -2 }, /* (301) frame_bound ::= expr PRECEDING */ - { 274, -2 }, /* (302) frame_bound ::= CURRENT ROW */ - { 274, -2 }, /* (303) frame_bound ::= expr FOLLOWING */ - { 218, -2 }, /* (304) window_clause ::= WINDOW windowdefn_list */ - { 237, -3 }, /* (305) over_clause ::= filter_opt OVER window */ - { 237, -3 }, /* (306) over_clause ::= filter_opt OVER nm */ - { 272, 0 }, /* (307) filter_opt ::= */ - { 272, -5 }, /* (308) filter_opt ::= FILTER LP WHERE expr RP */ - { 155, -1 }, /* (309) input ::= cmdlist */ - { 156, -2 }, /* (310) cmdlist ::= cmdlist ecmd */ - { 156, -1 }, /* (311) cmdlist ::= ecmd */ - { 157, -1 }, /* (312) ecmd ::= SEMI */ - { 157, -2 }, /* (313) ecmd ::= cmdx SEMI */ - { 157, -2 }, /* (314) ecmd ::= explain cmdx */ - { 162, 0 }, /* (315) trans_opt ::= */ - { 162, -1 }, /* (316) trans_opt ::= TRANSACTION */ - { 162, -2 }, /* (317) trans_opt ::= TRANSACTION nm */ - { 164, -1 }, /* (318) savepoint_opt ::= SAVEPOINT */ - { 164, 0 }, /* (319) savepoint_opt ::= */ - { 160, -2 }, /* (320) cmd ::= create_table create_table_args */ - { 171, -4 }, /* (321) columnlist ::= columnlist COMMA columnname carglist */ - { 171, -2 }, /* (322) columnlist ::= columnname carglist */ - { 163, -1 }, /* (323) nm ::= ID|INDEXED */ - { 163, -1 }, /* (324) nm ::= STRING */ - { 163, -1 }, /* (325) nm ::= JOIN_KW */ - { 177, -1 }, /* (326) typetoken ::= typename */ - { 178, -1 }, /* (327) typename ::= ID|STRING */ - { 179, -1 }, /* (328) signed ::= plus_num */ - { 179, -1 }, /* (329) signed ::= minus_num */ - { 176, -2 }, /* (330) carglist ::= carglist ccons */ - { 176, 0 }, /* (331) carglist ::= */ - { 183, -2 }, /* (332) ccons ::= NULL onconf */ - { 172, -2 }, /* (333) conslist_opt ::= COMMA conslist */ - { 195, -3 }, /* (334) conslist ::= conslist tconscomma tcons */ - { 195, -1 }, /* (335) conslist ::= tcons */ - { 196, 0 }, /* (336) tconscomma ::= */ - { 200, -1 }, /* (337) defer_subclause_opt ::= defer_subclause */ - { 202, -1 }, /* (338) resolvetype ::= raisetype */ - { 206, -1 }, /* (339) selectnowith ::= oneselect */ - { 207, -1 }, /* (340) oneselect ::= values */ - { 221, -2 }, /* (341) sclp ::= selcollist COMMA */ - { 222, -1 }, /* (342) as ::= ID|STRING */ - { 185, -1 }, /* (343) expr ::= term */ - { 238, -1 }, /* (344) likeop ::= LIKE_KW|MATCH */ - { 229, -1 }, /* (345) exprlist ::= nexprlist */ - { 247, -1 }, /* (346) nmnum ::= plus_num */ - { 247, -1 }, /* (347) nmnum ::= nm */ - { 247, -1 }, /* (348) nmnum ::= ON */ - { 247, -1 }, /* (349) nmnum ::= DELETE */ - { 247, -1 }, /* (350) nmnum ::= DEFAULT */ - { 180, -1 }, /* (351) plus_num ::= INTEGER|FLOAT */ - { 252, 0 }, /* (352) foreach_clause ::= */ - { 252, -3 }, /* (353) foreach_clause ::= FOR EACH ROW */ - { 255, -1 }, /* (354) trnm ::= nm */ - { 256, 0 }, /* (355) tridxby ::= */ - { 257, -1 }, /* (356) database_kw_opt ::= DATABASE */ - { 257, 0 }, /* (357) database_kw_opt ::= */ - { 260, 0 }, /* (358) kwcolumn_opt ::= */ - { 260, -1 }, /* (359) kwcolumn_opt ::= COLUMNKW */ - { 262, -1 }, /* (360) vtabarglist ::= vtabarg */ - { 262, -3 }, /* (361) vtabarglist ::= vtabarglist COMMA vtabarg */ - { 263, -2 }, /* (362) vtabarg ::= vtabarg vtabargtoken */ - { 266, 0 }, /* (363) anylist ::= */ - { 266, -4 }, /* (364) anylist ::= anylist LP anylist RP */ - { 266, -2 }, /* (365) anylist ::= anylist ANY */ - { 232, 0 }, /* (366) with ::= */ +/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side +** of that rule */ +static const YYCODETYPE yyRuleInfoLhs[] = { + 180, /* (0) explain ::= EXPLAIN */ + 180, /* (1) explain ::= EXPLAIN QUERY PLAN */ + 179, /* (2) cmdx ::= cmd */ + 181, /* (3) cmd ::= BEGIN transtype trans_opt */ + 182, /* (4) transtype ::= */ + 182, /* (5) transtype ::= DEFERRED */ + 182, /* (6) transtype ::= IMMEDIATE */ + 182, /* (7) transtype ::= EXCLUSIVE */ + 181, /* (8) cmd ::= COMMIT|END trans_opt */ + 181, /* (9) cmd ::= ROLLBACK trans_opt */ + 181, /* (10) cmd ::= SAVEPOINT nm */ + 181, /* (11) cmd ::= RELEASE savepoint_opt nm */ + 181, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + 186, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + 188, /* (14) createkw ::= CREATE */ + 190, /* (15) ifnotexists ::= */ + 190, /* (16) ifnotexists ::= IF NOT EXISTS */ + 189, /* (17) temp ::= TEMP */ + 189, /* (18) temp ::= */ + 187, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */ + 187, /* (20) create_table_args ::= AS select */ + 194, /* (21) table_options ::= */ + 194, /* (22) table_options ::= WITHOUT nm */ + 196, /* (23) columnname ::= nm typetoken */ + 198, /* (24) typetoken ::= */ + 198, /* (25) typetoken ::= typename LP signed RP */ + 198, /* (26) typetoken ::= typename LP signed COMMA signed RP */ + 199, /* (27) typename ::= typename ID|STRING */ + 203, /* (28) scanpt ::= */ + 204, /* (29) scantok ::= */ + 205, /* (30) ccons ::= CONSTRAINT nm */ + 205, /* (31) ccons ::= DEFAULT scantok term */ + 205, /* (32) ccons ::= DEFAULT LP expr RP */ + 205, /* (33) ccons ::= DEFAULT PLUS scantok term */ + 205, /* (34) ccons ::= DEFAULT MINUS scantok term */ + 205, /* (35) ccons ::= DEFAULT scantok ID|INDEXED */ + 205, /* (36) ccons ::= NOT NULL onconf */ + 205, /* (37) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + 205, /* (38) ccons ::= UNIQUE onconf */ + 205, /* (39) ccons ::= CHECK LP expr RP */ + 205, /* (40) ccons ::= REFERENCES nm eidlist_opt refargs */ + 205, /* (41) ccons ::= defer_subclause */ + 205, /* (42) ccons ::= COLLATE ID|STRING */ + 210, /* (43) autoinc ::= */ + 210, /* (44) autoinc ::= AUTOINCR */ + 212, /* (45) refargs ::= */ + 212, /* (46) refargs ::= refargs refarg */ + 214, /* (47) refarg ::= MATCH nm */ + 214, /* (48) refarg ::= ON INSERT refact */ + 214, /* (49) refarg ::= ON DELETE refact */ + 214, /* (50) refarg ::= ON UPDATE refact */ + 215, /* (51) refact ::= SET NULL */ + 215, /* (52) refact ::= SET DEFAULT */ + 215, /* (53) refact ::= CASCADE */ + 215, /* (54) refact ::= RESTRICT */ + 215, /* (55) refact ::= NO ACTION */ + 213, /* (56) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + 213, /* (57) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 216, /* (58) init_deferred_pred_opt ::= */ + 216, /* (59) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + 216, /* (60) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 193, /* (61) conslist_opt ::= */ + 218, /* (62) tconscomma ::= COMMA */ + 219, /* (63) tcons ::= CONSTRAINT nm */ + 219, /* (64) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + 219, /* (65) tcons ::= UNIQUE LP sortlist RP onconf */ + 219, /* (66) tcons ::= CHECK LP expr RP onconf */ + 219, /* (67) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 222, /* (68) defer_subclause_opt ::= */ + 208, /* (69) onconf ::= */ + 208, /* (70) onconf ::= ON CONFLICT resolvetype */ + 223, /* (71) orconf ::= */ + 223, /* (72) orconf ::= OR resolvetype */ + 224, /* (73) resolvetype ::= IGNORE */ + 224, /* (74) resolvetype ::= REPLACE */ + 181, /* (75) cmd ::= DROP TABLE ifexists fullname */ + 226, /* (76) ifexists ::= IF EXISTS */ + 226, /* (77) ifexists ::= */ + 181, /* (78) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + 181, /* (79) cmd ::= DROP VIEW ifexists fullname */ + 181, /* (80) cmd ::= select */ + 195, /* (81) select ::= WITH wqlist selectnowith */ + 195, /* (82) select ::= WITH RECURSIVE wqlist selectnowith */ + 195, /* (83) select ::= selectnowith */ + 228, /* (84) selectnowith ::= selectnowith multiselect_op oneselect */ + 231, /* (85) multiselect_op ::= UNION */ + 231, /* (86) multiselect_op ::= UNION ALL */ + 231, /* (87) multiselect_op ::= EXCEPT|INTERSECT */ + 229, /* (88) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + 229, /* (89) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + 241, /* (90) values ::= VALUES LP nexprlist RP */ + 241, /* (91) values ::= values COMMA LP nexprlist RP */ + 232, /* (92) distinct ::= DISTINCT */ + 232, /* (93) distinct ::= ALL */ + 232, /* (94) distinct ::= */ + 243, /* (95) sclp ::= */ + 233, /* (96) selcollist ::= sclp scanpt expr scanpt as */ + 233, /* (97) selcollist ::= sclp scanpt STAR */ + 233, /* (98) selcollist ::= sclp scanpt nm DOT STAR */ + 244, /* (99) as ::= AS nm */ + 244, /* (100) as ::= */ + 234, /* (101) from ::= */ + 234, /* (102) from ::= FROM seltablist */ + 246, /* (103) stl_prefix ::= seltablist joinop */ + 246, /* (104) stl_prefix ::= */ + 245, /* (105) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + 245, /* (106) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + 245, /* (107) seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + 245, /* (108) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + 191, /* (109) dbnm ::= */ + 191, /* (110) dbnm ::= DOT nm */ + 227, /* (111) fullname ::= nm */ + 227, /* (112) fullname ::= nm DOT nm */ + 252, /* (113) xfullname ::= nm */ + 252, /* (114) xfullname ::= nm DOT nm */ + 252, /* (115) xfullname ::= nm DOT nm AS nm */ + 252, /* (116) xfullname ::= nm AS nm */ + 247, /* (117) joinop ::= COMMA|JOIN */ + 247, /* (118) joinop ::= JOIN_KW JOIN */ + 247, /* (119) joinop ::= JOIN_KW nm JOIN */ + 247, /* (120) joinop ::= JOIN_KW nm nm JOIN */ + 249, /* (121) on_opt ::= ON expr */ + 249, /* (122) on_opt ::= */ + 248, /* (123) indexed_opt ::= */ + 248, /* (124) indexed_opt ::= INDEXED BY nm */ + 248, /* (125) indexed_opt ::= NOT INDEXED */ + 250, /* (126) using_opt ::= USING LP idlist RP */ + 250, /* (127) using_opt ::= */ + 238, /* (128) orderby_opt ::= */ + 238, /* (129) orderby_opt ::= ORDER BY sortlist */ + 220, /* (130) sortlist ::= sortlist COMMA expr sortorder */ + 220, /* (131) sortlist ::= expr sortorder */ + 209, /* (132) sortorder ::= ASC */ + 209, /* (133) sortorder ::= DESC */ + 209, /* (134) sortorder ::= */ + 236, /* (135) groupby_opt ::= */ + 236, /* (136) groupby_opt ::= GROUP BY nexprlist */ + 237, /* (137) having_opt ::= */ + 237, /* (138) having_opt ::= HAVING expr */ + 239, /* (139) limit_opt ::= */ + 239, /* (140) limit_opt ::= LIMIT expr */ + 239, /* (141) limit_opt ::= LIMIT expr OFFSET expr */ + 239, /* (142) limit_opt ::= LIMIT expr COMMA expr */ + 181, /* (143) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ + 235, /* (144) where_opt ::= */ + 235, /* (145) where_opt ::= WHERE expr */ + 181, /* (146) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ + 255, /* (147) setlist ::= setlist COMMA nm EQ expr */ + 255, /* (148) setlist ::= setlist COMMA LP idlist RP EQ expr */ + 255, /* (149) setlist ::= nm EQ expr */ + 255, /* (150) setlist ::= LP idlist RP EQ expr */ + 181, /* (151) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + 181, /* (152) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ + 258, /* (153) upsert ::= */ + 258, /* (154) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ + 258, /* (155) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ + 258, /* (156) upsert ::= ON CONFLICT DO NOTHING */ + 256, /* (157) insert_cmd ::= INSERT orconf */ + 256, /* (158) insert_cmd ::= REPLACE */ + 257, /* (159) idlist_opt ::= */ + 257, /* (160) idlist_opt ::= LP idlist RP */ + 253, /* (161) idlist ::= idlist COMMA nm */ + 253, /* (162) idlist ::= nm */ + 207, /* (163) expr ::= LP expr RP */ + 207, /* (164) expr ::= ID|INDEXED */ + 207, /* (165) expr ::= JOIN_KW */ + 207, /* (166) expr ::= nm DOT nm */ + 207, /* (167) expr ::= nm DOT nm DOT nm */ + 206, /* (168) term ::= NULL|FLOAT|BLOB */ + 206, /* (169) term ::= STRING */ + 206, /* (170) term ::= INTEGER */ + 207, /* (171) expr ::= VARIABLE */ + 207, /* (172) expr ::= expr COLLATE ID|STRING */ + 207, /* (173) expr ::= CAST LP expr AS typetoken RP */ + 207, /* (174) expr ::= ID|INDEXED LP distinct exprlist RP */ + 207, /* (175) expr ::= ID|INDEXED LP STAR RP */ + 207, /* (176) expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ + 207, /* (177) expr ::= ID|INDEXED LP STAR RP over_clause */ + 206, /* (178) term ::= CTIME_KW */ + 207, /* (179) expr ::= LP nexprlist COMMA expr RP */ + 207, /* (180) expr ::= expr AND expr */ + 207, /* (181) expr ::= expr OR expr */ + 207, /* (182) expr ::= expr LT|GT|GE|LE expr */ + 207, /* (183) expr ::= expr EQ|NE expr */ + 207, /* (184) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + 207, /* (185) expr ::= expr PLUS|MINUS expr */ + 207, /* (186) expr ::= expr STAR|SLASH|REM expr */ + 207, /* (187) expr ::= expr CONCAT expr */ + 260, /* (188) likeop ::= NOT LIKE_KW|MATCH */ + 207, /* (189) expr ::= expr likeop expr */ + 207, /* (190) expr ::= expr likeop expr ESCAPE expr */ + 207, /* (191) expr ::= expr ISNULL|NOTNULL */ + 207, /* (192) expr ::= expr NOT NULL */ + 207, /* (193) expr ::= expr IS expr */ + 207, /* (194) expr ::= expr IS NOT expr */ + 207, /* (195) expr ::= NOT expr */ + 207, /* (196) expr ::= BITNOT expr */ + 207, /* (197) expr ::= PLUS|MINUS expr */ + 261, /* (198) between_op ::= BETWEEN */ + 261, /* (199) between_op ::= NOT BETWEEN */ + 207, /* (200) expr ::= expr between_op expr AND expr */ + 262, /* (201) in_op ::= IN */ + 262, /* (202) in_op ::= NOT IN */ + 207, /* (203) expr ::= expr in_op LP exprlist RP */ + 207, /* (204) expr ::= LP select RP */ + 207, /* (205) expr ::= expr in_op LP select RP */ + 207, /* (206) expr ::= expr in_op nm dbnm paren_exprlist */ + 207, /* (207) expr ::= EXISTS LP select RP */ + 207, /* (208) expr ::= CASE case_operand case_exprlist case_else END */ + 265, /* (209) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + 265, /* (210) case_exprlist ::= WHEN expr THEN expr */ + 266, /* (211) case_else ::= ELSE expr */ + 266, /* (212) case_else ::= */ + 264, /* (213) case_operand ::= expr */ + 264, /* (214) case_operand ::= */ + 251, /* (215) exprlist ::= */ + 242, /* (216) nexprlist ::= nexprlist COMMA expr */ + 242, /* (217) nexprlist ::= expr */ + 263, /* (218) paren_exprlist ::= */ + 263, /* (219) paren_exprlist ::= LP exprlist RP */ + 181, /* (220) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + 267, /* (221) uniqueflag ::= UNIQUE */ + 267, /* (222) uniqueflag ::= */ + 211, /* (223) eidlist_opt ::= */ + 211, /* (224) eidlist_opt ::= LP eidlist RP */ + 221, /* (225) eidlist ::= eidlist COMMA nm collate sortorder */ + 221, /* (226) eidlist ::= nm collate sortorder */ + 268, /* (227) collate ::= */ + 268, /* (228) collate ::= COLLATE ID|STRING */ + 181, /* (229) cmd ::= DROP INDEX ifexists fullname */ + 181, /* (230) cmd ::= VACUUM vinto */ + 181, /* (231) cmd ::= VACUUM nm vinto */ + 269, /* (232) vinto ::= INTO expr */ + 269, /* (233) vinto ::= */ + 181, /* (234) cmd ::= PRAGMA nm dbnm */ + 181, /* (235) cmd ::= PRAGMA nm dbnm EQ nmnum */ + 181, /* (236) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + 181, /* (237) cmd ::= PRAGMA nm dbnm EQ minus_num */ + 181, /* (238) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + 201, /* (239) plus_num ::= PLUS INTEGER|FLOAT */ + 202, /* (240) minus_num ::= MINUS INTEGER|FLOAT */ + 181, /* (241) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + 271, /* (242) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + 273, /* (243) trigger_time ::= BEFORE|AFTER */ + 273, /* (244) trigger_time ::= INSTEAD OF */ + 273, /* (245) trigger_time ::= */ + 274, /* (246) trigger_event ::= DELETE|INSERT */ + 274, /* (247) trigger_event ::= UPDATE */ + 274, /* (248) trigger_event ::= UPDATE OF idlist */ + 276, /* (249) when_clause ::= */ + 276, /* (250) when_clause ::= WHEN expr */ + 272, /* (251) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + 272, /* (252) trigger_cmd_list ::= trigger_cmd SEMI */ + 278, /* (253) trnm ::= nm DOT nm */ + 279, /* (254) tridxby ::= INDEXED BY nm */ + 279, /* (255) tridxby ::= NOT INDEXED */ + 277, /* (256) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ + 277, /* (257) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + 277, /* (258) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + 277, /* (259) trigger_cmd ::= scanpt select scanpt */ + 207, /* (260) expr ::= RAISE LP IGNORE RP */ + 207, /* (261) expr ::= RAISE LP raisetype COMMA nm RP */ + 225, /* (262) raisetype ::= ROLLBACK */ + 225, /* (263) raisetype ::= ABORT */ + 225, /* (264) raisetype ::= FAIL */ + 181, /* (265) cmd ::= DROP TRIGGER ifexists fullname */ + 181, /* (266) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + 181, /* (267) cmd ::= DETACH database_kw_opt expr */ + 281, /* (268) key_opt ::= */ + 281, /* (269) key_opt ::= KEY expr */ + 181, /* (270) cmd ::= REINDEX */ + 181, /* (271) cmd ::= REINDEX nm dbnm */ + 181, /* (272) cmd ::= ANALYZE */ + 181, /* (273) cmd ::= ANALYZE nm dbnm */ + 181, /* (274) cmd ::= ALTER TABLE fullname RENAME TO nm */ + 181, /* (275) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + 282, /* (276) add_column_fullname ::= fullname */ + 181, /* (277) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + 181, /* (278) cmd ::= create_vtab */ + 181, /* (279) cmd ::= create_vtab LP vtabarglist RP */ + 284, /* (280) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 286, /* (281) vtabarg ::= */ + 287, /* (282) vtabargtoken ::= ANY */ + 287, /* (283) vtabargtoken ::= lp anylist RP */ + 288, /* (284) lp ::= LP */ + 254, /* (285) with ::= WITH wqlist */ + 254, /* (286) with ::= WITH RECURSIVE wqlist */ + 230, /* (287) wqlist ::= nm eidlist_opt AS LP select RP */ + 230, /* (288) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ + 290, /* (289) windowdefn_list ::= windowdefn */ + 290, /* (290) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + 291, /* (291) windowdefn ::= nm AS LP window RP */ + 292, /* (292) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + 292, /* (293) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + 292, /* (294) window ::= ORDER BY sortlist frame_opt */ + 292, /* (295) window ::= nm ORDER BY sortlist frame_opt */ + 292, /* (296) window ::= frame_opt */ + 292, /* (297) window ::= nm frame_opt */ + 293, /* (298) frame_opt ::= */ + 293, /* (299) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + 293, /* (300) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + 296, /* (301) range_or_rows ::= RANGE|ROWS|GROUPS */ + 298, /* (302) frame_bound_s ::= frame_bound */ + 298, /* (303) frame_bound_s ::= UNBOUNDED PRECEDING */ + 299, /* (304) frame_bound_e ::= frame_bound */ + 299, /* (305) frame_bound_e ::= UNBOUNDED FOLLOWING */ + 297, /* (306) frame_bound ::= expr PRECEDING|FOLLOWING */ + 297, /* (307) frame_bound ::= CURRENT ROW */ + 300, /* (308) frame_exclude_opt ::= */ + 300, /* (309) frame_exclude_opt ::= EXCLUDE frame_exclude */ + 301, /* (310) frame_exclude ::= NO OTHERS */ + 301, /* (311) frame_exclude ::= CURRENT ROW */ + 301, /* (312) frame_exclude ::= GROUP|TIES */ + 240, /* (313) window_clause ::= WINDOW windowdefn_list */ + 259, /* (314) over_clause ::= filter_opt OVER LP window RP */ + 259, /* (315) over_clause ::= filter_opt OVER nm */ + 295, /* (316) filter_opt ::= */ + 295, /* (317) filter_opt ::= FILTER LP WHERE expr RP */ + 176, /* (318) input ::= cmdlist */ + 177, /* (319) cmdlist ::= cmdlist ecmd */ + 177, /* (320) cmdlist ::= ecmd */ + 178, /* (321) ecmd ::= SEMI */ + 178, /* (322) ecmd ::= cmdx SEMI */ + 178, /* (323) ecmd ::= explain cmdx */ + 183, /* (324) trans_opt ::= */ + 183, /* (325) trans_opt ::= TRANSACTION */ + 183, /* (326) trans_opt ::= TRANSACTION nm */ + 185, /* (327) savepoint_opt ::= SAVEPOINT */ + 185, /* (328) savepoint_opt ::= */ + 181, /* (329) cmd ::= create_table create_table_args */ + 192, /* (330) columnlist ::= columnlist COMMA columnname carglist */ + 192, /* (331) columnlist ::= columnname carglist */ + 184, /* (332) nm ::= ID|INDEXED */ + 184, /* (333) nm ::= STRING */ + 184, /* (334) nm ::= JOIN_KW */ + 198, /* (335) typetoken ::= typename */ + 199, /* (336) typename ::= ID|STRING */ + 200, /* (337) signed ::= plus_num */ + 200, /* (338) signed ::= minus_num */ + 197, /* (339) carglist ::= carglist ccons */ + 197, /* (340) carglist ::= */ + 205, /* (341) ccons ::= NULL onconf */ + 193, /* (342) conslist_opt ::= COMMA conslist */ + 217, /* (343) conslist ::= conslist tconscomma tcons */ + 217, /* (344) conslist ::= tcons */ + 218, /* (345) tconscomma ::= */ + 222, /* (346) defer_subclause_opt ::= defer_subclause */ + 224, /* (347) resolvetype ::= raisetype */ + 228, /* (348) selectnowith ::= oneselect */ + 229, /* (349) oneselect ::= values */ + 243, /* (350) sclp ::= selcollist COMMA */ + 244, /* (351) as ::= ID|STRING */ + 207, /* (352) expr ::= term */ + 260, /* (353) likeop ::= LIKE_KW|MATCH */ + 251, /* (354) exprlist ::= nexprlist */ + 270, /* (355) nmnum ::= plus_num */ + 270, /* (356) nmnum ::= nm */ + 270, /* (357) nmnum ::= ON */ + 270, /* (358) nmnum ::= DELETE */ + 270, /* (359) nmnum ::= DEFAULT */ + 201, /* (360) plus_num ::= INTEGER|FLOAT */ + 275, /* (361) foreach_clause ::= */ + 275, /* (362) foreach_clause ::= FOR EACH ROW */ + 278, /* (363) trnm ::= nm */ + 279, /* (364) tridxby ::= */ + 280, /* (365) database_kw_opt ::= DATABASE */ + 280, /* (366) database_kw_opt ::= */ + 283, /* (367) kwcolumn_opt ::= */ + 283, /* (368) kwcolumn_opt ::= COLUMNKW */ + 285, /* (369) vtabarglist ::= vtabarg */ + 285, /* (370) vtabarglist ::= vtabarglist COMMA vtabarg */ + 286, /* (371) vtabarg ::= vtabarg vtabargtoken */ + 289, /* (372) anylist ::= */ + 289, /* (373) anylist ::= anylist LP anylist RP */ + 289, /* (374) anylist ::= anylist ANY */ + 254, /* (375) with ::= */ +}; + +/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number +** of symbols on the right-hand side of that rule. */ +static const signed char yyRuleInfoNRhs[] = { + -1, /* (0) explain ::= EXPLAIN */ + -3, /* (1) explain ::= EXPLAIN QUERY PLAN */ + -1, /* (2) cmdx ::= cmd */ + -3, /* (3) cmd ::= BEGIN transtype trans_opt */ + 0, /* (4) transtype ::= */ + -1, /* (5) transtype ::= DEFERRED */ + -1, /* (6) transtype ::= IMMEDIATE */ + -1, /* (7) transtype ::= EXCLUSIVE */ + -2, /* (8) cmd ::= COMMIT|END trans_opt */ + -2, /* (9) cmd ::= ROLLBACK trans_opt */ + -2, /* (10) cmd ::= SAVEPOINT nm */ + -3, /* (11) cmd ::= RELEASE savepoint_opt nm */ + -5, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + -6, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + -1, /* (14) createkw ::= CREATE */ + 0, /* (15) ifnotexists ::= */ + -3, /* (16) ifnotexists ::= IF NOT EXISTS */ + -1, /* (17) temp ::= TEMP */ + 0, /* (18) temp ::= */ + -5, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */ + -2, /* (20) create_table_args ::= AS select */ + 0, /* (21) table_options ::= */ + -2, /* (22) table_options ::= WITHOUT nm */ + -2, /* (23) columnname ::= nm typetoken */ + 0, /* (24) typetoken ::= */ + -4, /* (25) typetoken ::= typename LP signed RP */ + -6, /* (26) typetoken ::= typename LP signed COMMA signed RP */ + -2, /* (27) typename ::= typename ID|STRING */ + 0, /* (28) scanpt ::= */ + 0, /* (29) scantok ::= */ + -2, /* (30) ccons ::= CONSTRAINT nm */ + -3, /* (31) ccons ::= DEFAULT scantok term */ + -4, /* (32) ccons ::= DEFAULT LP expr RP */ + -4, /* (33) ccons ::= DEFAULT PLUS scantok term */ + -4, /* (34) ccons ::= DEFAULT MINUS scantok term */ + -3, /* (35) ccons ::= DEFAULT scantok ID|INDEXED */ + -3, /* (36) ccons ::= NOT NULL onconf */ + -5, /* (37) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + -2, /* (38) ccons ::= UNIQUE onconf */ + -4, /* (39) ccons ::= CHECK LP expr RP */ + -4, /* (40) ccons ::= REFERENCES nm eidlist_opt refargs */ + -1, /* (41) ccons ::= defer_subclause */ + -2, /* (42) ccons ::= COLLATE ID|STRING */ + 0, /* (43) autoinc ::= */ + -1, /* (44) autoinc ::= AUTOINCR */ + 0, /* (45) refargs ::= */ + -2, /* (46) refargs ::= refargs refarg */ + -2, /* (47) refarg ::= MATCH nm */ + -3, /* (48) refarg ::= ON INSERT refact */ + -3, /* (49) refarg ::= ON DELETE refact */ + -3, /* (50) refarg ::= ON UPDATE refact */ + -2, /* (51) refact ::= SET NULL */ + -2, /* (52) refact ::= SET DEFAULT */ + -1, /* (53) refact ::= CASCADE */ + -1, /* (54) refact ::= RESTRICT */ + -2, /* (55) refact ::= NO ACTION */ + -3, /* (56) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + -2, /* (57) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 0, /* (58) init_deferred_pred_opt ::= */ + -2, /* (59) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + -2, /* (60) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 0, /* (61) conslist_opt ::= */ + -1, /* (62) tconscomma ::= COMMA */ + -2, /* (63) tcons ::= CONSTRAINT nm */ + -7, /* (64) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + -5, /* (65) tcons ::= UNIQUE LP sortlist RP onconf */ + -5, /* (66) tcons ::= CHECK LP expr RP onconf */ + -10, /* (67) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 0, /* (68) defer_subclause_opt ::= */ + 0, /* (69) onconf ::= */ + -3, /* (70) onconf ::= ON CONFLICT resolvetype */ + 0, /* (71) orconf ::= */ + -2, /* (72) orconf ::= OR resolvetype */ + -1, /* (73) resolvetype ::= IGNORE */ + -1, /* (74) resolvetype ::= REPLACE */ + -4, /* (75) cmd ::= DROP TABLE ifexists fullname */ + -2, /* (76) ifexists ::= IF EXISTS */ + 0, /* (77) ifexists ::= */ + -9, /* (78) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + -4, /* (79) cmd ::= DROP VIEW ifexists fullname */ + -1, /* (80) cmd ::= select */ + -3, /* (81) select ::= WITH wqlist selectnowith */ + -4, /* (82) select ::= WITH RECURSIVE wqlist selectnowith */ + -1, /* (83) select ::= selectnowith */ + -3, /* (84) selectnowith ::= selectnowith multiselect_op oneselect */ + -1, /* (85) multiselect_op ::= UNION */ + -2, /* (86) multiselect_op ::= UNION ALL */ + -1, /* (87) multiselect_op ::= EXCEPT|INTERSECT */ + -9, /* (88) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + -10, /* (89) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + -4, /* (90) values ::= VALUES LP nexprlist RP */ + -5, /* (91) values ::= values COMMA LP nexprlist RP */ + -1, /* (92) distinct ::= DISTINCT */ + -1, /* (93) distinct ::= ALL */ + 0, /* (94) distinct ::= */ + 0, /* (95) sclp ::= */ + -5, /* (96) selcollist ::= sclp scanpt expr scanpt as */ + -3, /* (97) selcollist ::= sclp scanpt STAR */ + -5, /* (98) selcollist ::= sclp scanpt nm DOT STAR */ + -2, /* (99) as ::= AS nm */ + 0, /* (100) as ::= */ + 0, /* (101) from ::= */ + -2, /* (102) from ::= FROM seltablist */ + -2, /* (103) stl_prefix ::= seltablist joinop */ + 0, /* (104) stl_prefix ::= */ + -7, /* (105) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + -9, /* (106) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + -7, /* (107) seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + -7, /* (108) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + 0, /* (109) dbnm ::= */ + -2, /* (110) dbnm ::= DOT nm */ + -1, /* (111) fullname ::= nm */ + -3, /* (112) fullname ::= nm DOT nm */ + -1, /* (113) xfullname ::= nm */ + -3, /* (114) xfullname ::= nm DOT nm */ + -5, /* (115) xfullname ::= nm DOT nm AS nm */ + -3, /* (116) xfullname ::= nm AS nm */ + -1, /* (117) joinop ::= COMMA|JOIN */ + -2, /* (118) joinop ::= JOIN_KW JOIN */ + -3, /* (119) joinop ::= JOIN_KW nm JOIN */ + -4, /* (120) joinop ::= JOIN_KW nm nm JOIN */ + -2, /* (121) on_opt ::= ON expr */ + 0, /* (122) on_opt ::= */ + 0, /* (123) indexed_opt ::= */ + -3, /* (124) indexed_opt ::= INDEXED BY nm */ + -2, /* (125) indexed_opt ::= NOT INDEXED */ + -4, /* (126) using_opt ::= USING LP idlist RP */ + 0, /* (127) using_opt ::= */ + 0, /* (128) orderby_opt ::= */ + -3, /* (129) orderby_opt ::= ORDER BY sortlist */ + -4, /* (130) sortlist ::= sortlist COMMA expr sortorder */ + -2, /* (131) sortlist ::= expr sortorder */ + -1, /* (132) sortorder ::= ASC */ + -1, /* (133) sortorder ::= DESC */ + 0, /* (134) sortorder ::= */ + 0, /* (135) groupby_opt ::= */ + -3, /* (136) groupby_opt ::= GROUP BY nexprlist */ + 0, /* (137) having_opt ::= */ + -2, /* (138) having_opt ::= HAVING expr */ + 0, /* (139) limit_opt ::= */ + -2, /* (140) limit_opt ::= LIMIT expr */ + -4, /* (141) limit_opt ::= LIMIT expr OFFSET expr */ + -4, /* (142) limit_opt ::= LIMIT expr COMMA expr */ + -6, /* (143) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ + 0, /* (144) where_opt ::= */ + -2, /* (145) where_opt ::= WHERE expr */ + -8, /* (146) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ + -5, /* (147) setlist ::= setlist COMMA nm EQ expr */ + -7, /* (148) setlist ::= setlist COMMA LP idlist RP EQ expr */ + -3, /* (149) setlist ::= nm EQ expr */ + -5, /* (150) setlist ::= LP idlist RP EQ expr */ + -7, /* (151) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + -7, /* (152) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ + 0, /* (153) upsert ::= */ + -11, /* (154) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ + -8, /* (155) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ + -4, /* (156) upsert ::= ON CONFLICT DO NOTHING */ + -2, /* (157) insert_cmd ::= INSERT orconf */ + -1, /* (158) insert_cmd ::= REPLACE */ + 0, /* (159) idlist_opt ::= */ + -3, /* (160) idlist_opt ::= LP idlist RP */ + -3, /* (161) idlist ::= idlist COMMA nm */ + -1, /* (162) idlist ::= nm */ + -3, /* (163) expr ::= LP expr RP */ + -1, /* (164) expr ::= ID|INDEXED */ + -1, /* (165) expr ::= JOIN_KW */ + -3, /* (166) expr ::= nm DOT nm */ + -5, /* (167) expr ::= nm DOT nm DOT nm */ + -1, /* (168) term ::= NULL|FLOAT|BLOB */ + -1, /* (169) term ::= STRING */ + -1, /* (170) term ::= INTEGER */ + -1, /* (171) expr ::= VARIABLE */ + -3, /* (172) expr ::= expr COLLATE ID|STRING */ + -6, /* (173) expr ::= CAST LP expr AS typetoken RP */ + -5, /* (174) expr ::= ID|INDEXED LP distinct exprlist RP */ + -4, /* (175) expr ::= ID|INDEXED LP STAR RP */ + -6, /* (176) expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ + -5, /* (177) expr ::= ID|INDEXED LP STAR RP over_clause */ + -1, /* (178) term ::= CTIME_KW */ + -5, /* (179) expr ::= LP nexprlist COMMA expr RP */ + -3, /* (180) expr ::= expr AND expr */ + -3, /* (181) expr ::= expr OR expr */ + -3, /* (182) expr ::= expr LT|GT|GE|LE expr */ + -3, /* (183) expr ::= expr EQ|NE expr */ + -3, /* (184) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + -3, /* (185) expr ::= expr PLUS|MINUS expr */ + -3, /* (186) expr ::= expr STAR|SLASH|REM expr */ + -3, /* (187) expr ::= expr CONCAT expr */ + -2, /* (188) likeop ::= NOT LIKE_KW|MATCH */ + -3, /* (189) expr ::= expr likeop expr */ + -5, /* (190) expr ::= expr likeop expr ESCAPE expr */ + -2, /* (191) expr ::= expr ISNULL|NOTNULL */ + -3, /* (192) expr ::= expr NOT NULL */ + -3, /* (193) expr ::= expr IS expr */ + -4, /* (194) expr ::= expr IS NOT expr */ + -2, /* (195) expr ::= NOT expr */ + -2, /* (196) expr ::= BITNOT expr */ + -2, /* (197) expr ::= PLUS|MINUS expr */ + -1, /* (198) between_op ::= BETWEEN */ + -2, /* (199) between_op ::= NOT BETWEEN */ + -5, /* (200) expr ::= expr between_op expr AND expr */ + -1, /* (201) in_op ::= IN */ + -2, /* (202) in_op ::= NOT IN */ + -5, /* (203) expr ::= expr in_op LP exprlist RP */ + -3, /* (204) expr ::= LP select RP */ + -5, /* (205) expr ::= expr in_op LP select RP */ + -5, /* (206) expr ::= expr in_op nm dbnm paren_exprlist */ + -4, /* (207) expr ::= EXISTS LP select RP */ + -5, /* (208) expr ::= CASE case_operand case_exprlist case_else END */ + -5, /* (209) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + -4, /* (210) case_exprlist ::= WHEN expr THEN expr */ + -2, /* (211) case_else ::= ELSE expr */ + 0, /* (212) case_else ::= */ + -1, /* (213) case_operand ::= expr */ + 0, /* (214) case_operand ::= */ + 0, /* (215) exprlist ::= */ + -3, /* (216) nexprlist ::= nexprlist COMMA expr */ + -1, /* (217) nexprlist ::= expr */ + 0, /* (218) paren_exprlist ::= */ + -3, /* (219) paren_exprlist ::= LP exprlist RP */ + -12, /* (220) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + -1, /* (221) uniqueflag ::= UNIQUE */ + 0, /* (222) uniqueflag ::= */ + 0, /* (223) eidlist_opt ::= */ + -3, /* (224) eidlist_opt ::= LP eidlist RP */ + -5, /* (225) eidlist ::= eidlist COMMA nm collate sortorder */ + -3, /* (226) eidlist ::= nm collate sortorder */ + 0, /* (227) collate ::= */ + -2, /* (228) collate ::= COLLATE ID|STRING */ + -4, /* (229) cmd ::= DROP INDEX ifexists fullname */ + -2, /* (230) cmd ::= VACUUM vinto */ + -3, /* (231) cmd ::= VACUUM nm vinto */ + -2, /* (232) vinto ::= INTO expr */ + 0, /* (233) vinto ::= */ + -3, /* (234) cmd ::= PRAGMA nm dbnm */ + -5, /* (235) cmd ::= PRAGMA nm dbnm EQ nmnum */ + -6, /* (236) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + -5, /* (237) cmd ::= PRAGMA nm dbnm EQ minus_num */ + -6, /* (238) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + -2, /* (239) plus_num ::= PLUS INTEGER|FLOAT */ + -2, /* (240) minus_num ::= MINUS INTEGER|FLOAT */ + -5, /* (241) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + -11, /* (242) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + -1, /* (243) trigger_time ::= BEFORE|AFTER */ + -2, /* (244) trigger_time ::= INSTEAD OF */ + 0, /* (245) trigger_time ::= */ + -1, /* (246) trigger_event ::= DELETE|INSERT */ + -1, /* (247) trigger_event ::= UPDATE */ + -3, /* (248) trigger_event ::= UPDATE OF idlist */ + 0, /* (249) when_clause ::= */ + -2, /* (250) when_clause ::= WHEN expr */ + -3, /* (251) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + -2, /* (252) trigger_cmd_list ::= trigger_cmd SEMI */ + -3, /* (253) trnm ::= nm DOT nm */ + -3, /* (254) tridxby ::= INDEXED BY nm */ + -2, /* (255) tridxby ::= NOT INDEXED */ + -8, /* (256) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ + -8, /* (257) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + -6, /* (258) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + -3, /* (259) trigger_cmd ::= scanpt select scanpt */ + -4, /* (260) expr ::= RAISE LP IGNORE RP */ + -6, /* (261) expr ::= RAISE LP raisetype COMMA nm RP */ + -1, /* (262) raisetype ::= ROLLBACK */ + -1, /* (263) raisetype ::= ABORT */ + -1, /* (264) raisetype ::= FAIL */ + -4, /* (265) cmd ::= DROP TRIGGER ifexists fullname */ + -6, /* (266) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + -3, /* (267) cmd ::= DETACH database_kw_opt expr */ + 0, /* (268) key_opt ::= */ + -2, /* (269) key_opt ::= KEY expr */ + -1, /* (270) cmd ::= REINDEX */ + -3, /* (271) cmd ::= REINDEX nm dbnm */ + -1, /* (272) cmd ::= ANALYZE */ + -3, /* (273) cmd ::= ANALYZE nm dbnm */ + -6, /* (274) cmd ::= ALTER TABLE fullname RENAME TO nm */ + -7, /* (275) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + -1, /* (276) add_column_fullname ::= fullname */ + -8, /* (277) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + -1, /* (278) cmd ::= create_vtab */ + -4, /* (279) cmd ::= create_vtab LP vtabarglist RP */ + -8, /* (280) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 0, /* (281) vtabarg ::= */ + -1, /* (282) vtabargtoken ::= ANY */ + -3, /* (283) vtabargtoken ::= lp anylist RP */ + -1, /* (284) lp ::= LP */ + -2, /* (285) with ::= WITH wqlist */ + -3, /* (286) with ::= WITH RECURSIVE wqlist */ + -6, /* (287) wqlist ::= nm eidlist_opt AS LP select RP */ + -8, /* (288) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ + -1, /* (289) windowdefn_list ::= windowdefn */ + -3, /* (290) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + -5, /* (291) windowdefn ::= nm AS LP window RP */ + -5, /* (292) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + -6, /* (293) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + -4, /* (294) window ::= ORDER BY sortlist frame_opt */ + -5, /* (295) window ::= nm ORDER BY sortlist frame_opt */ + -1, /* (296) window ::= frame_opt */ + -2, /* (297) window ::= nm frame_opt */ + 0, /* (298) frame_opt ::= */ + -3, /* (299) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + -6, /* (300) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + -1, /* (301) range_or_rows ::= RANGE|ROWS|GROUPS */ + -1, /* (302) frame_bound_s ::= frame_bound */ + -2, /* (303) frame_bound_s ::= UNBOUNDED PRECEDING */ + -1, /* (304) frame_bound_e ::= frame_bound */ + -2, /* (305) frame_bound_e ::= UNBOUNDED FOLLOWING */ + -2, /* (306) frame_bound ::= expr PRECEDING|FOLLOWING */ + -2, /* (307) frame_bound ::= CURRENT ROW */ + 0, /* (308) frame_exclude_opt ::= */ + -2, /* (309) frame_exclude_opt ::= EXCLUDE frame_exclude */ + -2, /* (310) frame_exclude ::= NO OTHERS */ + -2, /* (311) frame_exclude ::= CURRENT ROW */ + -1, /* (312) frame_exclude ::= GROUP|TIES */ + -2, /* (313) window_clause ::= WINDOW windowdefn_list */ + -5, /* (314) over_clause ::= filter_opt OVER LP window RP */ + -3, /* (315) over_clause ::= filter_opt OVER nm */ + 0, /* (316) filter_opt ::= */ + -5, /* (317) filter_opt ::= FILTER LP WHERE expr RP */ + -1, /* (318) input ::= cmdlist */ + -2, /* (319) cmdlist ::= cmdlist ecmd */ + -1, /* (320) cmdlist ::= ecmd */ + -1, /* (321) ecmd ::= SEMI */ + -2, /* (322) ecmd ::= cmdx SEMI */ + -2, /* (323) ecmd ::= explain cmdx */ + 0, /* (324) trans_opt ::= */ + -1, /* (325) trans_opt ::= TRANSACTION */ + -2, /* (326) trans_opt ::= TRANSACTION nm */ + -1, /* (327) savepoint_opt ::= SAVEPOINT */ + 0, /* (328) savepoint_opt ::= */ + -2, /* (329) cmd ::= create_table create_table_args */ + -4, /* (330) columnlist ::= columnlist COMMA columnname carglist */ + -2, /* (331) columnlist ::= columnname carglist */ + -1, /* (332) nm ::= ID|INDEXED */ + -1, /* (333) nm ::= STRING */ + -1, /* (334) nm ::= JOIN_KW */ + -1, /* (335) typetoken ::= typename */ + -1, /* (336) typename ::= ID|STRING */ + -1, /* (337) signed ::= plus_num */ + -1, /* (338) signed ::= minus_num */ + -2, /* (339) carglist ::= carglist ccons */ + 0, /* (340) carglist ::= */ + -2, /* (341) ccons ::= NULL onconf */ + -2, /* (342) conslist_opt ::= COMMA conslist */ + -3, /* (343) conslist ::= conslist tconscomma tcons */ + -1, /* (344) conslist ::= tcons */ + 0, /* (345) tconscomma ::= */ + -1, /* (346) defer_subclause_opt ::= defer_subclause */ + -1, /* (347) resolvetype ::= raisetype */ + -1, /* (348) selectnowith ::= oneselect */ + -1, /* (349) oneselect ::= values */ + -2, /* (350) sclp ::= selcollist COMMA */ + -1, /* (351) as ::= ID|STRING */ + -1, /* (352) expr ::= term */ + -1, /* (353) likeop ::= LIKE_KW|MATCH */ + -1, /* (354) exprlist ::= nexprlist */ + -1, /* (355) nmnum ::= plus_num */ + -1, /* (356) nmnum ::= nm */ + -1, /* (357) nmnum ::= ON */ + -1, /* (358) nmnum ::= DELETE */ + -1, /* (359) nmnum ::= DEFAULT */ + -1, /* (360) plus_num ::= INTEGER|FLOAT */ + 0, /* (361) foreach_clause ::= */ + -3, /* (362) foreach_clause ::= FOR EACH ROW */ + -1, /* (363) trnm ::= nm */ + 0, /* (364) tridxby ::= */ + -1, /* (365) database_kw_opt ::= DATABASE */ + 0, /* (366) database_kw_opt ::= */ + 0, /* (367) kwcolumn_opt ::= */ + -1, /* (368) kwcolumn_opt ::= COLUMNKW */ + -1, /* (369) vtabarglist ::= vtabarg */ + -3, /* (370) vtabarglist ::= vtabarglist COMMA vtabarg */ + -2, /* (371) vtabarg ::= vtabarg vtabargtoken */ + 0, /* (372) anylist ::= */ + -4, /* (373) anylist ::= anylist LP anylist RP */ + -2, /* (374) anylist ::= anylist ANY */ + 0, /* (375) with ::= */ }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -148587,7 +151835,7 @@ static YYACTIONTYPE yy_reduce( yymsp = yypParser->yytos; #ifndef NDEBUG if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ - yysize = yyRuleInfo[yyruleno].nrhs; + yysize = yyRuleInfoNRhs[yyruleno]; if( yysize ){ fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n", yyTracePrompt, @@ -148602,7 +151850,7 @@ static YYACTIONTYPE yy_reduce( /* Check that the stack is large enough to grow by a single entry ** if the RHS of the rule is empty. This ensures that there is room ** enough on the stack to push the LHS value */ - if( yyRuleInfo[yyruleno].nrhs==0 ){ + if( yyRuleInfoNRhs[yyruleno]==0 ){ #ifdef YYTRACKMAXSTACKDEPTH if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ yypParser->yyhwm++; @@ -148652,15 +151900,16 @@ static YYACTIONTYPE yy_reduce( { sqlite3FinishCoding(pParse); } break; case 3: /* cmd ::= BEGIN transtype trans_opt */ -{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy70);} +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy100);} break; case 4: /* transtype ::= */ -{yymsp[1].minor.yy70 = TK_DEFERRED;} +{yymsp[1].minor.yy100 = TK_DEFERRED;} break; case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); -{yymsp[0].minor.yy70 = yymsp[0].major; /*A-overwrites-X*/} + case 301: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==301); +{yymsp[0].minor.yy100 = yymsp[0].major; /*A-overwrites-X*/} break; case 8: /* cmd ::= COMMIT|END trans_opt */ case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); @@ -148683,7 +151932,7 @@ static YYACTIONTYPE yy_reduce( break; case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { - sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy70,0,0,yymsp[-2].minor.yy70); + sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy100,0,0,yymsp[-2].minor.yy100); } break; case 14: /* createkw ::= CREATE */ @@ -148692,38 +151941,38 @@ static YYACTIONTYPE yy_reduce( case 15: /* ifnotexists ::= */ case 18: /* temp ::= */ yytestcase(yyruleno==18); case 21: /* table_options ::= */ yytestcase(yyruleno==21); - case 42: /* autoinc ::= */ yytestcase(yyruleno==42); - case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57); - case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67); - case 76: /* ifexists ::= */ yytestcase(yyruleno==76); - case 93: /* distinct ::= */ yytestcase(yyruleno==93); - case 226: /* collate ::= */ yytestcase(yyruleno==226); -{yymsp[1].minor.yy70 = 0;} + case 43: /* autoinc ::= */ yytestcase(yyruleno==43); + case 58: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==58); + case 68: /* defer_subclause_opt ::= */ yytestcase(yyruleno==68); + case 77: /* ifexists ::= */ yytestcase(yyruleno==77); + case 94: /* distinct ::= */ yytestcase(yyruleno==94); + case 227: /* collate ::= */ yytestcase(yyruleno==227); +{yymsp[1].minor.yy100 = 0;} break; case 16: /* ifnotexists ::= IF NOT EXISTS */ -{yymsp[-2].minor.yy70 = 1;} +{yymsp[-2].minor.yy100 = 1;} break; case 17: /* temp ::= TEMP */ - case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43); -{yymsp[0].minor.yy70 = 1;} + case 44: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==44); +{yymsp[0].minor.yy100 = 1;} break; case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_options */ { - sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy70,0); + sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy100,0); } break; case 20: /* create_table_args ::= AS select */ { - sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy489); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy489); + sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy391); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy391); } break; case 22: /* table_options ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ - yymsp[-1].minor.yy70 = TF_WithoutRowid | TF_NoVisibleRowid; + yymsp[-1].minor.yy100 = TF_WithoutRowid | TF_NoVisibleRowid; }else{ - yymsp[-1].minor.yy70 = 0; + yymsp[-1].minor.yy100 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } @@ -148732,8 +151981,8 @@ static YYACTIONTYPE yy_reduce( {sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);} break; case 24: /* typetoken ::= */ - case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60); - case 99: /* as ::= */ yytestcase(yyruleno==99); + case 61: /* conslist_opt ::= */ yytestcase(yyruleno==61); + case 100: /* as ::= */ yytestcase(yyruleno==100); {yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} break; case 25: /* typetoken ::= typename LP signed RP */ @@ -148752,29 +152001,35 @@ static YYACTIONTYPE yy_reduce( case 28: /* scanpt ::= */ { assert( yyLookahead!=YYNOCODE ); - yymsp[1].minor.yy392 = yyLookaheadToken.z; + yymsp[1].minor.yy528 = yyLookaheadToken.z; +} + break; + case 29: /* scantok ::= */ +{ + assert( yyLookahead!=YYNOCODE ); + yymsp[1].minor.yy0 = yyLookaheadToken; } break; - case 29: /* ccons ::= CONSTRAINT nm */ - case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62); + case 30: /* ccons ::= CONSTRAINT nm */ + case 63: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==63); {pParse->constraintName = yymsp[0].minor.yy0;} break; - case 30: /* ccons ::= DEFAULT scanpt term scanpt */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy18,yymsp[-2].minor.yy392,yymsp[0].minor.yy392);} + case 31: /* ccons ::= DEFAULT scantok term */ +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy102,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; - case 31: /* ccons ::= DEFAULT LP expr RP */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy18,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} + case 32: /* ccons ::= DEFAULT LP expr RP */ +{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy102,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} break; - case 32: /* ccons ::= DEFAULT PLUS term scanpt */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy18,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy392);} + case 33: /* ccons ::= DEFAULT PLUS scantok term */ +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy102,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; - case 33: /* ccons ::= DEFAULT MINUS term scanpt */ + case 34: /* ccons ::= DEFAULT MINUS scantok term */ { - Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[-1].minor.yy18, 0); - sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy392); + Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy102, 0); + sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]); } break; - case 34: /* ccons ::= DEFAULT scanpt ID|INDEXED */ + case 35: /* ccons ::= DEFAULT scantok ID|INDEXED */ { Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0); if( p ){ @@ -148784,171 +152039,171 @@ static YYACTIONTYPE yy_reduce( sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n); } break; - case 35: /* ccons ::= NOT NULL onconf */ -{sqlite3AddNotNull(pParse, yymsp[0].minor.yy70);} + case 36: /* ccons ::= NOT NULL onconf */ +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy100);} break; - case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ -{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy70,yymsp[0].minor.yy70,yymsp[-2].minor.yy70);} + case 37: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy100,yymsp[0].minor.yy100,yymsp[-2].minor.yy100);} break; - case 37: /* ccons ::= UNIQUE onconf */ -{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy70,0,0,0,0, + case 38: /* ccons ::= UNIQUE onconf */ +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy100,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; - case 38: /* ccons ::= CHECK LP expr RP */ -{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy18);} + case 39: /* ccons ::= CHECK LP expr RP */ +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy102);} break; - case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */ -{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy420,yymsp[0].minor.yy70);} + case 40: /* ccons ::= REFERENCES nm eidlist_opt refargs */ +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy94,yymsp[0].minor.yy100);} break; - case 40: /* ccons ::= defer_subclause */ -{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy70);} + case 41: /* ccons ::= defer_subclause */ +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy100);} break; - case 41: /* ccons ::= COLLATE ID|STRING */ + case 42: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; - case 44: /* refargs ::= */ -{ yymsp[1].minor.yy70 = OE_None*0x0101; /* EV: R-19803-45884 */} + case 45: /* refargs ::= */ +{ yymsp[1].minor.yy100 = OE_None*0x0101; /* EV: R-19803-45884 */} break; - case 45: /* refargs ::= refargs refarg */ -{ yymsp[-1].minor.yy70 = (yymsp[-1].minor.yy70 & ~yymsp[0].minor.yy111.mask) | yymsp[0].minor.yy111.value; } + case 46: /* refargs ::= refargs refarg */ +{ yymsp[-1].minor.yy100 = (yymsp[-1].minor.yy100 & ~yymsp[0].minor.yy199.mask) | yymsp[0].minor.yy199.value; } break; - case 46: /* refarg ::= MATCH nm */ -{ yymsp[-1].minor.yy111.value = 0; yymsp[-1].minor.yy111.mask = 0x000000; } + case 47: /* refarg ::= MATCH nm */ +{ yymsp[-1].minor.yy199.value = 0; yymsp[-1].minor.yy199.mask = 0x000000; } break; - case 47: /* refarg ::= ON INSERT refact */ -{ yymsp[-2].minor.yy111.value = 0; yymsp[-2].minor.yy111.mask = 0x000000; } + case 48: /* refarg ::= ON INSERT refact */ +{ yymsp[-2].minor.yy199.value = 0; yymsp[-2].minor.yy199.mask = 0x000000; } break; - case 48: /* refarg ::= ON DELETE refact */ -{ yymsp[-2].minor.yy111.value = yymsp[0].minor.yy70; yymsp[-2].minor.yy111.mask = 0x0000ff; } + case 49: /* refarg ::= ON DELETE refact */ +{ yymsp[-2].minor.yy199.value = yymsp[0].minor.yy100; yymsp[-2].minor.yy199.mask = 0x0000ff; } break; - case 49: /* refarg ::= ON UPDATE refact */ -{ yymsp[-2].minor.yy111.value = yymsp[0].minor.yy70<<8; yymsp[-2].minor.yy111.mask = 0x00ff00; } + case 50: /* refarg ::= ON UPDATE refact */ +{ yymsp[-2].minor.yy199.value = yymsp[0].minor.yy100<<8; yymsp[-2].minor.yy199.mask = 0x00ff00; } break; - case 50: /* refact ::= SET NULL */ -{ yymsp[-1].minor.yy70 = OE_SetNull; /* EV: R-33326-45252 */} + case 51: /* refact ::= SET NULL */ +{ yymsp[-1].minor.yy100 = OE_SetNull; /* EV: R-33326-45252 */} break; - case 51: /* refact ::= SET DEFAULT */ -{ yymsp[-1].minor.yy70 = OE_SetDflt; /* EV: R-33326-45252 */} + case 52: /* refact ::= SET DEFAULT */ +{ yymsp[-1].minor.yy100 = OE_SetDflt; /* EV: R-33326-45252 */} break; - case 52: /* refact ::= CASCADE */ -{ yymsp[0].minor.yy70 = OE_Cascade; /* EV: R-33326-45252 */} + case 53: /* refact ::= CASCADE */ +{ yymsp[0].minor.yy100 = OE_Cascade; /* EV: R-33326-45252 */} break; - case 53: /* refact ::= RESTRICT */ -{ yymsp[0].minor.yy70 = OE_Restrict; /* EV: R-33326-45252 */} + case 54: /* refact ::= RESTRICT */ +{ yymsp[0].minor.yy100 = OE_Restrict; /* EV: R-33326-45252 */} break; - case 54: /* refact ::= NO ACTION */ -{ yymsp[-1].minor.yy70 = OE_None; /* EV: R-33326-45252 */} + case 55: /* refact ::= NO ACTION */ +{ yymsp[-1].minor.yy100 = OE_None; /* EV: R-33326-45252 */} break; - case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ -{yymsp[-2].minor.yy70 = 0;} + case 56: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ +{yymsp[-2].minor.yy100 = 0;} break; - case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71); - case 156: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==156); -{yymsp[-1].minor.yy70 = yymsp[0].minor.yy70;} + case 57: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + case 72: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==72); + case 157: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==157); +{yymsp[-1].minor.yy100 = yymsp[0].minor.yy100;} break; - case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ - case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75); - case 198: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==198); - case 201: /* in_op ::= NOT IN */ yytestcase(yyruleno==201); - case 227: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==227); -{yymsp[-1].minor.yy70 = 1;} + case 59: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ + case 76: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==76); + case 199: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==199); + case 202: /* in_op ::= NOT IN */ yytestcase(yyruleno==202); + case 228: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==228); +{yymsp[-1].minor.yy100 = 1;} break; - case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ -{yymsp[-1].minor.yy70 = 0;} + case 60: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ +{yymsp[-1].minor.yy100 = 0;} break; - case 61: /* tconscomma ::= COMMA */ + case 62: /* tconscomma ::= COMMA */ {pParse->constraintName.n = 0;} break; - case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ -{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy420,yymsp[0].minor.yy70,yymsp[-2].minor.yy70,0);} + case 64: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy94,yymsp[0].minor.yy100,yymsp[-2].minor.yy100,0);} break; - case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */ -{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy420,yymsp[0].minor.yy70,0,0,0,0, + case 65: /* tcons ::= UNIQUE LP sortlist RP onconf */ +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy94,yymsp[0].minor.yy100,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; - case 65: /* tcons ::= CHECK LP expr RP onconf */ -{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy18);} + case 66: /* tcons ::= CHECK LP expr RP onconf */ +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy102);} break; - case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + case 67: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { - sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy420, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy420, yymsp[-1].minor.yy70); - sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy70); + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy94, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy94, yymsp[-1].minor.yy100); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy100); } break; - case 68: /* onconf ::= */ - case 70: /* orconf ::= */ yytestcase(yyruleno==70); -{yymsp[1].minor.yy70 = OE_Default;} + case 69: /* onconf ::= */ + case 71: /* orconf ::= */ yytestcase(yyruleno==71); +{yymsp[1].minor.yy100 = OE_Default;} break; - case 69: /* onconf ::= ON CONFLICT resolvetype */ -{yymsp[-2].minor.yy70 = yymsp[0].minor.yy70;} + case 70: /* onconf ::= ON CONFLICT resolvetype */ +{yymsp[-2].minor.yy100 = yymsp[0].minor.yy100;} break; - case 72: /* resolvetype ::= IGNORE */ -{yymsp[0].minor.yy70 = OE_Ignore;} + case 73: /* resolvetype ::= IGNORE */ +{yymsp[0].minor.yy100 = OE_Ignore;} break; - case 73: /* resolvetype ::= REPLACE */ - case 157: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==157); -{yymsp[0].minor.yy70 = OE_Replace;} + case 74: /* resolvetype ::= REPLACE */ + case 158: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==158); +{yymsp[0].minor.yy100 = OE_Replace;} break; - case 74: /* cmd ::= DROP TABLE ifexists fullname */ + case 75: /* cmd ::= DROP TABLE ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy135, 0, yymsp[-1].minor.yy70); + sqlite3DropTable(pParse, yymsp[0].minor.yy407, 0, yymsp[-1].minor.yy100); } break; - case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + case 78: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ { - sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy420, yymsp[0].minor.yy489, yymsp[-7].minor.yy70, yymsp[-5].minor.yy70); + sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy94, yymsp[0].minor.yy391, yymsp[-7].minor.yy100, yymsp[-5].minor.yy100); } break; - case 78: /* cmd ::= DROP VIEW ifexists fullname */ + case 79: /* cmd ::= DROP VIEW ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy135, 1, yymsp[-1].minor.yy70); + sqlite3DropTable(pParse, yymsp[0].minor.yy407, 1, yymsp[-1].minor.yy100); } break; - case 79: /* cmd ::= select */ + case 80: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; - sqlite3Select(pParse, yymsp[0].minor.yy489, &dest); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy489); + sqlite3Select(pParse, yymsp[0].minor.yy391, &dest); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy391); } break; - case 80: /* select ::= WITH wqlist selectnowith */ + case 81: /* select ::= WITH wqlist selectnowith */ { - Select *p = yymsp[0].minor.yy489; + Select *p = yymsp[0].minor.yy391; if( p ){ - p->pWith = yymsp[-1].minor.yy449; + p->pWith = yymsp[-1].minor.yy243; parserDoubleLinkSelect(pParse, p); }else{ - sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy449); + sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy243); } - yymsp[-2].minor.yy489 = p; + yymsp[-2].minor.yy391 = p; } break; - case 81: /* select ::= WITH RECURSIVE wqlist selectnowith */ + case 82: /* select ::= WITH RECURSIVE wqlist selectnowith */ { - Select *p = yymsp[0].minor.yy489; + Select *p = yymsp[0].minor.yy391; if( p ){ - p->pWith = yymsp[-1].minor.yy449; + p->pWith = yymsp[-1].minor.yy243; parserDoubleLinkSelect(pParse, p); }else{ - sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy449); + sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy243); } - yymsp[-3].minor.yy489 = p; + yymsp[-3].minor.yy391 = p; } break; - case 82: /* select ::= selectnowith */ + case 83: /* select ::= selectnowith */ { - Select *p = yymsp[0].minor.yy489; + Select *p = yymsp[0].minor.yy391; if( p ){ parserDoubleLinkSelect(pParse, p); } - yymsp[0].minor.yy489 = p; /*A-overwrites-X*/ + yymsp[0].minor.yy391 = p; /*A-overwrites-X*/ } break; - case 83: /* selectnowith ::= selectnowith multiselect_op oneselect */ + case 84: /* selectnowith ::= selectnowith multiselect_op oneselect */ { - Select *pRhs = yymsp[0].minor.yy489; - Select *pLhs = yymsp[-2].minor.yy489; + Select *pRhs = yymsp[0].minor.yy391; + Select *pLhs = yymsp[-2].minor.yy391; if( pRhs && pRhs->pPrior ){ SrcList *pFrom; Token x; @@ -148958,341 +152213,349 @@ static YYACTIONTYPE yy_reduce( pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0); } if( pRhs ){ - pRhs->op = (u8)yymsp[-1].minor.yy70; + pRhs->op = (u8)yymsp[-1].minor.yy100; pRhs->pPrior = pLhs; if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; pRhs->selFlags &= ~SF_MultiValue; - if( yymsp[-1].minor.yy70!=TK_ALL ) pParse->hasCompound = 1; + if( yymsp[-1].minor.yy100!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); } - yymsp[-2].minor.yy489 = pRhs; + yymsp[-2].minor.yy391 = pRhs; } break; - case 84: /* multiselect_op ::= UNION */ - case 86: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==86); -{yymsp[0].minor.yy70 = yymsp[0].major; /*A-overwrites-OP*/} + case 85: /* multiselect_op ::= UNION */ + case 87: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==87); +{yymsp[0].minor.yy100 = yymsp[0].major; /*A-overwrites-OP*/} break; - case 85: /* multiselect_op ::= UNION ALL */ -{yymsp[-1].minor.yy70 = TK_ALL;} + case 86: /* multiselect_op ::= UNION ALL */ +{yymsp[-1].minor.yy100 = TK_ALL;} break; - case 87: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + case 88: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { - yymsp[-8].minor.yy489 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy420,yymsp[-5].minor.yy135,yymsp[-4].minor.yy18,yymsp[-3].minor.yy420,yymsp[-2].minor.yy18,yymsp[-1].minor.yy420,yymsp[-7].minor.yy70,yymsp[0].minor.yy18); + yymsp[-8].minor.yy391 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy94,yymsp[-5].minor.yy407,yymsp[-4].minor.yy102,yymsp[-3].minor.yy94,yymsp[-2].minor.yy102,yymsp[-1].minor.yy94,yymsp[-7].minor.yy100,yymsp[0].minor.yy102); } break; - case 88: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + case 89: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ { - yymsp[-9].minor.yy489 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy420,yymsp[-6].minor.yy135,yymsp[-5].minor.yy18,yymsp[-4].minor.yy420,yymsp[-3].minor.yy18,yymsp[-1].minor.yy420,yymsp[-8].minor.yy70,yymsp[0].minor.yy18); - if( yymsp[-9].minor.yy489 ){ - yymsp[-9].minor.yy489->pWinDefn = yymsp[-2].minor.yy327; + yymsp[-9].minor.yy391 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy94,yymsp[-6].minor.yy407,yymsp[-5].minor.yy102,yymsp[-4].minor.yy94,yymsp[-3].minor.yy102,yymsp[-1].minor.yy94,yymsp[-8].minor.yy100,yymsp[0].minor.yy102); + if( yymsp[-9].minor.yy391 ){ + yymsp[-9].minor.yy391->pWinDefn = yymsp[-2].minor.yy379; }else{ - sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy327); + sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy379); } } break; - case 89: /* values ::= VALUES LP nexprlist RP */ + case 90: /* values ::= VALUES LP nexprlist RP */ { - yymsp[-3].minor.yy489 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy420,0,0,0,0,0,SF_Values,0); + yymsp[-3].minor.yy391 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy94,0,0,0,0,0,SF_Values,0); } break; - case 90: /* values ::= values COMMA LP nexprlist RP */ + case 91: /* values ::= values COMMA LP nexprlist RP */ { - Select *pRight, *pLeft = yymsp[-4].minor.yy489; - pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy420,0,0,0,0,0,SF_Values|SF_MultiValue,0); + Select *pRight, *pLeft = yymsp[-4].minor.yy391; + pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy94,0,0,0,0,0,SF_Values|SF_MultiValue,0); if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; if( pRight ){ pRight->op = TK_ALL; pRight->pPrior = pLeft; - yymsp[-4].minor.yy489 = pRight; + yymsp[-4].minor.yy391 = pRight; }else{ - yymsp[-4].minor.yy489 = pLeft; + yymsp[-4].minor.yy391 = pLeft; } } break; - case 91: /* distinct ::= DISTINCT */ -{yymsp[0].minor.yy70 = SF_Distinct;} + case 92: /* distinct ::= DISTINCT */ +{yymsp[0].minor.yy100 = SF_Distinct;} break; - case 92: /* distinct ::= ALL */ -{yymsp[0].minor.yy70 = SF_All;} + case 93: /* distinct ::= ALL */ +{yymsp[0].minor.yy100 = SF_All;} break; - case 94: /* sclp ::= */ - case 127: /* orderby_opt ::= */ yytestcase(yyruleno==127); - case 134: /* groupby_opt ::= */ yytestcase(yyruleno==134); - case 214: /* exprlist ::= */ yytestcase(yyruleno==214); - case 217: /* paren_exprlist ::= */ yytestcase(yyruleno==217); - case 222: /* eidlist_opt ::= */ yytestcase(yyruleno==222); -{yymsp[1].minor.yy420 = 0;} + case 95: /* sclp ::= */ + case 128: /* orderby_opt ::= */ yytestcase(yyruleno==128); + case 135: /* groupby_opt ::= */ yytestcase(yyruleno==135); + case 215: /* exprlist ::= */ yytestcase(yyruleno==215); + case 218: /* paren_exprlist ::= */ yytestcase(yyruleno==218); + case 223: /* eidlist_opt ::= */ yytestcase(yyruleno==223); +{yymsp[1].minor.yy94 = 0;} break; - case 95: /* selcollist ::= sclp scanpt expr scanpt as */ + case 96: /* selcollist ::= sclp scanpt expr scanpt as */ { - yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy420, yymsp[-2].minor.yy18); - if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy420, &yymsp[0].minor.yy0, 1); - sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy420,yymsp[-3].minor.yy392,yymsp[-1].minor.yy392); + yymsp[-4].minor.yy94 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy94, yymsp[-2].minor.yy102); + if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy94, &yymsp[0].minor.yy0, 1); + sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy94,yymsp[-3].minor.yy528,yymsp[-1].minor.yy528); } break; - case 96: /* selcollist ::= sclp scanpt STAR */ + case 97: /* selcollist ::= sclp scanpt STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); - yymsp[-2].minor.yy420 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy420, p); + yymsp[-2].minor.yy94 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy94, p); } break; - case 97: /* selcollist ::= sclp scanpt nm DOT STAR */ + case 98: /* selcollist ::= sclp scanpt nm DOT STAR */ { Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); - yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy420, pDot); + yymsp[-4].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy94, pDot); } break; - case 98: /* as ::= AS nm */ - case 109: /* dbnm ::= DOT nm */ yytestcase(yyruleno==109); - case 236: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==236); - case 237: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==237); + case 99: /* as ::= AS nm */ + case 110: /* dbnm ::= DOT nm */ yytestcase(yyruleno==110); + case 239: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==239); + case 240: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==240); {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; - case 100: /* from ::= */ -{yymsp[1].minor.yy135 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy135));} + case 101: /* from ::= */ +{yymsp[1].minor.yy407 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy407));} break; - case 101: /* from ::= FROM seltablist */ + case 102: /* from ::= FROM seltablist */ { - yymsp[-1].minor.yy135 = yymsp[0].minor.yy135; - sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy135); + yymsp[-1].minor.yy407 = yymsp[0].minor.yy407; + sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy407); } break; - case 102: /* stl_prefix ::= seltablist joinop */ + case 103: /* stl_prefix ::= seltablist joinop */ { - if( ALWAYS(yymsp[-1].minor.yy135 && yymsp[-1].minor.yy135->nSrc>0) ) yymsp[-1].minor.yy135->a[yymsp[-1].minor.yy135->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy70; + if( ALWAYS(yymsp[-1].minor.yy407 && yymsp[-1].minor.yy407->nSrc>0) ) yymsp[-1].minor.yy407->a[yymsp[-1].minor.yy407->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy100; } break; - case 103: /* stl_prefix ::= */ -{yymsp[1].minor.yy135 = 0;} + case 104: /* stl_prefix ::= */ +{yymsp[1].minor.yy407 = 0;} break; - case 104: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + case 105: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ { - yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy18,yymsp[0].minor.yy48); - sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy135, &yymsp[-2].minor.yy0); + yymsp[-6].minor.yy407 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy407,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy102,yymsp[0].minor.yy76); + sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy407, &yymsp[-2].minor.yy0); } break; - case 105: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + case 106: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ { - yymsp[-8].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy135,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy18,yymsp[0].minor.yy48); - sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy135, yymsp[-4].minor.yy420); + yymsp[-8].minor.yy407 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy407,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy102,yymsp[0].minor.yy76); + sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy407, yymsp[-4].minor.yy94); } break; - case 106: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + case 107: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ { - yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy489,yymsp[-1].minor.yy18,yymsp[0].minor.yy48); + yymsp[-6].minor.yy407 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy407,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy391,yymsp[-1].minor.yy102,yymsp[0].minor.yy76); } break; - case 107: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + case 108: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ { - if( yymsp[-6].minor.yy135==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy18==0 && yymsp[0].minor.yy48==0 ){ - yymsp[-6].minor.yy135 = yymsp[-4].minor.yy135; - }else if( yymsp[-4].minor.yy135->nSrc==1 ){ - yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy18,yymsp[0].minor.yy48); - if( yymsp[-6].minor.yy135 ){ - struct SrcList_item *pNew = &yymsp[-6].minor.yy135->a[yymsp[-6].minor.yy135->nSrc-1]; - struct SrcList_item *pOld = yymsp[-4].minor.yy135->a; + if( yymsp[-6].minor.yy407==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy102==0 && yymsp[0].minor.yy76==0 ){ + yymsp[-6].minor.yy407 = yymsp[-4].minor.yy407; + }else if( yymsp[-4].minor.yy407->nSrc==1 ){ + yymsp[-6].minor.yy407 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy407,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy102,yymsp[0].minor.yy76); + if( yymsp[-6].minor.yy407 ){ + struct SrcList_item *pNew = &yymsp[-6].minor.yy407->a[yymsp[-6].minor.yy407->nSrc-1]; + struct SrcList_item *pOld = yymsp[-4].minor.yy407->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pNew->pSelect = pOld->pSelect; + if( pOld->fg.isTabFunc ){ + pNew->u1.pFuncArg = pOld->u1.pFuncArg; + pOld->u1.pFuncArg = 0; + pOld->fg.isTabFunc = 0; + pNew->fg.isTabFunc = 1; + } pOld->zName = pOld->zDatabase = 0; pOld->pSelect = 0; } - sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy135); + sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy407); }else{ Select *pSubquery; - sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy135); - pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy135,0,0,0,0,SF_NestedFrom,0); - yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy18,yymsp[0].minor.yy48); + sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy407); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy407,0,0,0,0,SF_NestedFrom,0); + yymsp[-6].minor.yy407 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy407,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy102,yymsp[0].minor.yy76); } } break; - case 108: /* dbnm ::= */ - case 122: /* indexed_opt ::= */ yytestcase(yyruleno==122); + case 109: /* dbnm ::= */ + case 123: /* indexed_opt ::= */ yytestcase(yyruleno==123); {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; - case 110: /* fullname ::= nm */ + case 111: /* fullname ::= nm */ { - yylhsminor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[0].minor.yy0,0); - if( IN_RENAME_OBJECT && yylhsminor.yy135 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy135->a[0].zName, &yymsp[0].minor.yy0); + yylhsminor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); + if( IN_RENAME_OBJECT && yylhsminor.yy407 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy407->a[0].zName, &yymsp[0].minor.yy0); } - yymsp[0].minor.yy135 = yylhsminor.yy135; + yymsp[0].minor.yy407 = yylhsminor.yy407; break; - case 111: /* fullname ::= nm DOT nm */ + case 112: /* fullname ::= nm DOT nm */ { - yylhsminor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); - if( IN_RENAME_OBJECT && yylhsminor.yy135 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy135->a[0].zName, &yymsp[0].minor.yy0); + yylhsminor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); + if( IN_RENAME_OBJECT && yylhsminor.yy407 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy407->a[0].zName, &yymsp[0].minor.yy0); } - yymsp[-2].minor.yy135 = yylhsminor.yy135; + yymsp[-2].minor.yy407 = yylhsminor.yy407; break; - case 112: /* xfullname ::= nm */ -{yymsp[0].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} + case 113: /* xfullname ::= nm */ +{yymsp[0].minor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} break; - case 113: /* xfullname ::= nm DOT nm */ -{yymsp[-2].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} + case 114: /* xfullname ::= nm DOT nm */ +{yymsp[-2].minor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 114: /* xfullname ::= nm DOT nm AS nm */ + case 115: /* xfullname ::= nm DOT nm AS nm */ { - yymsp[-4].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ - if( yymsp[-4].minor.yy135 ) yymsp[-4].minor.yy135->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + yymsp[-4].minor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ + if( yymsp[-4].minor.yy407 ) yymsp[-4].minor.yy407->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; - case 115: /* xfullname ::= nm AS nm */ + case 116: /* xfullname ::= nm AS nm */ { - yymsp[-2].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ - if( yymsp[-2].minor.yy135 ) yymsp[-2].minor.yy135->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + yymsp[-2].minor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ + if( yymsp[-2].minor.yy407 ) yymsp[-2].minor.yy407->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; - case 116: /* joinop ::= COMMA|JOIN */ -{ yymsp[0].minor.yy70 = JT_INNER; } + case 117: /* joinop ::= COMMA|JOIN */ +{ yymsp[0].minor.yy100 = JT_INNER; } break; - case 117: /* joinop ::= JOIN_KW JOIN */ -{yymsp[-1].minor.yy70 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} + case 118: /* joinop ::= JOIN_KW JOIN */ +{yymsp[-1].minor.yy100 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} break; - case 118: /* joinop ::= JOIN_KW nm JOIN */ -{yymsp[-2].minor.yy70 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} + case 119: /* joinop ::= JOIN_KW nm JOIN */ +{yymsp[-2].minor.yy100 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} break; - case 119: /* joinop ::= JOIN_KW nm nm JOIN */ -{yymsp[-3].minor.yy70 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} + case 120: /* joinop ::= JOIN_KW nm nm JOIN */ +{yymsp[-3].minor.yy100 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} break; - case 120: /* on_opt ::= ON expr */ - case 137: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==137); - case 144: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==144); - case 210: /* case_else ::= ELSE expr */ yytestcase(yyruleno==210); -{yymsp[-1].minor.yy18 = yymsp[0].minor.yy18;} + case 121: /* on_opt ::= ON expr */ + case 138: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==138); + case 145: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==145); + case 211: /* case_else ::= ELSE expr */ yytestcase(yyruleno==211); + case 232: /* vinto ::= INTO expr */ yytestcase(yyruleno==232); +{yymsp[-1].minor.yy102 = yymsp[0].minor.yy102;} break; - case 121: /* on_opt ::= */ - case 136: /* having_opt ::= */ yytestcase(yyruleno==136); - case 138: /* limit_opt ::= */ yytestcase(yyruleno==138); - case 143: /* where_opt ::= */ yytestcase(yyruleno==143); - case 211: /* case_else ::= */ yytestcase(yyruleno==211); - case 213: /* case_operand ::= */ yytestcase(yyruleno==213); -{yymsp[1].minor.yy18 = 0;} + case 122: /* on_opt ::= */ + case 137: /* having_opt ::= */ yytestcase(yyruleno==137); + case 139: /* limit_opt ::= */ yytestcase(yyruleno==139); + case 144: /* where_opt ::= */ yytestcase(yyruleno==144); + case 212: /* case_else ::= */ yytestcase(yyruleno==212); + case 214: /* case_operand ::= */ yytestcase(yyruleno==214); + case 233: /* vinto ::= */ yytestcase(yyruleno==233); +{yymsp[1].minor.yy102 = 0;} break; - case 123: /* indexed_opt ::= INDEXED BY nm */ + case 124: /* indexed_opt ::= INDEXED BY nm */ {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} break; - case 124: /* indexed_opt ::= NOT INDEXED */ + case 125: /* indexed_opt ::= NOT INDEXED */ {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} break; - case 125: /* using_opt ::= USING LP idlist RP */ -{yymsp[-3].minor.yy48 = yymsp[-1].minor.yy48;} + case 126: /* using_opt ::= USING LP idlist RP */ +{yymsp[-3].minor.yy76 = yymsp[-1].minor.yy76;} break; - case 126: /* using_opt ::= */ - case 158: /* idlist_opt ::= */ yytestcase(yyruleno==158); -{yymsp[1].minor.yy48 = 0;} + case 127: /* using_opt ::= */ + case 159: /* idlist_opt ::= */ yytestcase(yyruleno==159); +{yymsp[1].minor.yy76 = 0;} break; - case 128: /* orderby_opt ::= ORDER BY sortlist */ - case 135: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==135); -{yymsp[-2].minor.yy420 = yymsp[0].minor.yy420;} + case 129: /* orderby_opt ::= ORDER BY sortlist */ + case 136: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==136); +{yymsp[-2].minor.yy94 = yymsp[0].minor.yy94;} break; - case 129: /* sortlist ::= sortlist COMMA expr sortorder */ + case 130: /* sortlist ::= sortlist COMMA expr sortorder */ { - yymsp[-3].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy420,yymsp[-1].minor.yy18); - sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy420,yymsp[0].minor.yy70); + yymsp[-3].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy94,yymsp[-1].minor.yy102); + sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy94,yymsp[0].minor.yy100); } break; - case 130: /* sortlist ::= expr sortorder */ + case 131: /* sortlist ::= expr sortorder */ { - yymsp[-1].minor.yy420 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy18); /*A-overwrites-Y*/ - sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy420,yymsp[0].minor.yy70); + yymsp[-1].minor.yy94 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy102); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy94,yymsp[0].minor.yy100); } break; - case 131: /* sortorder ::= ASC */ -{yymsp[0].minor.yy70 = SQLITE_SO_ASC;} + case 132: /* sortorder ::= ASC */ +{yymsp[0].minor.yy100 = SQLITE_SO_ASC;} break; - case 132: /* sortorder ::= DESC */ -{yymsp[0].minor.yy70 = SQLITE_SO_DESC;} + case 133: /* sortorder ::= DESC */ +{yymsp[0].minor.yy100 = SQLITE_SO_DESC;} break; - case 133: /* sortorder ::= */ -{yymsp[1].minor.yy70 = SQLITE_SO_UNDEFINED;} + case 134: /* sortorder ::= */ +{yymsp[1].minor.yy100 = SQLITE_SO_UNDEFINED;} break; - case 139: /* limit_opt ::= LIMIT expr */ -{yymsp[-1].minor.yy18 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy18,0);} + case 140: /* limit_opt ::= LIMIT expr */ +{yymsp[-1].minor.yy102 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy102,0);} break; - case 140: /* limit_opt ::= LIMIT expr OFFSET expr */ -{yymsp[-3].minor.yy18 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy18,yymsp[0].minor.yy18);} + case 141: /* limit_opt ::= LIMIT expr OFFSET expr */ +{yymsp[-3].minor.yy102 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy102,yymsp[0].minor.yy102);} break; - case 141: /* limit_opt ::= LIMIT expr COMMA expr */ -{yymsp[-3].minor.yy18 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy18,yymsp[-2].minor.yy18);} + case 142: /* limit_opt ::= LIMIT expr COMMA expr */ +{yymsp[-3].minor.yy102 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy102,yymsp[-2].minor.yy102);} break; - case 142: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ + case 143: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ { - sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy135, &yymsp[-1].minor.yy0); - sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy135,yymsp[0].minor.yy18,0,0); + sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy407, &yymsp[-1].minor.yy0); + sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy407,yymsp[0].minor.yy102,0,0); } break; - case 145: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ + case 146: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ { - sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy135, &yymsp[-3].minor.yy0); - sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy420,"set list"); - sqlite3Update(pParse,yymsp[-4].minor.yy135,yymsp[-1].minor.yy420,yymsp[0].minor.yy18,yymsp[-5].minor.yy70,0,0,0); + sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy407, &yymsp[-3].minor.yy0); + sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy94,"set list"); + sqlite3Update(pParse,yymsp[-4].minor.yy407,yymsp[-1].minor.yy94,yymsp[0].minor.yy102,yymsp[-5].minor.yy100,0,0,0); } break; - case 146: /* setlist ::= setlist COMMA nm EQ expr */ + case 147: /* setlist ::= setlist COMMA nm EQ expr */ { - yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy420, yymsp[0].minor.yy18); - sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy420, &yymsp[-2].minor.yy0, 1); + yymsp[-4].minor.yy94 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy94, yymsp[0].minor.yy102); + sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy94, &yymsp[-2].minor.yy0, 1); } break; - case 147: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ + case 148: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { - yymsp[-6].minor.yy420 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy420, yymsp[-3].minor.yy48, yymsp[0].minor.yy18); + yymsp[-6].minor.yy94 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy94, yymsp[-3].minor.yy76, yymsp[0].minor.yy102); } break; - case 148: /* setlist ::= nm EQ expr */ + case 149: /* setlist ::= nm EQ expr */ { - yylhsminor.yy420 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy18); - sqlite3ExprListSetName(pParse, yylhsminor.yy420, &yymsp[-2].minor.yy0, 1); + yylhsminor.yy94 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy102); + sqlite3ExprListSetName(pParse, yylhsminor.yy94, &yymsp[-2].minor.yy0, 1); } - yymsp[-2].minor.yy420 = yylhsminor.yy420; + yymsp[-2].minor.yy94 = yylhsminor.yy94; break; - case 149: /* setlist ::= LP idlist RP EQ expr */ + case 150: /* setlist ::= LP idlist RP EQ expr */ { - yymsp[-4].minor.yy420 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy48, yymsp[0].minor.yy18); + yymsp[-4].minor.yy94 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy76, yymsp[0].minor.yy102); } break; - case 150: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + case 151: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ { - sqlite3Insert(pParse, yymsp[-3].minor.yy135, yymsp[-1].minor.yy489, yymsp[-2].minor.yy48, yymsp[-5].minor.yy70, yymsp[0].minor.yy340); + sqlite3Insert(pParse, yymsp[-3].minor.yy407, yymsp[-1].minor.yy391, yymsp[-2].minor.yy76, yymsp[-5].minor.yy100, yymsp[0].minor.yy95); } break; - case 151: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ + case 152: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ { - sqlite3Insert(pParse, yymsp[-3].minor.yy135, 0, yymsp[-2].minor.yy48, yymsp[-5].minor.yy70, 0); + sqlite3Insert(pParse, yymsp[-3].minor.yy407, 0, yymsp[-2].minor.yy76, yymsp[-5].minor.yy100, 0); } break; - case 152: /* upsert ::= */ -{ yymsp[1].minor.yy340 = 0; } + case 153: /* upsert ::= */ +{ yymsp[1].minor.yy95 = 0; } break; - case 153: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ -{ yymsp[-10].minor.yy340 = sqlite3UpsertNew(pParse->db,yymsp[-7].minor.yy420,yymsp[-5].minor.yy18,yymsp[-1].minor.yy420,yymsp[0].minor.yy18);} + case 154: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ +{ yymsp[-10].minor.yy95 = sqlite3UpsertNew(pParse->db,yymsp[-7].minor.yy94,yymsp[-5].minor.yy102,yymsp[-1].minor.yy94,yymsp[0].minor.yy102);} break; - case 154: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ -{ yymsp[-7].minor.yy340 = sqlite3UpsertNew(pParse->db,yymsp[-4].minor.yy420,yymsp[-2].minor.yy18,0,0); } + case 155: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ +{ yymsp[-7].minor.yy95 = sqlite3UpsertNew(pParse->db,yymsp[-4].minor.yy94,yymsp[-2].minor.yy102,0,0); } break; - case 155: /* upsert ::= ON CONFLICT DO NOTHING */ -{ yymsp[-3].minor.yy340 = sqlite3UpsertNew(pParse->db,0,0,0,0); } + case 156: /* upsert ::= ON CONFLICT DO NOTHING */ +{ yymsp[-3].minor.yy95 = sqlite3UpsertNew(pParse->db,0,0,0,0); } break; - case 159: /* idlist_opt ::= LP idlist RP */ -{yymsp[-2].minor.yy48 = yymsp[-1].minor.yy48;} + case 160: /* idlist_opt ::= LP idlist RP */ +{yymsp[-2].minor.yy76 = yymsp[-1].minor.yy76;} break; - case 160: /* idlist ::= idlist COMMA nm */ -{yymsp[-2].minor.yy48 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy48,&yymsp[0].minor.yy0);} + case 161: /* idlist ::= idlist COMMA nm */ +{yymsp[-2].minor.yy76 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy76,&yymsp[0].minor.yy0);} break; - case 161: /* idlist ::= nm */ -{yymsp[0].minor.yy48 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} + case 162: /* idlist ::= nm */ +{yymsp[0].minor.yy76 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} break; - case 162: /* expr ::= LP expr RP */ -{yymsp[-2].minor.yy18 = yymsp[-1].minor.yy18;} + case 163: /* expr ::= LP expr RP */ +{yymsp[-2].minor.yy102 = yymsp[-1].minor.yy102;} break; - case 163: /* expr ::= ID|INDEXED */ - case 164: /* expr ::= JOIN_KW */ yytestcase(yyruleno==164); -{yymsp[0].minor.yy18=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} + case 164: /* expr ::= ID|INDEXED */ + case 165: /* expr ::= JOIN_KW */ yytestcase(yyruleno==165); +{yymsp[0].minor.yy102=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 165: /* expr ::= nm DOT nm */ + case 166: /* expr ::= nm DOT nm */ { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); @@ -149300,11 +152563,11 @@ static YYACTIONTYPE yy_reduce( sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[0].minor.yy0); sqlite3RenameTokenMap(pParse, (void*)temp1, &yymsp[-2].minor.yy0); } - yylhsminor.yy18 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); + yylhsminor.yy102 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } - yymsp[-2].minor.yy18 = yylhsminor.yy18; + yymsp[-2].minor.yy102 = yylhsminor.yy102; break; - case 166: /* expr ::= nm DOT nm DOT nm */ + case 167: /* expr ::= nm DOT nm DOT nm */ { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); @@ -149314,26 +152577,26 @@ static YYACTIONTYPE yy_reduce( sqlite3RenameTokenMap(pParse, (void*)temp3, &yymsp[0].minor.yy0); sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[-2].minor.yy0); } - yylhsminor.yy18 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); + yylhsminor.yy102 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); } - yymsp[-4].minor.yy18 = yylhsminor.yy18; + yymsp[-4].minor.yy102 = yylhsminor.yy102; break; - case 167: /* term ::= NULL|FLOAT|BLOB */ - case 168: /* term ::= STRING */ yytestcase(yyruleno==168); -{yymsp[0].minor.yy18=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} + case 168: /* term ::= NULL|FLOAT|BLOB */ + case 169: /* term ::= STRING */ yytestcase(yyruleno==169); +{yymsp[0].minor.yy102=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 169: /* term ::= INTEGER */ + case 170: /* term ::= INTEGER */ { - yylhsminor.yy18 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); + yylhsminor.yy102 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); } - yymsp[0].minor.yy18 = yylhsminor.yy18; + yymsp[0].minor.yy102 = yylhsminor.yy102; break; - case 170: /* expr ::= VARIABLE */ + case 171: /* expr ::= VARIABLE */ { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ u32 n = yymsp[0].minor.yy0.n; - yymsp[0].minor.yy18 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); - sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy18, n); + yymsp[0].minor.yy102 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); + sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy102, n); }else{ /* When doing a nested parse, one can include terms in an expression ** that look like this: #1 #2 ... These terms refer to registers @@ -149342,154 +152605,156 @@ static YYACTIONTYPE yy_reduce( assert( t.n>=2 ); if( pParse->nested==0 ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); - yymsp[0].minor.yy18 = 0; + yymsp[0].minor.yy102 = 0; }else{ - yymsp[0].minor.yy18 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); - if( yymsp[0].minor.yy18 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy18->iTable); + yymsp[0].minor.yy102 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); + if( yymsp[0].minor.yy102 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy102->iTable); } } } break; - case 171: /* expr ::= expr COLLATE ID|STRING */ + case 172: /* expr ::= expr COLLATE ID|STRING */ { - yymsp[-2].minor.yy18 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy18, &yymsp[0].minor.yy0, 1); + yymsp[-2].minor.yy102 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy102, &yymsp[0].minor.yy0, 1); } break; - case 172: /* expr ::= CAST LP expr AS typetoken RP */ + case 173: /* expr ::= CAST LP expr AS typetoken RP */ { - yymsp[-5].minor.yy18 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); - sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy18, yymsp[-3].minor.yy18, 0); + yymsp[-5].minor.yy102 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); + sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy102, yymsp[-3].minor.yy102, 0); } break; - case 173: /* expr ::= ID|INDEXED LP distinct exprlist RP */ + case 174: /* expr ::= ID|INDEXED LP distinct exprlist RP */ { - yylhsminor.yy18 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy420, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy70); + yylhsminor.yy102 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy94, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy100); } - yymsp[-4].minor.yy18 = yylhsminor.yy18; + yymsp[-4].minor.yy102 = yylhsminor.yy102; break; - case 174: /* expr ::= ID|INDEXED LP STAR RP */ + case 175: /* expr ::= ID|INDEXED LP STAR RP */ { - yylhsminor.yy18 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); + yylhsminor.yy102 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); } - yymsp[-3].minor.yy18 = yylhsminor.yy18; + yymsp[-3].minor.yy102 = yylhsminor.yy102; break; - case 175: /* expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ + case 176: /* expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ { - yylhsminor.yy18 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy420, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy70); - sqlite3WindowAttach(pParse, yylhsminor.yy18, yymsp[0].minor.yy327); + yylhsminor.yy102 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy94, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy100); + sqlite3WindowAttach(pParse, yylhsminor.yy102, yymsp[0].minor.yy379); } - yymsp[-5].minor.yy18 = yylhsminor.yy18; + yymsp[-5].minor.yy102 = yylhsminor.yy102; break; - case 176: /* expr ::= ID|INDEXED LP STAR RP over_clause */ + case 177: /* expr ::= ID|INDEXED LP STAR RP over_clause */ { - yylhsminor.yy18 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); - sqlite3WindowAttach(pParse, yylhsminor.yy18, yymsp[0].minor.yy327); + yylhsminor.yy102 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); + sqlite3WindowAttach(pParse, yylhsminor.yy102, yymsp[0].minor.yy379); } - yymsp[-4].minor.yy18 = yylhsminor.yy18; + yymsp[-4].minor.yy102 = yylhsminor.yy102; break; - case 177: /* term ::= CTIME_KW */ + case 178: /* term ::= CTIME_KW */ { - yylhsminor.yy18 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); + yylhsminor.yy102 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); } - yymsp[0].minor.yy18 = yylhsminor.yy18; + yymsp[0].minor.yy102 = yylhsminor.yy102; break; - case 178: /* expr ::= LP nexprlist COMMA expr RP */ + case 179: /* expr ::= LP nexprlist COMMA expr RP */ { - ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy420, yymsp[-1].minor.yy18); - yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); - if( yymsp[-4].minor.yy18 ){ - yymsp[-4].minor.yy18->x.pList = pList; + ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy94, yymsp[-1].minor.yy102); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); + if( yymsp[-4].minor.yy102 ){ + yymsp[-4].minor.yy102->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } } break; - case 179: /* expr ::= expr AND expr */ - case 180: /* expr ::= expr OR expr */ yytestcase(yyruleno==180); - case 181: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==181); - case 182: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==182); - case 183: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==183); - case 184: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==184); - case 185: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==185); - case 186: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==186); -{yymsp[-2].minor.yy18=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy18,yymsp[0].minor.yy18);} + case 180: /* expr ::= expr AND expr */ +{yymsp[-2].minor.yy102=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy102,yymsp[0].minor.yy102);} + break; + case 181: /* expr ::= expr OR expr */ + case 182: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==182); + case 183: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==183); + case 184: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==184); + case 185: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==185); + case 186: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==186); + case 187: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==187); +{yymsp[-2].minor.yy102=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy102,yymsp[0].minor.yy102);} break; - case 187: /* likeop ::= NOT LIKE_KW|MATCH */ + case 188: /* likeop ::= NOT LIKE_KW|MATCH */ {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} break; - case 188: /* expr ::= expr likeop expr */ + case 189: /* expr ::= expr likeop expr */ { ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; yymsp[-1].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy18); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy18); - yymsp[-2].minor.yy18 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); - if( bNot ) yymsp[-2].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy18, 0); - if( yymsp[-2].minor.yy18 ) yymsp[-2].minor.yy18->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy102); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy102); + yymsp[-2].minor.yy102 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); + if( bNot ) yymsp[-2].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy102, 0); + if( yymsp[-2].minor.yy102 ) yymsp[-2].minor.yy102->flags |= EP_InfixFunc; } break; - case 189: /* expr ::= expr likeop expr ESCAPE expr */ + case 190: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; yymsp[-3].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy18); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy18); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy18); - yymsp[-4].minor.yy18 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); - if( bNot ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0); - if( yymsp[-4].minor.yy18 ) yymsp[-4].minor.yy18->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy102); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy102); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy102); + yymsp[-4].minor.yy102 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); + if( bNot ) yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy102, 0); + if( yymsp[-4].minor.yy102 ) yymsp[-4].minor.yy102->flags |= EP_InfixFunc; } break; - case 190: /* expr ::= expr ISNULL|NOTNULL */ -{yymsp[-1].minor.yy18 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy18,0);} + case 191: /* expr ::= expr ISNULL|NOTNULL */ +{yymsp[-1].minor.yy102 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy102,0);} break; - case 191: /* expr ::= expr NOT NULL */ -{yymsp[-2].minor.yy18 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy18,0);} + case 192: /* expr ::= expr NOT NULL */ +{yymsp[-2].minor.yy102 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy102,0);} break; - case 192: /* expr ::= expr IS expr */ + case 193: /* expr ::= expr IS expr */ { - yymsp[-2].minor.yy18 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy18,yymsp[0].minor.yy18); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy18, yymsp[-2].minor.yy18, TK_ISNULL); + yymsp[-2].minor.yy102 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy102,yymsp[0].minor.yy102); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy102, yymsp[-2].minor.yy102, TK_ISNULL); } break; - case 193: /* expr ::= expr IS NOT expr */ + case 194: /* expr ::= expr IS NOT expr */ { - yymsp[-3].minor.yy18 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy18,yymsp[0].minor.yy18); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy18, yymsp[-3].minor.yy18, TK_NOTNULL); + yymsp[-3].minor.yy102 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy102,yymsp[0].minor.yy102); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy102, yymsp[-3].minor.yy102, TK_NOTNULL); } break; - case 194: /* expr ::= NOT expr */ - case 195: /* expr ::= BITNOT expr */ yytestcase(yyruleno==195); -{yymsp[-1].minor.yy18 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy18, 0);/*A-overwrites-B*/} + case 195: /* expr ::= NOT expr */ + case 196: /* expr ::= BITNOT expr */ yytestcase(yyruleno==196); +{yymsp[-1].minor.yy102 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy102, 0);/*A-overwrites-B*/} break; - case 196: /* expr ::= PLUS|MINUS expr */ + case 197: /* expr ::= PLUS|MINUS expr */ { - yymsp[-1].minor.yy18 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy18, 0); + yymsp[-1].minor.yy102 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy102, 0); /*A-overwrites-B*/ } break; - case 197: /* between_op ::= BETWEEN */ - case 200: /* in_op ::= IN */ yytestcase(yyruleno==200); -{yymsp[0].minor.yy70 = 0;} + case 198: /* between_op ::= BETWEEN */ + case 201: /* in_op ::= IN */ yytestcase(yyruleno==201); +{yymsp[0].minor.yy100 = 0;} break; - case 199: /* expr ::= expr between_op expr AND expr */ + case 200: /* expr ::= expr between_op expr AND expr */ { - ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy18); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy18); - yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy18, 0); - if( yymsp[-4].minor.yy18 ){ - yymsp[-4].minor.yy18->x.pList = pList; + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy102); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy102); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy102, 0); + if( yymsp[-4].minor.yy102 ){ + yymsp[-4].minor.yy102->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } - if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0); + if( yymsp[-3].minor.yy100 ) yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy102, 0); } break; - case 202: /* expr ::= expr in_op LP exprlist RP */ + case 203: /* expr ::= expr in_op LP exprlist RP */ { - if( yymsp[-1].minor.yy420==0 ){ + if( yymsp[-1].minor.yy94==0 ){ /* Expressions of the form ** ** expr1 IN () @@ -149498,9 +152763,9 @@ static YYACTIONTYPE yy_reduce( ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ - sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy18); - yymsp[-4].minor.yy18 = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy70],1); - }else if( yymsp[-1].minor.yy420->nExpr==1 ){ + sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy102); + yymsp[-4].minor.yy102 = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy100],1); + }else if( yymsp[-1].minor.yy94->nExpr==1 ){ /* Expressions of the form: ** ** expr1 IN (?1) @@ -149517,199 +152782,199 @@ static YYACTIONTYPE yy_reduce( ** affinity or the collating sequence to use for comparison. Otherwise, ** the semantics would be subtly different from IN or NOT IN. */ - Expr *pRHS = yymsp[-1].minor.yy420->a[0].pExpr; - yymsp[-1].minor.yy420->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy420); + Expr *pRHS = yymsp[-1].minor.yy94->a[0].pExpr; + yymsp[-1].minor.yy94->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy94); /* pRHS cannot be NULL because a malloc error would have been detected ** before now and control would have never reached this point */ if( ALWAYS(pRHS) ){ pRHS->flags &= ~EP_Collate; pRHS->flags |= EP_Generic; } - yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, yymsp[-3].minor.yy70 ? TK_NE : TK_EQ, yymsp[-4].minor.yy18, pRHS); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, yymsp[-3].minor.yy100 ? TK_NE : TK_EQ, yymsp[-4].minor.yy102, pRHS); }else{ - yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy18, 0); - if( yymsp[-4].minor.yy18 ){ - yymsp[-4].minor.yy18->x.pList = yymsp[-1].minor.yy420; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy18); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy102, 0); + if( yymsp[-4].minor.yy102 ){ + yymsp[-4].minor.yy102->x.pList = yymsp[-1].minor.yy94; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy102); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy420); + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy94); } - if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0); + if( yymsp[-3].minor.yy100 ) yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy102, 0); } } break; - case 203: /* expr ::= LP select RP */ + case 204: /* expr ::= LP select RP */ { - yymsp[-2].minor.yy18 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); - sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy18, yymsp[-1].minor.yy489); + yymsp[-2].minor.yy102 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy102, yymsp[-1].minor.yy391); } break; - case 204: /* expr ::= expr in_op LP select RP */ + case 205: /* expr ::= expr in_op LP select RP */ { - yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy18, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy18, yymsp[-1].minor.yy489); - if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy102, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy102, yymsp[-1].minor.yy391); + if( yymsp[-3].minor.yy100 ) yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy102, 0); } break; - case 205: /* expr ::= expr in_op nm dbnm paren_exprlist */ + case 206: /* expr ::= expr in_op nm dbnm paren_exprlist */ { - SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); + SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); - if( yymsp[0].minor.yy420 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy420); - yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy18, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy18, pSelect); - if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0); + if( yymsp[0].minor.yy94 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy94); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy102, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy102, pSelect); + if( yymsp[-3].minor.yy100 ) yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy102, 0); } break; - case 206: /* expr ::= EXISTS LP select RP */ + case 207: /* expr ::= EXISTS LP select RP */ { Expr *p; - p = yymsp[-3].minor.yy18 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); - sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy489); + p = yymsp[-3].minor.yy102 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); + sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy391); } break; - case 207: /* expr ::= CASE case_operand case_exprlist case_else END */ + case 208: /* expr ::= CASE case_operand case_exprlist case_else END */ { - yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy18, 0); - if( yymsp[-4].minor.yy18 ){ - yymsp[-4].minor.yy18->x.pList = yymsp[-1].minor.yy18 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy420,yymsp[-1].minor.yy18) : yymsp[-2].minor.yy420; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy18); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy102, 0); + if( yymsp[-4].minor.yy102 ){ + yymsp[-4].minor.yy102->x.pList = yymsp[-1].minor.yy102 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy94,yymsp[-1].minor.yy102) : yymsp[-2].minor.yy94; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy102); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy420); - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy18); + sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy94); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy102); } } break; - case 208: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ + case 209: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { - yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy420, yymsp[-2].minor.yy18); - yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy420, yymsp[0].minor.yy18); + yymsp[-4].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy94, yymsp[-2].minor.yy102); + yymsp[-4].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy94, yymsp[0].minor.yy102); } break; - case 209: /* case_exprlist ::= WHEN expr THEN expr */ + case 210: /* case_exprlist ::= WHEN expr THEN expr */ { - yymsp[-3].minor.yy420 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy18); - yymsp[-3].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy420, yymsp[0].minor.yy18); + yymsp[-3].minor.yy94 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy102); + yymsp[-3].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy94, yymsp[0].minor.yy102); } break; - case 212: /* case_operand ::= expr */ -{yymsp[0].minor.yy18 = yymsp[0].minor.yy18; /*A-overwrites-X*/} + case 213: /* case_operand ::= expr */ +{yymsp[0].minor.yy102 = yymsp[0].minor.yy102; /*A-overwrites-X*/} break; - case 215: /* nexprlist ::= nexprlist COMMA expr */ -{yymsp[-2].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy420,yymsp[0].minor.yy18);} + case 216: /* nexprlist ::= nexprlist COMMA expr */ +{yymsp[-2].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy94,yymsp[0].minor.yy102);} break; - case 216: /* nexprlist ::= expr */ -{yymsp[0].minor.yy420 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy18); /*A-overwrites-Y*/} + case 217: /* nexprlist ::= expr */ +{yymsp[0].minor.yy94 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy102); /*A-overwrites-Y*/} break; - case 218: /* paren_exprlist ::= LP exprlist RP */ - case 223: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==223); -{yymsp[-2].minor.yy420 = yymsp[-1].minor.yy420;} + case 219: /* paren_exprlist ::= LP exprlist RP */ + case 224: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==224); +{yymsp[-2].minor.yy94 = yymsp[-1].minor.yy94;} break; - case 219: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + case 220: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, - sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy420, yymsp[-10].minor.yy70, - &yymsp[-11].minor.yy0, yymsp[0].minor.yy18, SQLITE_SO_ASC, yymsp[-8].minor.yy70, SQLITE_IDXTYPE_APPDEF); + sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy94, yymsp[-10].minor.yy100, + &yymsp[-11].minor.yy0, yymsp[0].minor.yy102, SQLITE_SO_ASC, yymsp[-8].minor.yy100, SQLITE_IDXTYPE_APPDEF); if( IN_RENAME_OBJECT && pParse->pNewIndex ){ sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0); } } break; - case 220: /* uniqueflag ::= UNIQUE */ - case 260: /* raisetype ::= ABORT */ yytestcase(yyruleno==260); -{yymsp[0].minor.yy70 = OE_Abort;} + case 221: /* uniqueflag ::= UNIQUE */ + case 263: /* raisetype ::= ABORT */ yytestcase(yyruleno==263); +{yymsp[0].minor.yy100 = OE_Abort;} break; - case 221: /* uniqueflag ::= */ -{yymsp[1].minor.yy70 = OE_None;} + case 222: /* uniqueflag ::= */ +{yymsp[1].minor.yy100 = OE_None;} break; - case 224: /* eidlist ::= eidlist COMMA nm collate sortorder */ + case 225: /* eidlist ::= eidlist COMMA nm collate sortorder */ { - yymsp[-4].minor.yy420 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy420, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy70, yymsp[0].minor.yy70); + yymsp[-4].minor.yy94 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy94, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy100, yymsp[0].minor.yy100); } break; - case 225: /* eidlist ::= nm collate sortorder */ + case 226: /* eidlist ::= nm collate sortorder */ { - yymsp[-2].minor.yy420 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy70, yymsp[0].minor.yy70); /*A-overwrites-Y*/ + yymsp[-2].minor.yy94 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy100, yymsp[0].minor.yy100); /*A-overwrites-Y*/ } break; - case 228: /* cmd ::= DROP INDEX ifexists fullname */ -{sqlite3DropIndex(pParse, yymsp[0].minor.yy135, yymsp[-1].minor.yy70);} + case 229: /* cmd ::= DROP INDEX ifexists fullname */ +{sqlite3DropIndex(pParse, yymsp[0].minor.yy407, yymsp[-1].minor.yy100);} break; - case 229: /* cmd ::= VACUUM */ -{sqlite3Vacuum(pParse,0);} + case 230: /* cmd ::= VACUUM vinto */ +{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy102);} break; - case 230: /* cmd ::= VACUUM nm */ -{sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);} + case 231: /* cmd ::= VACUUM nm vinto */ +{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy102);} break; - case 231: /* cmd ::= PRAGMA nm dbnm */ + case 234: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; - case 232: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 235: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; - case 233: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 236: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; - case 234: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ + case 237: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; - case 235: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ + case 238: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} break; - case 238: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + case 241: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ { Token all; all.z = yymsp[-3].minor.yy0.z; all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; - sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy207, &all); + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy11, &all); } break; - case 239: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + case 242: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { - sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy70, yymsp[-4].minor.yy34.a, yymsp[-4].minor.yy34.b, yymsp[-2].minor.yy135, yymsp[0].minor.yy18, yymsp[-10].minor.yy70, yymsp[-8].minor.yy70); + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy100, yymsp[-4].minor.yy298.a, yymsp[-4].minor.yy298.b, yymsp[-2].minor.yy407, yymsp[0].minor.yy102, yymsp[-10].minor.yy100, yymsp[-8].minor.yy100); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; - case 240: /* trigger_time ::= BEFORE|AFTER */ -{ yymsp[0].minor.yy70 = yymsp[0].major; /*A-overwrites-X*/ } + case 243: /* trigger_time ::= BEFORE|AFTER */ +{ yymsp[0].minor.yy100 = yymsp[0].major; /*A-overwrites-X*/ } break; - case 241: /* trigger_time ::= INSTEAD OF */ -{ yymsp[-1].minor.yy70 = TK_INSTEAD;} + case 244: /* trigger_time ::= INSTEAD OF */ +{ yymsp[-1].minor.yy100 = TK_INSTEAD;} break; - case 242: /* trigger_time ::= */ -{ yymsp[1].minor.yy70 = TK_BEFORE; } + case 245: /* trigger_time ::= */ +{ yymsp[1].minor.yy100 = TK_BEFORE; } break; - case 243: /* trigger_event ::= DELETE|INSERT */ - case 244: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==244); -{yymsp[0].minor.yy34.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy34.b = 0;} + case 246: /* trigger_event ::= DELETE|INSERT */ + case 247: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==247); +{yymsp[0].minor.yy298.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy298.b = 0;} break; - case 245: /* trigger_event ::= UPDATE OF idlist */ -{yymsp[-2].minor.yy34.a = TK_UPDATE; yymsp[-2].minor.yy34.b = yymsp[0].minor.yy48;} + case 248: /* trigger_event ::= UPDATE OF idlist */ +{yymsp[-2].minor.yy298.a = TK_UPDATE; yymsp[-2].minor.yy298.b = yymsp[0].minor.yy76;} break; - case 246: /* when_clause ::= */ - case 265: /* key_opt ::= */ yytestcase(yyruleno==265); - case 307: /* filter_opt ::= */ yytestcase(yyruleno==307); -{ yymsp[1].minor.yy18 = 0; } + case 249: /* when_clause ::= */ + case 268: /* key_opt ::= */ yytestcase(yyruleno==268); + case 316: /* filter_opt ::= */ yytestcase(yyruleno==316); +{ yymsp[1].minor.yy102 = 0; } break; - case 247: /* when_clause ::= WHEN expr */ - case 266: /* key_opt ::= KEY expr */ yytestcase(yyruleno==266); -{ yymsp[-1].minor.yy18 = yymsp[0].minor.yy18; } + case 250: /* when_clause ::= WHEN expr */ + case 269: /* key_opt ::= KEY expr */ yytestcase(yyruleno==269); +{ yymsp[-1].minor.yy102 = yymsp[0].minor.yy102; } break; - case 248: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + case 251: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { - assert( yymsp[-2].minor.yy207!=0 ); - yymsp[-2].minor.yy207->pLast->pNext = yymsp[-1].minor.yy207; - yymsp[-2].minor.yy207->pLast = yymsp[-1].minor.yy207; + assert( yymsp[-2].minor.yy11!=0 ); + yymsp[-2].minor.yy11->pLast->pNext = yymsp[-1].minor.yy11; + yymsp[-2].minor.yy11->pLast = yymsp[-1].minor.yy11; } break; - case 249: /* trigger_cmd_list ::= trigger_cmd SEMI */ + case 252: /* trigger_cmd_list ::= trigger_cmd SEMI */ { - assert( yymsp[-1].minor.yy207!=0 ); - yymsp[-1].minor.yy207->pLast = yymsp[-1].minor.yy207; + assert( yymsp[-1].minor.yy11!=0 ); + yymsp[-1].minor.yy11->pLast = yymsp[-1].minor.yy11; } break; - case 250: /* trnm ::= nm DOT nm */ + case 253: /* trnm ::= nm DOT nm */ { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, @@ -149717,312 +152982,334 @@ static YYACTIONTYPE yy_reduce( "statements within triggers"); } break; - case 251: /* tridxby ::= INDEXED BY nm */ + case 254: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 252: /* tridxby ::= NOT INDEXED */ + case 255: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 253: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ -{yylhsminor.yy207 = sqlite3TriggerUpdateStep(pParse, &yymsp[-5].minor.yy0, yymsp[-2].minor.yy420, yymsp[-1].minor.yy18, yymsp[-6].minor.yy70, yymsp[-7].minor.yy0.z, yymsp[0].minor.yy392);} - yymsp[-7].minor.yy207 = yylhsminor.yy207; + case 256: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ +{yylhsminor.yy11 = sqlite3TriggerUpdateStep(pParse, &yymsp[-5].minor.yy0, yymsp[-2].minor.yy94, yymsp[-1].minor.yy102, yymsp[-6].minor.yy100, yymsp[-7].minor.yy0.z, yymsp[0].minor.yy528);} + yymsp[-7].minor.yy11 = yylhsminor.yy11; break; - case 254: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + case 257: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ { - yylhsminor.yy207 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy48,yymsp[-2].minor.yy489,yymsp[-6].minor.yy70,yymsp[-1].minor.yy340,yymsp[-7].minor.yy392,yymsp[0].minor.yy392);/*yylhsminor.yy207-overwrites-yymsp[-6].minor.yy70*/ + yylhsminor.yy11 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy76,yymsp[-2].minor.yy391,yymsp[-6].minor.yy100,yymsp[-1].minor.yy95,yymsp[-7].minor.yy528,yymsp[0].minor.yy528);/*yylhsminor.yy11-overwrites-yymsp[-6].minor.yy100*/ } - yymsp[-7].minor.yy207 = yylhsminor.yy207; + yymsp[-7].minor.yy11 = yylhsminor.yy11; break; - case 255: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ -{yylhsminor.yy207 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy18, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy392);} - yymsp[-5].minor.yy207 = yylhsminor.yy207; + case 258: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ +{yylhsminor.yy11 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy102, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy528);} + yymsp[-5].minor.yy11 = yylhsminor.yy11; break; - case 256: /* trigger_cmd ::= scanpt select scanpt */ -{yylhsminor.yy207 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy489, yymsp[-2].minor.yy392, yymsp[0].minor.yy392); /*yylhsminor.yy207-overwrites-yymsp[-1].minor.yy489*/} - yymsp[-2].minor.yy207 = yylhsminor.yy207; + case 259: /* trigger_cmd ::= scanpt select scanpt */ +{yylhsminor.yy11 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy391, yymsp[-2].minor.yy528, yymsp[0].minor.yy528); /*yylhsminor.yy11-overwrites-yymsp[-1].minor.yy391*/} + yymsp[-2].minor.yy11 = yylhsminor.yy11; break; - case 257: /* expr ::= RAISE LP IGNORE RP */ + case 260: /* expr ::= RAISE LP IGNORE RP */ { - yymsp[-3].minor.yy18 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); - if( yymsp[-3].minor.yy18 ){ - yymsp[-3].minor.yy18->affinity = OE_Ignore; + yymsp[-3].minor.yy102 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); + if( yymsp[-3].minor.yy102 ){ + yymsp[-3].minor.yy102->affinity = OE_Ignore; } } break; - case 258: /* expr ::= RAISE LP raisetype COMMA nm RP */ + case 261: /* expr ::= RAISE LP raisetype COMMA nm RP */ { - yymsp[-5].minor.yy18 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); - if( yymsp[-5].minor.yy18 ) { - yymsp[-5].minor.yy18->affinity = (char)yymsp[-3].minor.yy70; + yymsp[-5].minor.yy102 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); + if( yymsp[-5].minor.yy102 ) { + yymsp[-5].minor.yy102->affinity = (char)yymsp[-3].minor.yy100; } } break; - case 259: /* raisetype ::= ROLLBACK */ -{yymsp[0].minor.yy70 = OE_Rollback;} + case 262: /* raisetype ::= ROLLBACK */ +{yymsp[0].minor.yy100 = OE_Rollback;} break; - case 261: /* raisetype ::= FAIL */ -{yymsp[0].minor.yy70 = OE_Fail;} + case 264: /* raisetype ::= FAIL */ +{yymsp[0].minor.yy100 = OE_Fail;} break; - case 262: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 265: /* cmd ::= DROP TRIGGER ifexists fullname */ { - sqlite3DropTrigger(pParse,yymsp[0].minor.yy135,yymsp[-1].minor.yy70); + sqlite3DropTrigger(pParse,yymsp[0].minor.yy407,yymsp[-1].minor.yy100); } break; - case 263: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 266: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { - sqlite3Attach(pParse, yymsp[-3].minor.yy18, yymsp[-1].minor.yy18, yymsp[0].minor.yy18); + sqlite3Attach(pParse, yymsp[-3].minor.yy102, yymsp[-1].minor.yy102, yymsp[0].minor.yy102); } break; - case 264: /* cmd ::= DETACH database_kw_opt expr */ + case 267: /* cmd ::= DETACH database_kw_opt expr */ { - sqlite3Detach(pParse, yymsp[0].minor.yy18); + sqlite3Detach(pParse, yymsp[0].minor.yy102); } break; - case 267: /* cmd ::= REINDEX */ + case 270: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 268: /* cmd ::= REINDEX nm dbnm */ + case 271: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 269: /* cmd ::= ANALYZE */ + case 272: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 270: /* cmd ::= ANALYZE nm dbnm */ + case 273: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 271: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 274: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { - sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy135,&yymsp[0].minor.yy0); + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy407,&yymsp[0].minor.yy0); } break; - case 272: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 275: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; - case 273: /* add_column_fullname ::= fullname */ + case 276: /* add_column_fullname ::= fullname */ { disableLookaside(pParse); - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy135); + sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy407); } break; - case 274: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + case 277: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ { - sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy135, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); + sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy407, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); } break; - case 275: /* cmd ::= create_vtab */ + case 278: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 276: /* cmd ::= create_vtab LP vtabarglist RP */ + case 279: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 277: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 280: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { - sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy70); + sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy100); } break; - case 278: /* vtabarg ::= */ + case 281: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 279: /* vtabargtoken ::= ANY */ - case 280: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==280); - case 281: /* lp ::= LP */ yytestcase(yyruleno==281); + case 282: /* vtabargtoken ::= ANY */ + case 283: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==283); + case 284: /* lp ::= LP */ yytestcase(yyruleno==284); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 282: /* with ::= WITH wqlist */ - case 283: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==283); -{ sqlite3WithPush(pParse, yymsp[0].minor.yy449, 1); } + case 285: /* with ::= WITH wqlist */ + case 286: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==286); +{ sqlite3WithPush(pParse, yymsp[0].minor.yy243, 1); } break; - case 284: /* wqlist ::= nm eidlist_opt AS LP select RP */ + case 287: /* wqlist ::= nm eidlist_opt AS LP select RP */ { - yymsp[-5].minor.yy449 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy420, yymsp[-1].minor.yy489); /*A-overwrites-X*/ + yymsp[-5].minor.yy243 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy94, yymsp[-1].minor.yy391); /*A-overwrites-X*/ } break; - case 285: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ + case 288: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ { - yymsp[-7].minor.yy449 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy449, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy420, yymsp[-1].minor.yy489); + yymsp[-7].minor.yy243 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy243, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy94, yymsp[-1].minor.yy391); } break; - case 286: /* windowdefn_list ::= windowdefn */ -{ yylhsminor.yy327 = yymsp[0].minor.yy327; } - yymsp[0].minor.yy327 = yylhsminor.yy327; + case 289: /* windowdefn_list ::= windowdefn */ +{ yylhsminor.yy379 = yymsp[0].minor.yy379; } + yymsp[0].minor.yy379 = yylhsminor.yy379; break; - case 287: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ + case 290: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ { - assert( yymsp[0].minor.yy327!=0 ); - yymsp[0].minor.yy327->pNextWin = yymsp[-2].minor.yy327; - yylhsminor.yy327 = yymsp[0].minor.yy327; + assert( yymsp[0].minor.yy379!=0 ); + sqlite3WindowChain(pParse, yymsp[0].minor.yy379, yymsp[-2].minor.yy379); + yymsp[0].minor.yy379->pNextWin = yymsp[-2].minor.yy379; + yylhsminor.yy379 = yymsp[0].minor.yy379; } - yymsp[-2].minor.yy327 = yylhsminor.yy327; + yymsp[-2].minor.yy379 = yylhsminor.yy379; break; - case 288: /* windowdefn ::= nm AS window */ + case 291: /* windowdefn ::= nm AS LP window RP */ { - if( ALWAYS(yymsp[0].minor.yy327) ){ - yymsp[0].minor.yy327->zName = sqlite3DbStrNDup(pParse->db, yymsp[-2].minor.yy0.z, yymsp[-2].minor.yy0.n); + if( ALWAYS(yymsp[-1].minor.yy379) ){ + yymsp[-1].minor.yy379->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); } - yylhsminor.yy327 = yymsp[0].minor.yy327; + yylhsminor.yy379 = yymsp[-1].minor.yy379; } - yymsp[-2].minor.yy327 = yylhsminor.yy327; + yymsp[-4].minor.yy379 = yylhsminor.yy379; break; - case 289: /* window ::= LP part_opt orderby_opt frame_opt RP */ + case 292: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ { - yymsp[-4].minor.yy327 = yymsp[-1].minor.yy327; - if( ALWAYS(yymsp[-4].minor.yy327) ){ - yymsp[-4].minor.yy327->pPartition = yymsp[-3].minor.yy420; - yymsp[-4].minor.yy327->pOrderBy = yymsp[-2].minor.yy420; - } + yymsp[-4].minor.yy379 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy379, yymsp[-2].minor.yy94, yymsp[-1].minor.yy94, 0); } break; - case 290: /* part_opt ::= PARTITION BY nexprlist */ -{ yymsp[-2].minor.yy420 = yymsp[0].minor.yy420; } + case 293: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ +{ + yylhsminor.yy379 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy379, yymsp[-2].minor.yy94, yymsp[-1].minor.yy94, &yymsp[-5].minor.yy0); +} + yymsp[-5].minor.yy379 = yylhsminor.yy379; break; - case 291: /* part_opt ::= */ -{ yymsp[1].minor.yy420 = 0; } + case 294: /* window ::= ORDER BY sortlist frame_opt */ +{ + yymsp[-3].minor.yy379 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy379, 0, yymsp[-1].minor.yy94, 0); +} break; - case 292: /* frame_opt ::= */ + case 295: /* window ::= nm ORDER BY sortlist frame_opt */ +{ + yylhsminor.yy379 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy379, 0, yymsp[-1].minor.yy94, &yymsp[-4].minor.yy0); +} + yymsp[-4].minor.yy379 = yylhsminor.yy379; + break; + case 296: /* window ::= frame_opt */ +{ + yylhsminor.yy379 = yymsp[0].minor.yy379; +} + yymsp[0].minor.yy379 = yylhsminor.yy379; + break; + case 297: /* window ::= nm frame_opt */ +{ + yylhsminor.yy379 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy379, 0, 0, &yymsp[-1].minor.yy0); +} + yymsp[-1].minor.yy379 = yylhsminor.yy379; + break; + case 298: /* frame_opt ::= */ { - yymsp[1].minor.yy327 = sqlite3WindowAlloc(pParse, TK_RANGE, TK_UNBOUNDED, 0, TK_CURRENT, 0); + yymsp[1].minor.yy379 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); } break; - case 293: /* frame_opt ::= range_or_rows frame_bound_s */ + case 299: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ { - yylhsminor.yy327 = sqlite3WindowAlloc(pParse, yymsp[-1].minor.yy70, yymsp[0].minor.yy119.eType, yymsp[0].minor.yy119.pExpr, TK_CURRENT, 0); + yylhsminor.yy379 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy100, yymsp[-1].minor.yy389.eType, yymsp[-1].minor.yy389.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy218); } - yymsp[-1].minor.yy327 = yylhsminor.yy327; + yymsp[-2].minor.yy379 = yylhsminor.yy379; break; - case 294: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e */ + case 300: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ { - yylhsminor.yy327 = sqlite3WindowAlloc(pParse, yymsp[-4].minor.yy70, yymsp[-2].minor.yy119.eType, yymsp[-2].minor.yy119.pExpr, yymsp[0].minor.yy119.eType, yymsp[0].minor.yy119.pExpr); + yylhsminor.yy379 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy100, yymsp[-3].minor.yy389.eType, yymsp[-3].minor.yy389.pExpr, yymsp[-1].minor.yy389.eType, yymsp[-1].minor.yy389.pExpr, yymsp[0].minor.yy218); } - yymsp[-4].minor.yy327 = yylhsminor.yy327; + yymsp[-5].minor.yy379 = yylhsminor.yy379; break; - case 295: /* range_or_rows ::= RANGE */ -{ yymsp[0].minor.yy70 = TK_RANGE; } + case 302: /* frame_bound_s ::= frame_bound */ + case 304: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==304); +{yylhsminor.yy389 = yymsp[0].minor.yy389;} + yymsp[0].minor.yy389 = yylhsminor.yy389; break; - case 296: /* range_or_rows ::= ROWS */ -{ yymsp[0].minor.yy70 = TK_ROWS; } + case 303: /* frame_bound_s ::= UNBOUNDED PRECEDING */ + case 305: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==305); + case 307: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==307); +{yylhsminor.yy389.eType = yymsp[-1].major; yylhsminor.yy389.pExpr = 0;} + yymsp[-1].minor.yy389 = yylhsminor.yy389; break; - case 297: /* frame_bound_s ::= frame_bound */ - case 299: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==299); -{ yylhsminor.yy119 = yymsp[0].minor.yy119; } - yymsp[0].minor.yy119 = yylhsminor.yy119; + case 306: /* frame_bound ::= expr PRECEDING|FOLLOWING */ +{yylhsminor.yy389.eType = yymsp[0].major; yylhsminor.yy389.pExpr = yymsp[-1].minor.yy102;} + yymsp[-1].minor.yy389 = yylhsminor.yy389; break; - case 298: /* frame_bound_s ::= UNBOUNDED PRECEDING */ - case 300: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==300); -{yymsp[-1].minor.yy119.eType = TK_UNBOUNDED; yymsp[-1].minor.yy119.pExpr = 0;} + case 308: /* frame_exclude_opt ::= */ +{yymsp[1].minor.yy218 = 0;} break; - case 301: /* frame_bound ::= expr PRECEDING */ -{ yylhsminor.yy119.eType = TK_PRECEDING; yylhsminor.yy119.pExpr = yymsp[-1].minor.yy18; } - yymsp[-1].minor.yy119 = yylhsminor.yy119; + case 309: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ +{yymsp[-1].minor.yy218 = yymsp[0].minor.yy218;} break; - case 302: /* frame_bound ::= CURRENT ROW */ -{ yymsp[-1].minor.yy119.eType = TK_CURRENT ; yymsp[-1].minor.yy119.pExpr = 0; } + case 310: /* frame_exclude ::= NO OTHERS */ + case 311: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==311); +{yymsp[-1].minor.yy218 = yymsp[-1].major; /*A-overwrites-X*/} break; - case 303: /* frame_bound ::= expr FOLLOWING */ -{ yylhsminor.yy119.eType = TK_FOLLOWING; yylhsminor.yy119.pExpr = yymsp[-1].minor.yy18; } - yymsp[-1].minor.yy119 = yylhsminor.yy119; + case 312: /* frame_exclude ::= GROUP|TIES */ +{yymsp[0].minor.yy218 = yymsp[0].major; /*A-overwrites-X*/} break; - case 304: /* window_clause ::= WINDOW windowdefn_list */ -{ yymsp[-1].minor.yy327 = yymsp[0].minor.yy327; } + case 313: /* window_clause ::= WINDOW windowdefn_list */ +{ yymsp[-1].minor.yy379 = yymsp[0].minor.yy379; } break; - case 305: /* over_clause ::= filter_opt OVER window */ + case 314: /* over_clause ::= filter_opt OVER LP window RP */ { - yylhsminor.yy327 = yymsp[0].minor.yy327; - assert( yylhsminor.yy327!=0 ); - yylhsminor.yy327->pFilter = yymsp[-2].minor.yy18; + yylhsminor.yy379 = yymsp[-1].minor.yy379; + assert( yylhsminor.yy379!=0 ); + yylhsminor.yy379->pFilter = yymsp[-4].minor.yy102; } - yymsp[-2].minor.yy327 = yylhsminor.yy327; + yymsp[-4].minor.yy379 = yylhsminor.yy379; break; - case 306: /* over_clause ::= filter_opt OVER nm */ + case 315: /* over_clause ::= filter_opt OVER nm */ { - yylhsminor.yy327 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); - if( yylhsminor.yy327 ){ - yylhsminor.yy327->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); - yylhsminor.yy327->pFilter = yymsp[-2].minor.yy18; + yylhsminor.yy379 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( yylhsminor.yy379 ){ + yylhsminor.yy379->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); + yylhsminor.yy379->pFilter = yymsp[-2].minor.yy102; }else{ - sqlite3ExprDelete(pParse->db, yymsp[-2].minor.yy18); + sqlite3ExprDelete(pParse->db, yymsp[-2].minor.yy102); } } - yymsp[-2].minor.yy327 = yylhsminor.yy327; + yymsp[-2].minor.yy379 = yylhsminor.yy379; break; - case 308: /* filter_opt ::= FILTER LP WHERE expr RP */ -{ yymsp[-4].minor.yy18 = yymsp[-1].minor.yy18; } + case 317: /* filter_opt ::= FILTER LP WHERE expr RP */ +{ yymsp[-4].minor.yy102 = yymsp[-1].minor.yy102; } break; default: - /* (309) input ::= cmdlist */ yytestcase(yyruleno==309); - /* (310) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==310); - /* (311) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=311); - /* (312) ecmd ::= SEMI */ yytestcase(yyruleno==312); - /* (313) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==313); - /* (314) ecmd ::= explain cmdx */ yytestcase(yyruleno==314); - /* (315) trans_opt ::= */ yytestcase(yyruleno==315); - /* (316) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==316); - /* (317) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==317); - /* (318) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==318); - /* (319) savepoint_opt ::= */ yytestcase(yyruleno==319); - /* (320) cmd ::= create_table create_table_args */ yytestcase(yyruleno==320); - /* (321) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==321); - /* (322) columnlist ::= columnname carglist */ yytestcase(yyruleno==322); - /* (323) nm ::= ID|INDEXED */ yytestcase(yyruleno==323); - /* (324) nm ::= STRING */ yytestcase(yyruleno==324); - /* (325) nm ::= JOIN_KW */ yytestcase(yyruleno==325); - /* (326) typetoken ::= typename */ yytestcase(yyruleno==326); - /* (327) typename ::= ID|STRING */ yytestcase(yyruleno==327); - /* (328) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=328); - /* (329) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=329); - /* (330) carglist ::= carglist ccons */ yytestcase(yyruleno==330); - /* (331) carglist ::= */ yytestcase(yyruleno==331); - /* (332) ccons ::= NULL onconf */ yytestcase(yyruleno==332); - /* (333) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==333); - /* (334) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==334); - /* (335) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=335); - /* (336) tconscomma ::= */ yytestcase(yyruleno==336); - /* (337) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=337); - /* (338) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=338); - /* (339) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=339); - /* (340) oneselect ::= values */ yytestcase(yyruleno==340); - /* (341) sclp ::= selcollist COMMA */ yytestcase(yyruleno==341); - /* (342) as ::= ID|STRING */ yytestcase(yyruleno==342); - /* (343) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=343); - /* (344) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==344); - /* (345) exprlist ::= nexprlist */ yytestcase(yyruleno==345); - /* (346) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=346); - /* (347) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=347); - /* (348) nmnum ::= ON */ yytestcase(yyruleno==348); - /* (349) nmnum ::= DELETE */ yytestcase(yyruleno==349); - /* (350) nmnum ::= DEFAULT */ yytestcase(yyruleno==350); - /* (351) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==351); - /* (352) foreach_clause ::= */ yytestcase(yyruleno==352); - /* (353) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==353); - /* (354) trnm ::= nm */ yytestcase(yyruleno==354); - /* (355) tridxby ::= */ yytestcase(yyruleno==355); - /* (356) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==356); - /* (357) database_kw_opt ::= */ yytestcase(yyruleno==357); - /* (358) kwcolumn_opt ::= */ yytestcase(yyruleno==358); - /* (359) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==359); - /* (360) vtabarglist ::= vtabarg */ yytestcase(yyruleno==360); - /* (361) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==361); - /* (362) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==362); - /* (363) anylist ::= */ yytestcase(yyruleno==363); - /* (364) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==364); - /* (365) anylist ::= anylist ANY */ yytestcase(yyruleno==365); - /* (366) with ::= */ yytestcase(yyruleno==366); + /* (318) input ::= cmdlist */ yytestcase(yyruleno==318); + /* (319) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==319); + /* (320) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=320); + /* (321) ecmd ::= SEMI */ yytestcase(yyruleno==321); + /* (322) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==322); + /* (323) ecmd ::= explain cmdx */ yytestcase(yyruleno==323); + /* (324) trans_opt ::= */ yytestcase(yyruleno==324); + /* (325) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==325); + /* (326) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==326); + /* (327) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==327); + /* (328) savepoint_opt ::= */ yytestcase(yyruleno==328); + /* (329) cmd ::= create_table create_table_args */ yytestcase(yyruleno==329); + /* (330) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==330); + /* (331) columnlist ::= columnname carglist */ yytestcase(yyruleno==331); + /* (332) nm ::= ID|INDEXED */ yytestcase(yyruleno==332); + /* (333) nm ::= STRING */ yytestcase(yyruleno==333); + /* (334) nm ::= JOIN_KW */ yytestcase(yyruleno==334); + /* (335) typetoken ::= typename */ yytestcase(yyruleno==335); + /* (336) typename ::= ID|STRING */ yytestcase(yyruleno==336); + /* (337) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=337); + /* (338) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=338); + /* (339) carglist ::= carglist ccons */ yytestcase(yyruleno==339); + /* (340) carglist ::= */ yytestcase(yyruleno==340); + /* (341) ccons ::= NULL onconf */ yytestcase(yyruleno==341); + /* (342) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==342); + /* (343) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==343); + /* (344) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=344); + /* (345) tconscomma ::= */ yytestcase(yyruleno==345); + /* (346) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=346); + /* (347) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=347); + /* (348) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=348); + /* (349) oneselect ::= values */ yytestcase(yyruleno==349); + /* (350) sclp ::= selcollist COMMA */ yytestcase(yyruleno==350); + /* (351) as ::= ID|STRING */ yytestcase(yyruleno==351); + /* (352) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=352); + /* (353) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==353); + /* (354) exprlist ::= nexprlist */ yytestcase(yyruleno==354); + /* (355) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=355); + /* (356) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=356); + /* (357) nmnum ::= ON */ yytestcase(yyruleno==357); + /* (358) nmnum ::= DELETE */ yytestcase(yyruleno==358); + /* (359) nmnum ::= DEFAULT */ yytestcase(yyruleno==359); + /* (360) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==360); + /* (361) foreach_clause ::= */ yytestcase(yyruleno==361); + /* (362) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==362); + /* (363) trnm ::= nm */ yytestcase(yyruleno==363); + /* (364) tridxby ::= */ yytestcase(yyruleno==364); + /* (365) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==365); + /* (366) database_kw_opt ::= */ yytestcase(yyruleno==366); + /* (367) kwcolumn_opt ::= */ yytestcase(yyruleno==367); + /* (368) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==368); + /* (369) vtabarglist ::= vtabarg */ yytestcase(yyruleno==369); + /* (370) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==370); + /* (371) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==371); + /* (372) anylist ::= */ yytestcase(yyruleno==372); + /* (373) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==373); + /* (374) anylist ::= anylist ANY */ yytestcase(yyruleno==374); + /* (375) with ::= */ yytestcase(yyruleno==375); break; /********** End reduce actions ************************************************/ }; - assert( yyrulenoyytos >= yypParser->yystack - && yymx != YYERRORSYMBOL && (yyact = yy_find_reduce_action( yypParser->yytos->stateno, - YYERRORSYMBOL)) >= YY_MIN_REDUCE + YYERRORSYMBOL)) > YY_MAX_SHIFTREDUCE ){ yy_pop_parser_stack(yypParser); } @@ -150480,144 +153766,144 @@ const unsigned char ebcdicToAscii[] = { ** is substantially reduced. This is important for embedded applications ** on platforms with limited memory. */ -/* Hash score: 208 */ -/* zKWText[] encodes 923 bytes of keyword text in 614 bytes */ +/* Hash score: 214 */ +/* zKWText[] encodes 950 bytes of keyword text in 629 bytes */ /* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ -/* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */ -/* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */ -/* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERANGEBETWEEN */ -/* OTHINGLOBYCASCADELETECASECOLLATECREATECURRENT_DATEDETACH */ -/* IMMEDIATEJOINSERTLIKEMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMIT */ -/* WHENOTNULLWHERECURSIVEAFTERENAMEANDEFAULTAUTOINCREMENTCAST */ -/* COLUMNCOMMITCONFLICTCROSSCURRENT_TIMESTAMPARTITIONDEFERRED */ -/* ISTINCTDROPRECEDINGFAILFILTEREPLACEFOLLOWINGFROMFULLIFISNULL */ -/* ORDERESTRICTOVERIGHTROLLBACKROWSUNBOUNDEDUNIONUSINGVACUUMVIEW */ -/* INDOWINITIALLYPRIMARY */ -static const char zKWText[613] = { +/* ABLEFTHENDEFERRABLELSEXCLUDELETEMPORARYCONSTRAINTERSECTIES */ +/* AVEPOINTOFFSETRANSACTIONATURALTERAISEXCEPTRIGGEREFERENCES */ +/* UNIQUERYWITHOUTERELEASEXCLUSIVEXISTSATTACHAVINGLOBEGINNERANGE */ +/* BETWEENOTHINGROUPSCASCADETACHCASECOLLATECREATECURRENT_DATE */ +/* IMMEDIATEJOINSERTLIKEMATCHPLANALYZEPRAGMABORTUPDATEVALUES */ +/* VIRTUALIMITWHENOTNULLWHERECURSIVEAFTERENAMEANDEFAULT */ +/* AUTOINCREMENTCASTCOLUMNCOMMITCONFLICTCROSSCURRENT_TIMESTAMP */ +/* ARTITIONDEFERREDISTINCTDROPRECEDINGFAILFILTEREPLACEFOLLOWING */ +/* FROMFULLIFISNULLORDERESTRICTOTHERSOVERIGHTROLLBACKROWS */ +/* UNBOUNDEDUNIONUSINGVACUUMVIEWINDOWBYINITIALLYPRIMARY */ +static const char zKWText[628] = { 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F', - 'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N', - 'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I', - 'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E', - 'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E', - 'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T', - 'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q', - 'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S', - 'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A', - 'T','E','B','E','G','I','N','N','E','R','A','N','G','E','B','E','T','W', - 'E','E','N','O','T','H','I','N','G','L','O','B','Y','C','A','S','C','A', - 'D','E','L','E','T','E','C','A','S','E','C','O','L','L','A','T','E','C', - 'R','E','A','T','E','C','U','R','R','E','N','T','_','D','A','T','E','D', - 'E','T','A','C','H','I','M','M','E','D','I','A','T','E','J','O','I','N', - 'S','E','R','T','L','I','K','E','M','A','T','C','H','P','L','A','N','A', - 'L','Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U', - 'E','S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','O', - 'T','N','U','L','L','W','H','E','R','E','C','U','R','S','I','V','E','A', - 'F','T','E','R','E','N','A','M','E','A','N','D','E','F','A','U','L','T', - 'A','U','T','O','I','N','C','R','E','M','E','N','T','C','A','S','T','C', - 'O','L','U','M','N','C','O','M','M','I','T','C','O','N','F','L','I','C', - 'T','C','R','O','S','S','C','U','R','R','E','N','T','_','T','I','M','E', - 'S','T','A','M','P','A','R','T','I','T','I','O','N','D','E','F','E','R', - 'R','E','D','I','S','T','I','N','C','T','D','R','O','P','R','E','C','E', - 'D','I','N','G','F','A','I','L','F','I','L','T','E','R','E','P','L','A', - 'C','E','F','O','L','L','O','W','I','N','G','F','R','O','M','F','U','L', - 'L','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T','R', - 'I','C','T','O','V','E','R','I','G','H','T','R','O','L','L','B','A','C', - 'K','R','O','W','S','U','N','B','O','U','N','D','E','D','U','N','I','O', - 'N','U','S','I','N','G','V','A','C','U','U','M','V','I','E','W','I','N', - 'D','O','W','I','N','I','T','I','A','L','L','Y','P','R','I','M','A','R', - 'Y', + 'E','R','R','A','B','L','E','L','S','E','X','C','L','U','D','E','L','E', + 'T','E','M','P','O','R','A','R','Y','C','O','N','S','T','R','A','I','N', + 'T','E','R','S','E','C','T','I','E','S','A','V','E','P','O','I','N','T', + 'O','F','F','S','E','T','R','A','N','S','A','C','T','I','O','N','A','T', + 'U','R','A','L','T','E','R','A','I','S','E','X','C','E','P','T','R','I', + 'G','G','E','R','E','F','E','R','E','N','C','E','S','U','N','I','Q','U', + 'E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S','E', + 'X','C','L','U','S','I','V','E','X','I','S','T','S','A','T','T','A','C', + 'H','A','V','I','N','G','L','O','B','E','G','I','N','N','E','R','A','N', + 'G','E','B','E','T','W','E','E','N','O','T','H','I','N','G','R','O','U', + 'P','S','C','A','S','C','A','D','E','T','A','C','H','C','A','S','E','C', + 'O','L','L','A','T','E','C','R','E','A','T','E','C','U','R','R','E','N', + 'T','_','D','A','T','E','I','M','M','E','D','I','A','T','E','J','O','I', + 'N','S','E','R','T','L','I','K','E','M','A','T','C','H','P','L','A','N', + 'A','L','Y','Z','E','P','R','A','G','M','A','B','O','R','T','U','P','D', + 'A','T','E','V','A','L','U','E','S','V','I','R','T','U','A','L','I','M', + 'I','T','W','H','E','N','O','T','N','U','L','L','W','H','E','R','E','C', + 'U','R','S','I','V','E','A','F','T','E','R','E','N','A','M','E','A','N', + 'D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E','M','E', + 'N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M','I','T', + 'C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R','R','E', + 'N','T','_','T','I','M','E','S','T','A','M','P','A','R','T','I','T','I', + 'O','N','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D', + 'R','O','P','R','E','C','E','D','I','N','G','F','A','I','L','F','I','L', + 'T','E','R','E','P','L','A','C','E','F','O','L','L','O','W','I','N','G', + 'F','R','O','M','F','U','L','L','I','F','I','S','N','U','L','L','O','R', + 'D','E','R','E','S','T','R','I','C','T','O','T','H','E','R','S','O','V', + 'E','R','I','G','H','T','R','O','L','L','B','A','C','K','R','O','W','S', + 'U','N','B','O','U','N','D','E','D','U','N','I','O','N','U','S','I','N', + 'G','V','A','C','U','U','M','V','I','E','W','I','N','D','O','W','B','Y', + 'I','N','I','T','I','A','L','L','Y','P','R','I','M','A','R','Y', }; /* aKWHash[i] is the hash value for the i-th keyword */ static const unsigned char aKWHash[127] = { - 74, 109, 124, 72, 106, 45, 0, 0, 81, 0, 76, 61, 0, - 42, 12, 77, 15, 0, 123, 84, 54, 118, 125, 19, 0, 0, - 130, 0, 128, 121, 0, 22, 96, 0, 9, 0, 0, 115, 69, - 0, 67, 6, 0, 48, 93, 136, 0, 126, 104, 0, 0, 44, - 0, 107, 24, 0, 17, 0, 131, 53, 23, 0, 5, 62, 132, - 99, 0, 0, 135, 110, 60, 134, 57, 113, 55, 0, 94, 0, - 103, 26, 0, 102, 0, 0, 0, 98, 95, 100, 105, 117, 14, - 39, 116, 0, 80, 0, 133, 114, 92, 59, 0, 129, 79, 119, - 86, 46, 83, 0, 0, 97, 40, 122, 120, 0, 127, 0, 0, - 29, 0, 89, 87, 88, 0, 20, 85, 111, 56, + 75, 111, 127, 73, 108, 29, 0, 0, 83, 0, 77, 63, 0, + 37, 33, 78, 15, 0, 126, 86, 57, 120, 128, 19, 0, 0, + 133, 0, 131, 123, 0, 22, 98, 0, 9, 0, 0, 117, 71, + 0, 69, 6, 0, 49, 95, 140, 0, 129, 106, 0, 0, 54, + 0, 109, 24, 0, 17, 0, 134, 56, 23, 26, 5, 58, 135, + 101, 0, 0, 139, 112, 62, 138, 59, 115, 65, 0, 96, 0, + 105, 45, 0, 104, 0, 0, 0, 100, 97, 102, 107, 119, 14, + 31, 118, 0, 81, 0, 136, 116, 137, 61, 124, 132, 80, 121, + 88, 30, 85, 0, 0, 99, 35, 125, 122, 0, 130, 0, 0, + 41, 0, 91, 89, 90, 0, 20, 87, 113, 82, }; /* aKWNext[] forms the hash collision chain. If aKWHash[i]==0 ** then the i-th keyword has no more hash collisions. Otherwise, ** the next keyword with the same hash is aKWHash[i]-1. */ -static const unsigned char aKWNext[136] = { +static const unsigned char aKWNext[140] = { 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, - 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 33, 0, 21, 0, 0, 0, 0, 0, 50, - 0, 43, 3, 47, 0, 0, 32, 0, 0, 0, 0, 0, 0, - 0, 1, 64, 0, 0, 65, 0, 41, 0, 38, 0, 0, 0, - 0, 0, 49, 75, 0, 0, 30, 0, 58, 0, 0, 0, 31, - 63, 16, 34, 10, 0, 0, 0, 0, 0, 0, 0, 11, 70, - 91, 0, 0, 8, 0, 108, 0, 101, 28, 52, 68, 0, 112, - 0, 73, 51, 0, 90, 27, 37, 0, 71, 36, 82, 0, 35, - 66, 25, 18, 0, 0, 78, + 0, 0, 0, 21, 0, 0, 12, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 51, 28, 0, 0, 38, 0, 0, 0, 44, 0, 0, 0, 3, + 0, 0, 67, 1, 66, 0, 0, 0, 36, 0, 47, 0, 0, + 0, 0, 0, 48, 50, 76, 0, 0, 42, 0, 60, 0, 0, + 0, 43, 0, 16, 55, 10, 0, 0, 0, 0, 0, 0, 0, + 11, 72, 93, 0, 0, 8, 0, 110, 0, 103, 40, 53, 70, + 0, 114, 0, 74, 52, 0, 0, 92, 39, 46, 0, 68, 32, + 84, 0, 34, 27, 25, 18, 94, 0, 64, 79, }; /* aKWLen[i] is the length (in bytes) of the i-th keyword */ -static const unsigned char aKWLen[136] = { +static const unsigned char aKWLen[140] = { 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, - 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 6, - 11, 6, 2, 7, 5, 5, 9, 6, 9, 9, 7, 10, 10, - 4, 6, 2, 3, 9, 4, 2, 6, 5, 7, 4, 5, 7, - 6, 6, 5, 6, 5, 5, 5, 7, 7, 4, 2, 7, 3, - 6, 4, 7, 6, 12, 6, 9, 4, 6, 4, 5, 4, 7, - 6, 5, 6, 7, 5, 4, 7, 3, 2, 4, 5, 9, 5, - 6, 3, 7, 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, - 7, 9, 8, 8, 2, 4, 9, 4, 6, 7, 9, 4, 4, - 2, 6, 5, 8, 4, 5, 8, 4, 3, 9, 5, 5, 6, - 4, 6, 2, 9, 3, 7, + 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7, + 6, 9, 4, 2, 10, 9, 4, 9, 4, 6, 2, 3, 11, + 6, 2, 7, 5, 5, 6, 7, 10, 6, 5, 7, 4, 5, + 7, 9, 6, 6, 6, 4, 5, 5, 5, 7, 7, 6, 5, + 7, 3, 6, 4, 7, 6, 12, 9, 4, 6, 4, 5, 4, + 7, 6, 5, 6, 6, 7, 5, 4, 7, 3, 2, 4, 5, + 9, 5, 6, 3, 7, 13, 2, 2, 4, 6, 6, 8, 5, + 17, 12, 7, 9, 8, 8, 2, 4, 9, 4, 6, 7, 9, + 4, 4, 2, 6, 5, 8, 6, 4, 5, 8, 4, 3, 9, + 5, 5, 6, 4, 6, 2, 2, 9, 3, 7, }; /* aKWOffset[i] is the index into zKWText[] of the start of ** the text for the i-th keyword. */ -static const unsigned short int aKWOffset[136] = { +static const unsigned short int aKWOffset[140] = { 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, - 86, 91, 95, 96, 101, 105, 109, 117, 122, 128, 136, 142, 152, - 159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192, - 199, 204, 209, 212, 218, 221, 225, 230, 236, 242, 245, 247, 248, - 252, 258, 262, 269, 275, 287, 293, 302, 304, 310, 314, 319, 321, - 328, 333, 338, 344, 350, 355, 358, 358, 358, 361, 365, 368, 377, - 381, 387, 389, 396, 398, 400, 409, 413, 419, 425, 433, 438, 438, - 438, 454, 463, 470, 471, 478, 481, 490, 494, 499, 506, 515, 519, - 523, 525, 531, 535, 543, 546, 551, 559, 559, 563, 572, 577, 582, - 588, 591, 594, 597, 602, 606, + 86, 90, 90, 94, 99, 106, 114, 117, 123, 126, 126, 129, 131, + 136, 140, 141, 146, 150, 154, 159, 165, 175, 178, 183, 183, 187, + 191, 197, 205, 211, 216, 221, 224, 227, 231, 236, 242, 248, 248, + 254, 255, 259, 265, 269, 276, 282, 294, 303, 305, 311, 315, 320, + 322, 329, 334, 339, 345, 351, 357, 362, 365, 365, 365, 368, 372, + 375, 384, 388, 394, 396, 403, 405, 407, 416, 420, 426, 432, 440, + 445, 445, 445, 461, 470, 477, 478, 485, 488, 497, 501, 506, 513, + 522, 526, 530, 532, 538, 542, 550, 556, 559, 564, 572, 572, 576, + 585, 590, 595, 601, 604, 607, 610, 612, 617, 621, }; /* aKWCode[i] is the parser symbol code for the i-th keyword */ -static const unsigned char aKWCode[136] = { +static const unsigned char aKWCode[140] = { TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE, TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE, - TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW, - TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_SAVEPOINT, - TK_INTERSECT, TK_TRIGGER, TK_REFERENCES, TK_CONSTRAINT, TK_INTO, - TK_OFFSET, TK_OF, TK_SET, TK_TEMP, TK_TEMP, - TK_OR, TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH, - TK_JOIN_KW, TK_RELEASE, TK_ATTACH, TK_HAVING, TK_GROUP, - TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RANGE, TK_BETWEEN, - TK_NOTHING, TK_LIKE_KW, TK_BY, TK_CASCADE, TK_ASC, - TK_DELETE, TK_CASE, TK_COLLATE, TK_CREATE, TK_CTIME_KW, - TK_DETACH, TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_LIKE_KW, - TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, TK_ABORT, - TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, TK_NOTNULL, - TK_NOT, TK_NO, TK_NULL, TK_WHERE, TK_RECURSIVE, - TK_AFTER, TK_RENAME, TK_AND, TK_DEFAULT, TK_AUTOINCR, - TK_TO, TK_IN, TK_CAST, TK_COLUMNKW, TK_COMMIT, - TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_CURRENT, - TK_PARTITION, TK_DEFERRED, TK_DISTINCT, TK_IS, TK_DROP, - TK_PRECEDING, TK_FAIL, TK_FILTER, TK_REPLACE, TK_FOLLOWING, - TK_FROM, TK_JOIN_KW, TK_IF, TK_ISNULL, TK_ORDER, - TK_RESTRICT, TK_OVER, TK_JOIN_KW, TK_ROLLBACK, TK_ROWS, - TK_ROW, TK_UNBOUNDED, TK_UNION, TK_USING, TK_VACUUM, - TK_VIEW, TK_WINDOW, TK_DO, TK_INITIALLY, TK_ALL, - TK_PRIMARY, + TK_EXCLUDE, TK_DELETE, TK_TEMP, TK_TEMP, TK_OR, + TK_CONSTRAINT, TK_INTERSECT, TK_TIES, TK_SAVEPOINT, TK_INTO, + TK_OFFSET, TK_OF, TK_SET, TK_TRANSACTION,TK_ACTION, + TK_ON, TK_JOIN_KW, TK_ALTER, TK_RAISE, TK_EXCEPT, + TK_TRIGGER, TK_REFERENCES, TK_UNIQUE, TK_QUERY, TK_WITHOUT, + TK_WITH, TK_JOIN_KW, TK_RELEASE, TK_EXCLUSIVE, TK_EXISTS, + TK_ATTACH, TK_HAVING, TK_LIKE_KW, TK_BEGIN, TK_JOIN_KW, + TK_RANGE, TK_BETWEEN, TK_NOTHING, TK_GROUPS, TK_GROUP, + TK_CASCADE, TK_ASC, TK_DETACH, TK_CASE, TK_COLLATE, + TK_CREATE, TK_CTIME_KW, TK_IMMEDIATE, TK_JOIN, TK_INSERT, + TK_LIKE_KW, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, + TK_ABORT, TK_UPDATE, TK_VALUES, TK_VIRTUAL, TK_LIMIT, + TK_WHEN, TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, + TK_WHERE, TK_RECURSIVE, TK_AFTER, TK_RENAME, TK_AND, + TK_DEFAULT, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, + TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, + TK_CTIME_KW, TK_CURRENT, TK_PARTITION, TK_DEFERRED, TK_DISTINCT, + TK_IS, TK_DROP, TK_PRECEDING, TK_FAIL, TK_FILTER, + TK_REPLACE, TK_FOLLOWING, TK_FROM, TK_JOIN_KW, TK_IF, + TK_ISNULL, TK_ORDER, TK_RESTRICT, TK_OTHERS, TK_OVER, + TK_JOIN_KW, TK_ROLLBACK, TK_ROWS, TK_ROW, TK_UNBOUNDED, + TK_UNION, TK_USING, TK_VACUUM, TK_VIEW, TK_WINDOW, + TK_DO, TK_BY, TK_INITIALLY, TK_ALL, TK_PRIMARY, }; /* Check to see if z[0..n-1] is a keyword. If it is, write the ** parser symbol code for that keyword into *pType. Always @@ -150663,117 +153949,121 @@ static int keywordCode(const char *z, int n, int *pType){ testcase( i==22 ); /* END */ testcase( i==23 ); /* DEFERRABLE */ testcase( i==24 ); /* ELSE */ - testcase( i==25 ); /* EXCEPT */ - testcase( i==26 ); /* TRANSACTION */ - testcase( i==27 ); /* ACTION */ - testcase( i==28 ); /* ON */ - testcase( i==29 ); /* NATURAL */ - testcase( i==30 ); /* ALTER */ - testcase( i==31 ); /* RAISE */ - testcase( i==32 ); /* EXCLUSIVE */ - testcase( i==33 ); /* EXISTS */ - testcase( i==34 ); /* SAVEPOINT */ - testcase( i==35 ); /* INTERSECT */ - testcase( i==36 ); /* TRIGGER */ - testcase( i==37 ); /* REFERENCES */ - testcase( i==38 ); /* CONSTRAINT */ - testcase( i==39 ); /* INTO */ - testcase( i==40 ); /* OFFSET */ - testcase( i==41 ); /* OF */ - testcase( i==42 ); /* SET */ - testcase( i==43 ); /* TEMPORARY */ - testcase( i==44 ); /* TEMP */ - testcase( i==45 ); /* OR */ - testcase( i==46 ); /* UNIQUE */ - testcase( i==47 ); /* QUERY */ - testcase( i==48 ); /* WITHOUT */ - testcase( i==49 ); /* WITH */ - testcase( i==50 ); /* OUTER */ - testcase( i==51 ); /* RELEASE */ - testcase( i==52 ); /* ATTACH */ - testcase( i==53 ); /* HAVING */ - testcase( i==54 ); /* GROUP */ - testcase( i==55 ); /* UPDATE */ - testcase( i==56 ); /* BEGIN */ - testcase( i==57 ); /* INNER */ - testcase( i==58 ); /* RANGE */ - testcase( i==59 ); /* BETWEEN */ - testcase( i==60 ); /* NOTHING */ - testcase( i==61 ); /* GLOB */ - testcase( i==62 ); /* BY */ - testcase( i==63 ); /* CASCADE */ - testcase( i==64 ); /* ASC */ - testcase( i==65 ); /* DELETE */ - testcase( i==66 ); /* CASE */ - testcase( i==67 ); /* COLLATE */ - testcase( i==68 ); /* CREATE */ - testcase( i==69 ); /* CURRENT_DATE */ - testcase( i==70 ); /* DETACH */ - testcase( i==71 ); /* IMMEDIATE */ - testcase( i==72 ); /* JOIN */ - testcase( i==73 ); /* INSERT */ - testcase( i==74 ); /* LIKE */ - testcase( i==75 ); /* MATCH */ - testcase( i==76 ); /* PLAN */ - testcase( i==77 ); /* ANALYZE */ - testcase( i==78 ); /* PRAGMA */ - testcase( i==79 ); /* ABORT */ - testcase( i==80 ); /* VALUES */ - testcase( i==81 ); /* VIRTUAL */ - testcase( i==82 ); /* LIMIT */ - testcase( i==83 ); /* WHEN */ - testcase( i==84 ); /* NOTNULL */ - testcase( i==85 ); /* NOT */ - testcase( i==86 ); /* NO */ - testcase( i==87 ); /* NULL */ - testcase( i==88 ); /* WHERE */ - testcase( i==89 ); /* RECURSIVE */ - testcase( i==90 ); /* AFTER */ - testcase( i==91 ); /* RENAME */ - testcase( i==92 ); /* AND */ - testcase( i==93 ); /* DEFAULT */ - testcase( i==94 ); /* AUTOINCREMENT */ - testcase( i==95 ); /* TO */ - testcase( i==96 ); /* IN */ - testcase( i==97 ); /* CAST */ - testcase( i==98 ); /* COLUMN */ - testcase( i==99 ); /* COMMIT */ - testcase( i==100 ); /* CONFLICT */ - testcase( i==101 ); /* CROSS */ - testcase( i==102 ); /* CURRENT_TIMESTAMP */ - testcase( i==103 ); /* CURRENT_TIME */ - testcase( i==104 ); /* CURRENT */ - testcase( i==105 ); /* PARTITION */ - testcase( i==106 ); /* DEFERRED */ - testcase( i==107 ); /* DISTINCT */ - testcase( i==108 ); /* IS */ - testcase( i==109 ); /* DROP */ - testcase( i==110 ); /* PRECEDING */ - testcase( i==111 ); /* FAIL */ - testcase( i==112 ); /* FILTER */ - testcase( i==113 ); /* REPLACE */ - testcase( i==114 ); /* FOLLOWING */ - testcase( i==115 ); /* FROM */ - testcase( i==116 ); /* FULL */ - testcase( i==117 ); /* IF */ - testcase( i==118 ); /* ISNULL */ - testcase( i==119 ); /* ORDER */ - testcase( i==120 ); /* RESTRICT */ - testcase( i==121 ); /* OVER */ - testcase( i==122 ); /* RIGHT */ - testcase( i==123 ); /* ROLLBACK */ - testcase( i==124 ); /* ROWS */ - testcase( i==125 ); /* ROW */ - testcase( i==126 ); /* UNBOUNDED */ - testcase( i==127 ); /* UNION */ - testcase( i==128 ); /* USING */ - testcase( i==129 ); /* VACUUM */ - testcase( i==130 ); /* VIEW */ - testcase( i==131 ); /* WINDOW */ - testcase( i==132 ); /* DO */ - testcase( i==133 ); /* INITIALLY */ - testcase( i==134 ); /* ALL */ - testcase( i==135 ); /* PRIMARY */ + testcase( i==25 ); /* EXCLUDE */ + testcase( i==26 ); /* DELETE */ + testcase( i==27 ); /* TEMPORARY */ + testcase( i==28 ); /* TEMP */ + testcase( i==29 ); /* OR */ + testcase( i==30 ); /* CONSTRAINT */ + testcase( i==31 ); /* INTERSECT */ + testcase( i==32 ); /* TIES */ + testcase( i==33 ); /* SAVEPOINT */ + testcase( i==34 ); /* INTO */ + testcase( i==35 ); /* OFFSET */ + testcase( i==36 ); /* OF */ + testcase( i==37 ); /* SET */ + testcase( i==38 ); /* TRANSACTION */ + testcase( i==39 ); /* ACTION */ + testcase( i==40 ); /* ON */ + testcase( i==41 ); /* NATURAL */ + testcase( i==42 ); /* ALTER */ + testcase( i==43 ); /* RAISE */ + testcase( i==44 ); /* EXCEPT */ + testcase( i==45 ); /* TRIGGER */ + testcase( i==46 ); /* REFERENCES */ + testcase( i==47 ); /* UNIQUE */ + testcase( i==48 ); /* QUERY */ + testcase( i==49 ); /* WITHOUT */ + testcase( i==50 ); /* WITH */ + testcase( i==51 ); /* OUTER */ + testcase( i==52 ); /* RELEASE */ + testcase( i==53 ); /* EXCLUSIVE */ + testcase( i==54 ); /* EXISTS */ + testcase( i==55 ); /* ATTACH */ + testcase( i==56 ); /* HAVING */ + testcase( i==57 ); /* GLOB */ + testcase( i==58 ); /* BEGIN */ + testcase( i==59 ); /* INNER */ + testcase( i==60 ); /* RANGE */ + testcase( i==61 ); /* BETWEEN */ + testcase( i==62 ); /* NOTHING */ + testcase( i==63 ); /* GROUPS */ + testcase( i==64 ); /* GROUP */ + testcase( i==65 ); /* CASCADE */ + testcase( i==66 ); /* ASC */ + testcase( i==67 ); /* DETACH */ + testcase( i==68 ); /* CASE */ + testcase( i==69 ); /* COLLATE */ + testcase( i==70 ); /* CREATE */ + testcase( i==71 ); /* CURRENT_DATE */ + testcase( i==72 ); /* IMMEDIATE */ + testcase( i==73 ); /* JOIN */ + testcase( i==74 ); /* INSERT */ + testcase( i==75 ); /* LIKE */ + testcase( i==76 ); /* MATCH */ + testcase( i==77 ); /* PLAN */ + testcase( i==78 ); /* ANALYZE */ + testcase( i==79 ); /* PRAGMA */ + testcase( i==80 ); /* ABORT */ + testcase( i==81 ); /* UPDATE */ + testcase( i==82 ); /* VALUES */ + testcase( i==83 ); /* VIRTUAL */ + testcase( i==84 ); /* LIMIT */ + testcase( i==85 ); /* WHEN */ + testcase( i==86 ); /* NOTNULL */ + testcase( i==87 ); /* NOT */ + testcase( i==88 ); /* NO */ + testcase( i==89 ); /* NULL */ + testcase( i==90 ); /* WHERE */ + testcase( i==91 ); /* RECURSIVE */ + testcase( i==92 ); /* AFTER */ + testcase( i==93 ); /* RENAME */ + testcase( i==94 ); /* AND */ + testcase( i==95 ); /* DEFAULT */ + testcase( i==96 ); /* AUTOINCREMENT */ + testcase( i==97 ); /* TO */ + testcase( i==98 ); /* IN */ + testcase( i==99 ); /* CAST */ + testcase( i==100 ); /* COLUMN */ + testcase( i==101 ); /* COMMIT */ + testcase( i==102 ); /* CONFLICT */ + testcase( i==103 ); /* CROSS */ + testcase( i==104 ); /* CURRENT_TIMESTAMP */ + testcase( i==105 ); /* CURRENT_TIME */ + testcase( i==106 ); /* CURRENT */ + testcase( i==107 ); /* PARTITION */ + testcase( i==108 ); /* DEFERRED */ + testcase( i==109 ); /* DISTINCT */ + testcase( i==110 ); /* IS */ + testcase( i==111 ); /* DROP */ + testcase( i==112 ); /* PRECEDING */ + testcase( i==113 ); /* FAIL */ + testcase( i==114 ); /* FILTER */ + testcase( i==115 ); /* REPLACE */ + testcase( i==116 ); /* FOLLOWING */ + testcase( i==117 ); /* FROM */ + testcase( i==118 ); /* FULL */ + testcase( i==119 ); /* IF */ + testcase( i==120 ); /* ISNULL */ + testcase( i==121 ); /* ORDER */ + testcase( i==122 ); /* RESTRICT */ + testcase( i==123 ); /* OTHERS */ + testcase( i==124 ); /* OVER */ + testcase( i==125 ); /* RIGHT */ + testcase( i==126 ); /* ROLLBACK */ + testcase( i==127 ); /* ROWS */ + testcase( i==128 ); /* ROW */ + testcase( i==129 ); /* UNBOUNDED */ + testcase( i==130 ); /* UNION */ + testcase( i==131 ); /* USING */ + testcase( i==132 ); /* VACUUM */ + testcase( i==133 ); /* VIEW */ + testcase( i==134 ); /* WINDOW */ + testcase( i==135 ); /* DO */ + testcase( i==136 ); /* BY */ + testcase( i==137 ); /* INITIALLY */ + testcase( i==138 ); /* ALL */ + testcase( i==139 ); /* PRIMARY */ *pType = aKWCode[i]; break; } @@ -150785,7 +154075,7 @@ SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){ keywordCode((char*)z, n, &id); return id; } -#define SQLITE_N_KEYWORD 136 +#define SQLITE_N_KEYWORD 140 SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){ if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR; *pzName = zKWText + aKWOffset[i]; @@ -151218,6 +154508,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr #ifdef sqlite3Parser_ENGINEALWAYSONSTACK yyParser sEngine; /* Space to hold the Lemon-generated Parser object */ #endif + VVA_ONLY( u8 startedWithOom = db->mallocFailed ); assert( zSql!=0 ); mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; @@ -151227,7 +154518,14 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr pParse->rc = SQLITE_OK; pParse->zTail = zSql; assert( pzErrMsg!=0 ); - /* sqlite3ParserTrace(stdout, "parser: "); */ +#ifdef SQLITE_DEBUG + if( db->flags & SQLITE_ParserTrace ){ + printf("parser: [[[%s]]]\n", zSql); + sqlite3ParserTrace(stdout, "parser: "); + }else{ + sqlite3ParserTrace(0, 0); + } +#endif #ifdef sqlite3Parser_ENGINEALWAYSONSTACK pEngine = &sEngine; sqlite3ParserInit(pEngine, pParse); @@ -151242,6 +154540,8 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); assert( pParse->pVList==0 ); + pParse->pParentParse = db->pParse; + db->pParse = pParse; while( 1 ){ n = sqlite3GetToken((u8*)zSql, &tokenType); mxSqlLen -= n; @@ -151298,7 +154598,8 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr sqlite3Parser(pEngine, tokenType, pParse->sLastToken); lastTokenParsed = tokenType; zSql += n; - if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break; + assert( db->mallocFailed==0 || pParse->rc!=SQLITE_OK || startedWithOom ); + if( pParse->rc!=SQLITE_OK ) break; } assert( nErr==0 ); #ifdef YYTRACKMAXSTACKDEPTH @@ -151366,10 +154667,147 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr pParse->pZombieTab = p->pNextZombie; sqlite3DeleteTable(db, p); } + db->pParse = pParse->pParentParse; + pParse->pParentParse = 0; assert( nErr==0 || pParse->rc!=SQLITE_OK ); return nErr; } + +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Insert a single space character into pStr if the current string +** ends with an identifier +*/ +static void addSpaceSeparator(sqlite3_str *pStr){ + if( pStr->nChar && sqlite3IsIdChar(pStr->zText[pStr->nChar-1]) ){ + sqlite3_str_append(pStr, " ", 1); + } +} + +/* +** Compute a normalization of the SQL given by zSql[0..nSql-1]. Return +** the normalization in space obtained from sqlite3DbMalloc(). Or return +** NULL if anything goes wrong or if zSql is NULL. +*/ +SQLITE_PRIVATE char *sqlite3Normalize( + Vdbe *pVdbe, /* VM being reprepared */ + const char *zSql /* The original SQL string */ +){ + sqlite3 *db; /* The database connection */ + int i; /* Next unread byte of zSql[] */ + int n; /* length of current token */ + int tokenType; /* type of current token */ + int prevType = 0; /* Previous non-whitespace token */ + int nParen; /* Number of nested levels of parentheses */ + int iStartIN; /* Start of RHS of IN operator in z[] */ + int nParenAtIN; /* Value of nParent at start of RHS of IN operator */ + int j; /* Bytes of normalized SQL generated so far */ + sqlite3_str *pStr; /* The normalized SQL string under construction */ + + db = sqlite3VdbeDb(pVdbe); + tokenType = -1; + nParen = iStartIN = nParenAtIN = 0; + pStr = sqlite3_str_new(db); + assert( pStr!=0 ); /* sqlite3_str_new() never returns NULL */ + for(i=0; zSql[i] && pStr->accError==0; i+=n){ + if( tokenType!=TK_SPACE ){ + prevType = tokenType; + } + n = sqlite3GetToken((unsigned char*)zSql+i, &tokenType); + if( NEVER(n<=0) ) break; + switch( tokenType ){ + case TK_SPACE: { + break; + } + case TK_NULL: { + if( prevType==TK_IS || prevType==TK_NOT ){ + sqlite3_str_append(pStr, " NULL", 5); + break; + } + /* Fall through */ + } + case TK_STRING: + case TK_INTEGER: + case TK_FLOAT: + case TK_VARIABLE: + case TK_BLOB: { + sqlite3_str_append(pStr, "?", 1); + break; + } + case TK_LP: { + nParen++; + if( prevType==TK_IN ){ + iStartIN = pStr->nChar; + nParenAtIN = nParen; + } + sqlite3_str_append(pStr, "(", 1); + break; + } + case TK_RP: { + if( iStartIN>0 && nParen==nParenAtIN ){ + assert( pStr->nChar>=iStartIN ); + pStr->nChar = iStartIN+1; + sqlite3_str_append(pStr, "?,?,?", 5); + iStartIN = 0; + } + nParen--; + sqlite3_str_append(pStr, ")", 1); + break; + } + case TK_ID: { + iStartIN = 0; + j = pStr->nChar; + if( sqlite3Isquote(zSql[i]) ){ + char *zId = sqlite3DbStrNDup(db, zSql+i, n); + int nId; + int eType = 0; + if( zId==0 ) break; + sqlite3Dequote(zId); + if( zSql[i]=='"' && sqlite3VdbeUsesDoubleQuotedString(pVdbe, zId) ){ + sqlite3_str_append(pStr, "?", 1); + sqlite3DbFree(db, zId); + break; + } + nId = sqlite3Strlen30(zId); + if( sqlite3GetToken((u8*)zId, &eType)==nId && eType==TK_ID ){ + addSpaceSeparator(pStr); + sqlite3_str_append(pStr, zId, nId); + }else{ + sqlite3_str_appendf(pStr, "\"%w\"", zId); + } + sqlite3DbFree(db, zId); + }else{ + addSpaceSeparator(pStr); + sqlite3_str_append(pStr, zSql+i, n); + } + while( jnChar ){ + pStr->zText[j] = sqlite3Tolower(pStr->zText[j]); + j++; + } + break; + } + case TK_SELECT: { + iStartIN = 0; + /* fall through */ + } + default: { + if( sqlite3IsIdChar(zSql[i]) ) addSpaceSeparator(pStr); + j = pStr->nChar; + sqlite3_str_append(pStr, zSql+i, n); + while( jnChar ){ + pStr->zText[j] = sqlite3Toupper(pStr->zText[j]); + j++; + } + break; + } + } + } + if( tokenType!=TK_SEMI ) sqlite3_str_append(pStr, ";", 1); + return sqlite3_str_finish(pStr); +} +#endif /* SQLITE_ENABLE_NORMALIZE */ + /************** End of tokenize.c ********************************************/ /************** Begin file complete.c ****************************************/ /* @@ -152415,6 +155853,13 @@ SQLITE_API int sqlite3_config(int op, ...){ } #endif /* SQLITE_ENABLE_SORTER_REFERENCES */ +#ifdef SQLITE_ENABLE_DESERIALIZE + case SQLITE_CONFIG_MEMDB_MAXSIZE: { + sqlite3GlobalConfig.mxMemdbSize = va_arg(ap, sqlite3_int64); + break; + } +#endif /* SQLITE_ENABLE_DESERIALIZE */ + default: { rc = SQLITE_ERROR; break; @@ -152460,7 +155905,7 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ pStart = 0; }else if( pBuf==0 ){ sqlite3BeginBenignMalloc(); - pStart = sqlite3Malloc( sz*cnt ); /* IMP: R-61949-35727 */ + pStart = sqlite3Malloc( sz*(sqlite3_int64)cnt ); /* IMP: R-61949-35727 */ sqlite3EndBenignMalloc(); if( pStart ) cnt = sqlite3MallocSize(pStart)/sz; }else{ @@ -152597,6 +156042,12 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG }, { SQLITE_DBCONFIG_TRIGGER_EQP, SQLITE_TriggerEQP }, { SQLITE_DBCONFIG_RESET_DATABASE, SQLITE_ResetDatabase }, + { SQLITE_DBCONFIG_DEFENSIVE, SQLITE_Defensive }, + { SQLITE_DBCONFIG_WRITABLE_SCHEMA, SQLITE_WriteSchema| + SQLITE_NoSchemaError }, + { SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, SQLITE_LegacyAlter }, + { SQLITE_DBCONFIG_DQS_DDL, SQLITE_DqsDDL }, + { SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML }, }; unsigned int i; rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ @@ -152604,11 +156055,11 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ if( aFlagOp[i].op==op ){ int onoff = va_arg(ap, int); int *pRes = va_arg(ap, int*); - u32 oldFlags = db->flags; + u64 oldFlags = db->flags; if( onoff>0 ){ db->flags |= aFlagOp[i].mask; }else if( onoff==0 ){ - db->flags &= ~aFlagOp[i].mask; + db->flags &= ~(u64)aFlagOp[i].mask; } if( oldFlags!=db->flags ){ sqlite3ExpirePreparedStatements(db, 0); @@ -152627,28 +156078,17 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ return rc; } - -/* -** Return true if the buffer z[0..n-1] contains all spaces. -*/ -static int allSpaces(const char *z, int n){ - while( n>0 && z[n-1]==' ' ){ n--; } - return n==0; -} - /* ** This is the default collating function named "BINARY" which is always ** available. -** -** If the padFlag argument is not NULL then space padding at the end -** of strings is ignored. This implements the RTRIM collation. */ static int binCollFunc( - void *padFlag, + void *NotUsed, int nKey1, const void *pKey1, int nKey2, const void *pKey2 ){ int rc, n; + UNUSED_PARAMETER(NotUsed); n = nKey1xCmp!=binCollFunc || p->pUser!=0 - || strcmp(p->zName,"BINARY")==0 ); - return p==0 || (p->xCmp==binCollFunc && p->pUser==0); + assert( p==0 || p->xCmp!=binCollFunc || strcmp(p->zName,"BINARY")==0 ); + return p==0 || p->xCmp==binCollFunc; } /* @@ -153071,7 +156515,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ /* Any deferred constraint violations have now been resolved. */ db->nDeferredCons = 0; db->nDeferredImmCons = 0; - db->flags &= ~SQLITE_DeferFKs; + db->flags &= ~(u64)SQLITE_DeferFKs; /* If one has been configured, invoke the rollback-hook callback */ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ @@ -153813,6 +157257,8 @@ SQLITE_API void *sqlite3_profile( pOld = db->pProfileArg; db->xProfile = xProfile; db->pProfileArg = pArg; + db->mTrace &= SQLITE_TRACE_NONLEGACY_MASK; + if( db->xProfile ) db->mTrace |= SQLITE_TRACE_XPROFILE; sqlite3_mutex_leave(db->mutex); return pOld; } @@ -154164,7 +157610,7 @@ SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){ z = sqlite3ErrStr(SQLITE_NOMEM_BKPT); }else{ testcase( db->pErr==0 ); - z = (char*)sqlite3_value_text(db->pErr); + z = db->errCode ? (char*)sqlite3_value_text(db->pErr) : 0; assert( !db->mallocFailed ); if( z==0 ){ z = sqlite3ErrStr(db->errCode); @@ -154694,6 +158140,40 @@ SQLITE_PRIVATE int sqlite3ParseUri( return rc; } +#if defined(SQLITE_HAS_CODEC) +/* +** Process URI filename query parameters relevant to the SQLite Encryption +** Extension. Return true if any of the relevant query parameters are +** seen and return false if not. +*/ +SQLITE_PRIVATE int sqlite3CodecQueryParameters( + sqlite3 *db, /* Database connection */ + const char *zDb, /* Which schema is being created/attached */ + const char *zUri /* URI filename */ +){ + const char *zKey; + if( (zKey = sqlite3_uri_parameter(zUri, "hexkey"))!=0 && zKey[0] ){ + u8 iByte; + int i; + char zDecoded[40]; + for(i=0, iByte=0; iszMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; db->nMaxSorterMmap = 0x7FFFFFFF; - db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill + db->flags |= SQLITE_ShortColNames + | SQLITE_EnableTrigger + | SQLITE_CacheSpill + +/* The SQLITE_DQS compile-time option determines the default settings +** for SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML. +** +** SQLITE_DQS SQLITE_DBCONFIG_DQS_DDL SQLITE_DBCONFIG_DQS_DML +** ---------- ----------------------- ----------------------- +** undefined on on +** 3 on on +** 2 on off +** 1 off on +** 0 off off +** +** Legacy behavior is 3 (double-quoted string literals are allowed anywhere) +** and so that is the default. But developers are encouranged to use +** -DSQLITE_DQS=0 (best) or -DSQLITE_DQS=1 (second choice) if possible. +*/ +#if !defined(SQLITE_DQS) +# define SQLITE_DQS 3 +#endif +#if (SQLITE_DQS&1)==1 + | SQLITE_DqsDML +#endif +#if (SQLITE_DQS&2)==2 + | SQLITE_DqsDDL +#endif + #if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX | SQLITE_AutoIndex #endif @@ -154823,6 +158331,9 @@ static int openDatabase( #endif #if defined(SQLITE_ENABLE_QPSG) | SQLITE_EnableQPSG +#endif +#if defined(SQLITE_DEFAULT_DEFENSIVE) + | SQLITE_Defensive #endif ; sqlite3HashInit(&db->aCollSeq); @@ -154841,7 +158352,7 @@ static int openDatabase( createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0); createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0); createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); - createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0); + createCollation(db, "RTRIM", SQLITE_UTF8, 0, rtrimCollFunc, 0); if( db->mallocFailed ){ goto opendb_out; } @@ -155036,26 +158547,13 @@ static int openDatabase( } #endif #if defined(SQLITE_HAS_CODEC) - if( rc==SQLITE_OK ){ - const char *zKey; - if( (zKey = sqlite3_uri_parameter(zOpen, "hexkey"))!=0 && zKey[0] ){ - u8 iByte; - int i; - char zDecoded[40]; - for(i=0, iByte=0; i=0 ); return 5; @@ -157901,13 +161449,18 @@ static int fts3DestroyMethod(sqlite3_vtab *pVtab){ sqlite3 *db = p->db; /* Database handle */ /* Drop the shadow tables */ - if( p->zContentTbl==0 ){ - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName); - } - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName); - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName); - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName); - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName); + fts3DbExec(&rc, db, + "DROP TABLE IF EXISTS %Q.'%q_segments';" + "DROP TABLE IF EXISTS %Q.'%q_segdir';" + "DROP TABLE IF EXISTS %Q.'%q_docsize';" + "DROP TABLE IF EXISTS %Q.'%q_stat';" + "%s DROP TABLE IF EXISTS %Q.'%q_content';", + zDb, p->zName, + zDb, p->zName, + zDb, p->zName, + zDb, p->zName, + (p->zContentTbl ? "--" : ""), zDb,p->zName + ); /* If everything has worked, invoke fts3DisconnectMethod() to free the ** memory associated with the Fts3Table structure and return SQLITE_OK. @@ -158139,10 +161692,10 @@ static void fts3Appendf( ** memory. */ static char *fts3QuoteId(char const *zInput){ - int nRet; + sqlite3_int64 nRet; char *zRet; nRet = 2 + (int)strlen(zInput)*2 + 1; - zRet = sqlite3_malloc(nRet); + zRet = sqlite3_malloc64(nRet); if( zRet ){ int i; char *z = zRet; @@ -158323,7 +161876,7 @@ static int fts3PrefixParameter( } } - aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex); + aIndex = sqlite3_malloc64(sizeof(struct Fts3Index) * nIndex); *apIndex = aIndex; if( !aIndex ){ return SQLITE_NOMEM; @@ -158402,7 +161955,7 @@ static int fts3ContentColumns( if( rc==SQLITE_OK ){ const char **azCol; /* Output array */ - int nStr = 0; /* Size of all column names (incl. 0x00) */ + sqlite3_int64 nStr = 0; /* Size of all column names (incl. 0x00) */ int nCol; /* Number of table columns */ int i; /* Used to iterate through columns */ @@ -158412,11 +161965,11 @@ static int fts3ContentColumns( nCol = sqlite3_column_count(pStmt); for(i=0; i=0 && nSuffix>=0 ); - if( &zCsr[nSuffix]>zEnd ){ + if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr || nSuffix==0 ){ rc = FTS_CORRUPT_VTAB; goto finish_scan; } - if( nPrefix+nSuffix>nAlloc ){ + if( (i64)nPrefix+nSuffix>nAlloc ){ char *zNew; - nAlloc = (nPrefix+nSuffix) * 2; - zNew = (char *)sqlite3_realloc(zBuffer, nAlloc); + nAlloc = ((i64)nPrefix+nSuffix) * 2; + zNew = (char *)sqlite3_realloc64(zBuffer, nAlloc); if( !zNew ){ rc = SQLITE_NOMEM; goto finish_scan; @@ -159475,7 +163028,7 @@ static int fts3PutColNumber(char **pp, int iCol){ ** updated appropriately. The caller is responsible for insuring ** that there is enough space in *pp to hold the complete output. */ -static void fts3PoslistMerge( +static int fts3PoslistMerge( char **pp, /* Output buffer */ char **pp1, /* Left input list */ char **pp2 /* Right input list */ @@ -159488,11 +163041,17 @@ static void fts3PoslistMerge( int iCol1; /* The current column index in pp1 */ int iCol2; /* The current column index in pp2 */ - if( *p1==POS_COLUMN ) fts3GetVarint32(&p1[1], &iCol1); + if( *p1==POS_COLUMN ){ + fts3GetVarint32(&p1[1], &iCol1); + if( iCol1==0 ) return FTS_CORRUPT_VTAB; + } else if( *p1==POS_END ) iCol1 = POSITION_LIST_END; else iCol1 = 0; - if( *p2==POS_COLUMN ) fts3GetVarint32(&p2[1], &iCol2); + if( *p2==POS_COLUMN ){ + fts3GetVarint32(&p2[1], &iCol2); + if( iCol2==0 ) return FTS_CORRUPT_VTAB; + } else if( *p2==POS_END ) iCol2 = POSITION_LIST_END; else iCol2 = 0; @@ -159540,6 +163099,7 @@ static void fts3PoslistMerge( *pp = p; *pp1 = p1 + 1; *pp2 = p2 + 1; + return SQLITE_OK; } /* @@ -159604,10 +163164,9 @@ static int fts3PoslistPhraseMerge( p += sqlite3Fts3PutVarint(p, iCol1); } - assert( *p1!=POS_END && *p1!=POS_COLUMN ); - assert( *p2!=POS_END && *p2!=POS_COLUMN ); fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2; fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; + if( iPos1<0 || iPos2<0 ) break; while( 1 ){ if( iPos2==iPos1+nToken @@ -159833,6 +163392,7 @@ static int fts3DoclistOrMerge( char *a2, int n2, /* Second doclist */ char **paOut, int *pnOut /* OUT: Malloc'd doclist */ ){ + int rc = SQLITE_OK; sqlite3_int64 i1 = 0; sqlite3_int64 i2 = 0; sqlite3_int64 iPrev = 0; @@ -159876,7 +163436,7 @@ static int fts3DoclistOrMerge( ** A symetric argument may be made if the doclists are in descending ** order. */ - aOut = sqlite3_malloc(n1+n2+FTS3_VARINT_MAX-1); + aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING); if( !aOut ) return SQLITE_NOMEM; p = aOut; @@ -159887,7 +163447,8 @@ static int fts3DoclistOrMerge( if( p2 && p1 && iDiff==0 ){ fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); - fts3PoslistMerge(&p, &p1, &p2); + rc = fts3PoslistMerge(&p, &p1, &p2); + if( rc ) break; fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); }else if( !p2 || (p1 && iDiff<0) ){ @@ -159901,10 +163462,16 @@ static int fts3DoclistOrMerge( } } + if( rc!=SQLITE_OK ){ + sqlite3_free(aOut); + p = aOut = 0; + }else{ + assert( (p-aOut)<=n1+n2+FTS3_VARINT_MAX-1 ); + memset(&aOut[(p-aOut)], 0, FTS3_BUFFER_PADDING); + } *paOut = aOut; *pnOut = (int)(p-aOut); - assert( *pnOut<=n1+n2+FTS3_VARINT_MAX-1 ); - return SQLITE_OK; + return rc; } /* @@ -159939,7 +163506,7 @@ static int fts3DoclistPhraseMerge( assert( nDist>0 ); if( bDescDoclist ){ - aOut = sqlite3_malloc(*pnRight + FTS3_VARINT_MAX); + aOut = sqlite3_malloc64((sqlite3_int64)*pnRight + FTS3_VARINT_MAX); if( aOut==0 ) return SQLITE_NOMEM; }else{ aOut = aRight; @@ -160123,6 +163690,7 @@ static int fts3TermSelectMerge( pTS->anOutput[0] = nDoclist; if( pTS->aaOutput[0] ){ memcpy(pTS->aaOutput[0], aDoclist, nDoclist); + memset(&pTS->aaOutput[0][nDoclist], 0, FTS3_VARINT_MAX); }else{ return SQLITE_NOMEM; } @@ -160174,8 +163742,8 @@ static int fts3SegReaderCursorAppend( ){ if( (pCsr->nSegment%16)==0 ){ Fts3SegReader **apNew; - int nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*); - apNew = (Fts3SegReader **)sqlite3_realloc(pCsr->apSegment, nByte); + sqlite3_int64 nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*); + apNew = (Fts3SegReader **)sqlite3_realloc64(pCsr->apSegment, nByte); if( !apNew ){ sqlite3Fts3SegReaderFree(pNew); return SQLITE_NOMEM; @@ -160239,7 +163807,7 @@ static int fts3SegReaderCursor( /* If zTerm is not NULL, and this segment is not stored entirely on its ** root node, the range of leaves scanned can be reduced. Do this. */ - if( iStartBlock && zTerm ){ + if( iStartBlock && zTerm && zRoot ){ sqlite3_int64 *pi = (isPrefix ? &iLeavesEndBlock : 0); rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &iStartBlock, pi); if( rc!=SQLITE_OK ) goto finished; @@ -161181,14 +164749,28 @@ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts3Table *p = (Fts3Table*)pVtab; UNUSED_PARAMETER(iSavepoint); assert( p->inTransaction ); - assert( p->mxSavepoint >= iSavepoint ); TESTONLY( p->mxSavepoint = iSavepoint ); sqlite3Fts3PendingTermsClear(p); return SQLITE_OK; } +/* +** Return true if zName is the extension on one of the shadow tables used +** by this module. +*/ +static int fts3ShadowName(const char *zName){ + static const char *azName[] = { + "content", "docsize", "segdir", "segments", "stat", + }; + unsigned int i; + for(i=0; inToken-1].nList; - char *aDoclist = sqlite3_malloc(nByte+1); + char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING); if( !aDoclist ) return SQLITE_NOMEM; memcpy(aDoclist, a[p->nToken-1].pList, nByte+1); + memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING); for(i=0; i<(p->nToken-1); i++){ if( a[i].bIgnore==0 ){ @@ -162331,7 +165917,7 @@ static int fts3EvalStart(Fts3Cursor *pCsr){ if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){ Fts3TokenAndCost *aTC; Fts3Expr **apOr; - aTC = (Fts3TokenAndCost *)sqlite3_malloc( + aTC = (Fts3TokenAndCost *)sqlite3_malloc64( sizeof(Fts3TokenAndCost) * nToken + sizeof(Fts3Expr *) * nOr * 2 ); @@ -162642,7 +166228,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) ){ Fts3Expr *p; - int nTmp = 0; /* Bytes of temp space */ + sqlite3_int64 nTmp = 0; /* Bytes of temp space */ char *aTmp; /* Temp space for PoslistNearMerge() */ /* Allocate temporary working space. */ @@ -162651,7 +166237,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ nTmp += p->pRight->pPhrase->doclist.nList; } nTmp += p->pPhrase->doclist.nList; - aTmp = sqlite3_malloc(nTmp*2); + aTmp = sqlite3_malloc64(nTmp*2); if( !aTmp ){ *pRc = SQLITE_NOMEM; res = 0; @@ -162921,15 +166507,14 @@ static void fts3EvalRestart( ** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase ** expression nodes. */ -static void fts3EvalUpdateCounts(Fts3Expr *pExpr){ +static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){ if( pExpr ){ Fts3Phrase *pPhrase = pExpr->pPhrase; if( pPhrase && pPhrase->doclist.pList ){ int iCol = 0; char *p = pPhrase->doclist.pList; - assert( *p ); - while( 1 ){ + do{ u8 c = 0; int iCnt = 0; while( 0xFE & (*p | c) ){ @@ -162945,11 +166530,11 @@ static void fts3EvalUpdateCounts(Fts3Expr *pExpr){ if( *p==0x00 ) break; p++; p += fts3GetVarint32(p, &iCol); - } + }while( iColpLeft); - fts3EvalUpdateCounts(pExpr->pRight); + fts3EvalUpdateCounts(pExpr->pLeft, nCol); + fts3EvalUpdateCounts(pExpr->pRight, nCol); } } @@ -162993,7 +166578,7 @@ static int fts3EvalGatherStats( for(p=pRoot; p; p=p->pLeft){ Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight); assert( pE->aMI==0 ); - pE->aMI = (u32 *)sqlite3_malloc(pTab->nColumn * 3 * sizeof(u32)); + pE->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32)); if( !pE->aMI ) return SQLITE_NOMEM; memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32)); } @@ -163019,7 +166604,7 @@ static int fts3EvalGatherStats( ); if( rc==SQLITE_OK && pCsr->isEof==0 ){ - fts3EvalUpdateCounts(pRoot); + fts3EvalUpdateCounts(pRoot, pTab->nColumn); } } @@ -163369,7 +166954,7 @@ static int fts3auxConnectMethod( char const *zFts3; /* Name of fts3 table */ int nDb; /* Result of strlen(zDb) */ int nFts3; /* Result of strlen(zFts3) */ - int nByte; /* Bytes of space to allocate here */ + sqlite3_int64 nByte; /* Bytes of space to allocate here */ int rc; /* value returned by declare_vtab() */ Fts3auxTable *p; /* Virtual table object to return */ @@ -163401,7 +166986,7 @@ static int fts3auxConnectMethod( if( rc!=SQLITE_OK ) return rc; nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; - p = (Fts3auxTable *)sqlite3_malloc(nByte); + p = (Fts3auxTable *)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, nByte); @@ -163551,7 +167136,7 @@ static int fts3auxCloseMethod(sqlite3_vtab_cursor *pCursor){ static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){ if( nSize>pCsr->nStat ){ struct Fts3auxColstats *aNew; - aNew = (struct Fts3auxColstats *)sqlite3_realloc(pCsr->aStat, + aNew = (struct Fts3auxColstats *)sqlite3_realloc64(pCsr->aStat, sizeof(struct Fts3auxColstats) * nSize ); if( aNew==0 ) return SQLITE_NOMEM; @@ -163719,15 +167304,15 @@ static int fts3auxFilterMethod( assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) ); if( zStr ){ pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr); - pCsr->filter.nTerm = sqlite3_value_bytes(apVal[0]); if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM; + pCsr->filter.nTerm = (int)strlen(pCsr->filter.zTerm); } } if( iLe>=0 ){ pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe])); - pCsr->nStop = sqlite3_value_bytes(apVal[iLe]); if( pCsr->zStop==0 ) return SQLITE_NOMEM; + pCsr->nStop = (int)strlen(pCsr->zStop); } if( iLangid>=0 ){ @@ -163842,7 +167427,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; int rc; /* Return code */ @@ -163978,8 +167564,8 @@ static int fts3isspace(char c){ ** zero the memory before returning a pointer to it. If unsuccessful, ** return NULL. */ -static void *fts3MallocZero(int nByte){ - void *pRet = sqlite3_malloc(nByte); +static void *fts3MallocZero(sqlite3_int64 nByte){ + void *pRet = sqlite3_malloc64(nByte); if( pRet ) memset(pRet, 0, nByte); return pRet; } @@ -164054,7 +167640,7 @@ static int getNextToken( if( rc==SQLITE_OK ){ const char *zToken; int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; - int nByte; /* total space to allocate */ + sqlite3_int64 nByte; /* total space to allocate */ rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); if( rc==SQLITE_OK ){ @@ -164108,8 +167694,8 @@ static int getNextToken( ** Enlarge a memory allocation. If an out-of-memory allocation occurs, ** then free the old allocation. */ -static void *fts3ReallocOrFree(void *pOrig, int nNew){ - void *pRet = sqlite3_realloc(pOrig, nNew); +static void *fts3ReallocOrFree(void *pOrig, sqlite3_int64 nNew){ + void *pRet = sqlite3_realloc64(pOrig, nNew); if( !pRet ){ sqlite3_free(pOrig); } @@ -164353,7 +167939,6 @@ static int getNextNode( int nConsumed = 0; pParse->nNest++; rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed); - if( rc==SQLITE_OK && !*ppExpr ){ rc = SQLITE_DONE; } *pnConsumed = (int)(zInput - z) + 1 + nConsumed; return rc; }else if( *zInput==')' ){ @@ -164652,7 +168237,7 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){ if( rc==SQLITE_OK ){ if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){ Fts3Expr **apLeaf; - apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth); + apLeaf = (Fts3Expr **)sqlite3_malloc64(sizeof(Fts3Expr *) * nMaxDepth); if( 0==apLeaf ){ rc = SQLITE_NOMEM; }else{ @@ -165072,7 +168657,7 @@ static void fts3ExprTestCommon( zExpr = (const char *)sqlite3_value_text(argv[1]); nExpr = sqlite3_value_bytes(argv[1]); nCol = argc-2; - azCol = (char **)sqlite3_malloc(nCol*sizeof(char *)); + azCol = (char **)sqlite3_malloc64(nCol*sizeof(char *)); if( !azCol ){ sqlite3_result_error_nomem(context); goto exprtest_out; @@ -165186,8 +168771,8 @@ SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash *pHash /* ** Malloc and Free functions */ -static void *fts3HashMalloc(int n){ - void *p = sqlite3_malloc(n); +static void *fts3HashMalloc(sqlite3_int64 n){ + void *p = sqlite3_malloc64(n); if( p ){ memset(p, 0, n); } @@ -166281,7 +169866,7 @@ static void fts3TokenizerFunc( nName = sqlite3_value_bytes(argv[0])+1; if( argc==2 ){ - if( fts3TokenizerEnabled(context) ){ + if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[1]) ){ void *pOld; int n = sqlite3_value_bytes(argv[1]); if( zName==0 || n!=sizeof(pPtr) ){ @@ -166308,7 +169893,9 @@ static void fts3TokenizerFunc( return; } } - sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); + if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[0]) ){ + sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); + } } SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char c){ @@ -166396,8 +169983,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer( int iArg = 0; z = &z[n+1]; while( zzInput = sqlite3_malloc(nByte+1); + pCsr->zInput = sqlite3_malloc64(nByte+1); if( pCsr->zInput==0 ){ rc = SQLITE_NOMEM; }else{ @@ -167401,7 +170988,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; int rc; /* Return code */ @@ -167811,10 +171399,12 @@ static int fts3SqlStmt( pStmt = p->aStmt[eStmt]; if( !pStmt ){ + int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB; char *zSql; if( eStmt==SQL_CONTENT_INSERT ){ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ + f &= ~SQLITE_PREPARE_NO_VTAB; zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); }else{ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); @@ -167822,8 +171412,7 @@ static int fts3SqlStmt( if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v3(p->db, zSql, -1, SQLITE_PREPARE_PERSISTENT, - &pStmt, NULL); + rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL); sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); p->aStmt[eStmt] = pStmt; @@ -167981,7 +171570,7 @@ static sqlite3_int64 getAbsoluteLevel( int iLevel /* Level of segments */ ){ sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */ - assert( iLangid>=0 ); + assert_fts3_nc( iLangid>=0 ); assert( p->nIndex>0 ); assert( iIndex>=0 && iIndexnIndex ); @@ -168762,7 +172351,9 @@ static int fts3SegReaderNext( /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf ** blocks have already been traversed. */ - assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock ); +#ifdef CORRUPT_DB + assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock || CORRUPT_DB ); +#endif if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){ return SQLITE_OK; } @@ -168789,15 +172380,19 @@ static int fts3SegReaderNext( ** safe (no risk of overread) even if the node data is corrupted. */ pNext += fts3GetVarint32(pNext, &nPrefix); pNext += fts3GetVarint32(pNext, &nSuffix); - if( nPrefix<0 || nSuffix<=0 - || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] + if( nSuffix<=0 + || (&pReader->aNode[pReader->nNode] - pNext)pReader->nTermAlloc ){ return FTS_CORRUPT_VTAB; } - if( nPrefix+nSuffix>pReader->nTermAlloc ){ - int nNew = (nPrefix+nSuffix)*2; - char *zNew = sqlite3_realloc(pReader->zTerm, nNew); + /* Both nPrefix and nSuffix were read by fts3GetVarint32() and so are + ** between 0 and 0x7FFFFFFF. But the sum of the two may cause integer + ** overflow - hence the (i64) casts. */ + if( (i64)nPrefix+nSuffix>(i64)pReader->nTermAlloc ){ + i64 nNew = ((i64)nPrefix+nSuffix)*2; + char *zNew = sqlite3_realloc64(pReader->zTerm, nNew); if( !zNew ){ return SQLITE_NOMEM; } @@ -168819,7 +172414,7 @@ static int fts3SegReaderNext( ** b-tree node. And that the final byte of the doclist is 0x00. If either ** of these statements is untrue, then the data structure is corrupt. */ - if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] + if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode) || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1]) ){ return FTS_CORRUPT_VTAB; @@ -169019,8 +172614,13 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew( Fts3SegReader *pReader; /* Newly allocated SegReader object */ int nExtra = 0; /* Bytes to allocate segment root node */ - assert( iStartLeaf<=iEndLeaf ); + assert( zRoot!=0 || nRoot==0 ); +#ifdef CORRUPT_DB + assert( zRoot!=0 || CORRUPT_DB ); +#endif + if( iStartLeaf==0 ){ + if( iEndLeaf!=0 ) return FTS_CORRUPT_VTAB; nExtra = nRoot + FTS3_NODE_PADDING; } @@ -169040,7 +172640,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew( pReader->aNode = (char *)&pReader[1]; pReader->rootOnly = 1; pReader->nNode = nRoot; - memcpy(pReader->aNode, zRoot, nRoot); + if( nRoot ) memcpy(pReader->aNode, zRoot, nRoot); memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING); }else{ pReader->iCurrentBlock = iStartLeaf-1; @@ -169155,8 +172755,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending( } if( nElem>0 ){ - int nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *); - pReader = (Fts3SegReader *)sqlite3_malloc(nByte); + sqlite3_int64 nByte; + nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *); + pReader = (Fts3SegReader *)sqlite3_malloc64(nByte); if( !pReader ){ rc = SQLITE_NOMEM; }else{ @@ -169660,6 +173261,11 @@ static int fts3SegWriterAdd( nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm); nSuffix = nTerm-nPrefix; + /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of + ** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when + ** compared with BINARY collation. This indicates corruption. */ + if( nSuffix<=0 ) return FTS_CORRUPT_VTAB; + /* Figure out how many bytes are required by this new entry */ nReq = sqlite3Fts3VarintLen(nPrefix) + /* varint containing prefix size */ sqlite3Fts3VarintLen(nSuffix) + /* varint containing suffix size */ @@ -170016,14 +173622,14 @@ static void fts3ColumnFilter( nList -= (int)(p - pList); pList = p; - if( nList==0 ){ + if( nList<=0 ){ break; } p = &pList[1]; p += fts3GetVarint32(p, &iCurrent); } - if( bZero && &pList[nList]!=pEnd ){ + if( bZero && (pEnd - &pList[nList])>0){ memset(&pList[nList], 0, pEnd - &pList[nList]); } *ppList = pList; @@ -170367,7 +173973,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep( }else{ iDelta = iDocid - iPrev; } - assert( iDelta>0 || (nDoclist==0 && iDelta==iDocid) ); + if( iDelta<=0 && (nDoclist>0 || iDelta!=iDocid) ){ + return FTS_CORRUPT_VTAB; + } assert( nDoclist>0 || iDelta==iDocid ); nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0); @@ -170633,8 +174241,10 @@ static int fts3SegmentMerge( if( rc!=SQLITE_OK ) goto finished; assert( csr.nSegment>0 ); - assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) ); - assert( iNewLevel=getAbsoluteLevel(p, iLangid, iIndex, 0) ); + assert_fts3_nc( + iNewLevelnColumn ); + pBlob = sqlite3_malloc64( 10*(sqlite3_int64)p->nColumn ); if( pBlob==0 ){ *pRC = SQLITE_NOMEM; return; @@ -170809,7 +174421,7 @@ static void fts3UpdateDocTotals( const int nStat = p->nColumn+2; if( *pRC ) return; - a = sqlite3_malloc( (sizeof(u32)+10)*nStat ); + a = sqlite3_malloc64( (sizeof(u32)+10)*(sqlite3_int64)nStat ); if( a==0 ){ *pRC = SQLITE_NOMEM; return; @@ -170930,8 +174542,8 @@ static int fts3DoRebuild(Fts3Table *p){ } if( rc==SQLITE_OK ){ - int nByte = sizeof(u32) * (p->nColumn+1)*3; - aSz = (u32 *)sqlite3_malloc(nByte); + sqlite3_int64 nByte = sizeof(u32) * ((sqlite3_int64)p->nColumn+1)*3; + aSz = (u32 *)sqlite3_malloc64(nByte); if( aSz==0 ){ rc = SQLITE_NOMEM; }else{ @@ -170997,12 +174609,12 @@ static int fts3IncrmergeCsr( ){ int rc; /* Return Code */ sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */ - int nByte; /* Bytes allocated at pCsr->apSegment[] */ + sqlite3_int64 nByte; /* Bytes allocated at pCsr->apSegment[] */ /* Allocate space for the Fts3MultiSegReader.aCsr[] array */ memset(pCsr, 0, sizeof(*pCsr)); nByte = sizeof(Fts3SegReader *) * nSeg; - pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc(nByte); + pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc64(nByte); if( pCsr->apSegment==0 ){ rc = SQLITE_NOMEM; @@ -171145,6 +174757,9 @@ static int nodeReaderNext(NodeReader *p){ } p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix); + if( nPrefix>p->term.n || nSuffix>p->nNode-p->iOff || nSuffix==0 ){ + return FTS_CORRUPT_VTAB; + } blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc); if( rc==SQLITE_OK ){ memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix); @@ -171152,14 +174767,16 @@ static int nodeReaderNext(NodeReader *p){ p->iOff += nSuffix; if( p->iChild==0 ){ p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist); + if( (p->nNode-p->iOff)nDoclist ){ + return FTS_CORRUPT_VTAB; + } p->aDoclist = &p->aNode[p->iOff]; p->iOff += p->nDoclist; } } } - assert( p->iOff<=p->nNode ); - + assert_fts3_nc( p->iOff<=p->nNode ); return rc; } @@ -171320,7 +174937,7 @@ static int fts3AppendToNode( /* Node must have already been started. There must be a doclist for a ** leaf node, and there must not be a doclist for an internal node. */ assert( pNode->n>0 ); - assert( (pNode->a[0]=='\0')==(aDoclist!=0) ); + assert_fts3_nc( (pNode->a[0]=='\0')==(aDoclist!=0) ); blobGrowBuffer(pPrev, nTerm, &rc); if( rc!=SQLITE_OK ) return rc; @@ -171536,7 +175153,7 @@ static int fts3TermCmp( int nCmp = MIN(nLhs, nRhs); int res; - res = memcmp(zLhs, zRhs, nCmp); + res = (nCmp ? memcmp(zLhs, zRhs, nCmp) : 0); if( res==0 ) res = nLhs - nRhs; return res; @@ -171668,10 +175285,13 @@ static int fts3IncrmergeLoad( pNode = &pWriter->aNodeWriter[nHeight]; pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight; - blobGrowBuffer(&pNode->block, MAX(nRoot, p->nNodeSize), &rc); + blobGrowBuffer(&pNode->block, + MAX(nRoot, p->nNodeSize)+FTS3_NODE_PADDING, &rc + ); if( rc==SQLITE_OK ){ memcpy(pNode->block.a, aRoot, nRoot); pNode->block.n = nRoot; + memset(&pNode->block.a[nRoot], 0, FTS3_NODE_PADDING); } for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){ @@ -171679,23 +175299,28 @@ static int fts3IncrmergeLoad( pNode = &pWriter->aNodeWriter[i]; rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n); - while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader); - blobGrowBuffer(&pNode->key, reader.term.n, &rc); - if( rc==SQLITE_OK ){ - memcpy(pNode->key.a, reader.term.a, reader.term.n); - pNode->key.n = reader.term.n; - if( i>0 ){ - char *aBlock = 0; - int nBlock = 0; - pNode = &pWriter->aNodeWriter[i-1]; - pNode->iBlock = reader.iChild; - rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0); - blobGrowBuffer(&pNode->block, MAX(nBlock, p->nNodeSize), &rc); - if( rc==SQLITE_OK ){ - memcpy(pNode->block.a, aBlock, nBlock); - pNode->block.n = nBlock; + if( reader.aNode ){ + while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader); + blobGrowBuffer(&pNode->key, reader.term.n, &rc); + if( rc==SQLITE_OK ){ + memcpy(pNode->key.a, reader.term.a, reader.term.n); + pNode->key.n = reader.term.n; + if( i>0 ){ + char *aBlock = 0; + int nBlock = 0; + pNode = &pWriter->aNodeWriter[i-1]; + pNode->iBlock = reader.iChild; + rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0); + blobGrowBuffer(&pNode->block, + MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc + ); + if( rc==SQLITE_OK ){ + memcpy(pNode->block.a, aBlock, nBlock); + pNode->block.n = nBlock; + memset(&pNode->block.a[nBlock], 0, FTS3_NODE_PADDING); + } + sqlite3_free(aBlock); } - sqlite3_free(aBlock); } } nodeReaderRelease(&reader); @@ -171938,7 +175563,10 @@ static int fts3TruncateNode( NodeReader reader; /* Reader object */ Blob prev = {0, 0, 0}; /* Previous term written to new node */ int rc = SQLITE_OK; /* Return code */ - int bLeaf = aNode[0]=='\0'; /* True for a leaf node */ + int bLeaf; /* True for a leaf node */ + + if( nNode<1 ) return FTS_CORRUPT_VTAB; + bLeaf = aNode[0]=='\0'; /* Allocate required output space */ blobGrowBuffer(pNew, nNode, &rc); @@ -172977,7 +176605,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod( } /* Allocate space to hold the change in document sizes */ - aSzDel = sqlite3_malloc( sizeof(aSzDel[0])*(p->nColumn+1)*2 ); + aSzDel = sqlite3_malloc64(sizeof(aSzDel[0])*((sqlite3_int64)p->nColumn+1)*2); if( aSzDel==0 ){ rc = SQLITE_NOMEM; goto update_out; @@ -173231,17 +176859,19 @@ struct StrBuffer { /* ** Allocate a two-slot MatchinfoBuffer object. */ -static MatchinfoBuffer *fts3MIBufferNew(int nElem, const char *zMatchinfo){ +static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ MatchinfoBuffer *pRet; - int nByte = sizeof(u32) * (2*nElem + 1) + sizeof(MatchinfoBuffer); - int nStr = (int)strlen(zMatchinfo); + sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1) + + sizeof(MatchinfoBuffer); + sqlite3_int64 nStr = strlen(zMatchinfo); - pRet = sqlite3_malloc(nByte + nStr+1); + pRet = sqlite3_malloc64(nByte + nStr+1); if( pRet ){ memset(pRet, 0, nByte); pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; - pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*(nElem+1); - pRet->nElem = nElem; + pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + + sizeof(u32)*((int)nElem+1); + pRet->nElem = (int)nElem; pRet->zMatchinfo = ((char*)pRet) + nByte; memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1); pRet->aRef[0] = 1; @@ -173281,7 +176911,7 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ aOut = &p->aMatchinfo[p->nElem+2]; xRet = fts3MIBufferFree; }else{ - aOut = (u32*)sqlite3_malloc(p->nElem * sizeof(u32)); + aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32)); if( aOut ){ xRet = sqlite3_free; if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32)); @@ -173532,11 +177162,12 @@ static void fts3SnippetDetails( char *pCsr = pPhrase->pTail; int iCsr = pPhrase->iTail; - while( iCsr<(iStart+pIter->nSnippet) ){ + while( iCsr<(iStart+pIter->nSnippet) && iCsr>=iStart ){ int j; u64 mPhrase = (u64)1 << i; u64 mPos = (u64)1 << (iCsr - iStart); - assert( iCsr>=iStart ); + assert( iCsr>=iStart && (iCsr - iStart)<=64 ); + assert( i>=0 && i<=64 ); if( (mCover|mCovered)&mPhrase ){ iScore++; }else{ @@ -173578,11 +177209,14 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){ int iFirst = 0; pPhrase->pList = pCsr; fts3GetDeltaPosition(&pCsr, &iFirst); - assert( iFirst>=0 ); - pPhrase->pHead = pCsr; - pPhrase->pTail = pCsr; - pPhrase->iHead = iFirst; - pPhrase->iTail = iFirst; + if( iFirst<0 ){ + rc = FTS_CORRUPT_VTAB; + }else{ + pPhrase->pHead = pCsr; + pPhrase->pTail = pCsr; + pPhrase->iHead = iFirst; + pPhrase->iTail = iFirst; + } }else{ assert( rc!=SQLITE_OK || ( pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 @@ -173619,7 +177253,7 @@ static int fts3BestSnippet( int rc; /* Return Code */ int nList; /* Number of phrases in expression */ SnippetIter sIter; /* Iterates through snippet candidates */ - int nByte; /* Number of bytes of space to allocate */ + sqlite3_int64 nByte; /* Number of bytes of space to allocate */ int iBestScore = -1; /* Best snippet score found so far */ int i; /* Loop counter */ @@ -173637,7 +177271,7 @@ static int fts3BestSnippet( ** the required space using malloc(). */ nByte = sizeof(SnippetPhrase) * nList; - sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc(nByte); + sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc64(nByte); if( !sIter.aPhrase ){ return SQLITE_NOMEM; } @@ -173707,8 +177341,8 @@ static int fts3StringAppend( ** appended data. */ if( pStr->n+nAppend+1>=pStr->nAlloc ){ - int nAlloc = pStr->nAlloc+nAppend+100; - char *zNew = sqlite3_realloc(pStr->z, nAlloc); + sqlite3_int64 nAlloc = pStr->nAlloc+(sqlite3_int64)nAppend+100; + char *zNew = sqlite3_realloc64(pStr->z, nAlloc); if( !zNew ){ return SQLITE_NOMEM; } @@ -173763,6 +177397,7 @@ static int fts3SnippetShift( for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++); for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++); + assert( (nSnippet-1-nRight)<=63 && (nSnippet-1-nRight)>=0 ); nDesired = (nLeft-nRight)/2; /* Ideally, the start of the snippet should be pushed forward in the @@ -173955,7 +177590,7 @@ static int fts3ColumnlistCount(char **ppCollist){ /* ** This function gathers 'y' or 'b' data for a single phrase. */ -static void fts3ExprLHits( +static int fts3ExprLHits( Fts3Expr *pExpr, /* Phrase expression node */ MatchInfo *p /* Matchinfo context */ ){ @@ -173985,25 +177620,29 @@ static void fts3ExprLHits( if( *pIter!=0x01 ) break; pIter++; pIter += fts3GetVarint32(pIter, &iCol); + if( iCol>=p->nCol ) return FTS_CORRUPT_VTAB; } + return SQLITE_OK; } /* ** Gather the results for matchinfo directives 'y' and 'b'. */ -static void fts3ExprLHitGather( +static int fts3ExprLHitGather( Fts3Expr *pExpr, MatchInfo *p ){ + int rc = SQLITE_OK; assert( (pExpr->pLeft==0)==(pExpr->pRight==0) ); if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){ if( pExpr->pLeft ){ - fts3ExprLHitGather(pExpr->pLeft, p); - fts3ExprLHitGather(pExpr->pRight, p); + rc = fts3ExprLHitGather(pExpr->pLeft, p); + if( rc==SQLITE_OK ) rc = fts3ExprLHitGather(pExpr->pRight, p); }else{ - fts3ExprLHits(pExpr, p); + rc = fts3ExprLHits(pExpr, p); } } + return rc; } /* @@ -174093,8 +177732,8 @@ static int fts3MatchinfoCheck( return SQLITE_ERROR; } -static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ - int nVal; /* Number of integers output by cArg */ +static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ + size_t nVal; /* Number of integers output by cArg */ switch( cArg ){ case FTS3_MATCHINFO_NDOC: @@ -174220,11 +177859,12 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ int i; int iCol; int nToken = 0; + int rc = SQLITE_OK; /* Allocate and populate the array of LcsIterator objects. The array ** contains one element for each matchable phrase in the query. **/ - aIter = sqlite3_malloc(sizeof(LcsIterator) * pCsr->nPhrase); + aIter = sqlite3_malloc64(sizeof(LcsIterator) * pCsr->nPhrase); if( !aIter ) return SQLITE_NOMEM; memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase); (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); @@ -174240,13 +177880,16 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ int nLive = 0; /* Number of iterators in aIter not at EOF */ for(i=0; inPhrase; i++){ - int rc; LcsIterator *pIt = &aIter[i]; rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead); - if( rc!=SQLITE_OK ) return rc; + if( rc!=SQLITE_OK ) goto matchinfo_lcs_out; if( pIt->pRead ){ pIt->iPos = pIt->iPosOffset; - fts3LcsIteratorAdvance(&aIter[i]); + fts3LcsIteratorAdvance(pIt); + if( pIt->pRead==0 ){ + rc = FTS_CORRUPT_VTAB; + goto matchinfo_lcs_out; + } nLive++; } } @@ -174278,8 +177921,9 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ pInfo->aMatchinfo[iCol] = nLcs; } + matchinfo_lcs_out: sqlite3_free(aIter); - return SQLITE_OK; + return rc; } /* @@ -174373,9 +178017,9 @@ static int fts3MatchinfoValues( case FTS3_MATCHINFO_LHITS_BM: case FTS3_MATCHINFO_LHITS: { - int nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); + size_t nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); memset(pInfo->aMatchinfo, 0, nZero); - fts3ExprLHitGather(pCsr->pExpr, pInfo); + rc = fts3ExprLHitGather(pCsr->pExpr, pInfo); break; } @@ -174442,7 +178086,7 @@ static void fts3GetMatchinfo( ** initialize those elements that are constant for every row. */ if( pCsr->pMIBuffer==0 ){ - int nMatchinfo = 0; /* Number of u32 elements in match-info */ + size_t nMatchinfo = 0; /* Number of u32 elements in match-info */ int i; /* Used to iterate through zArg */ /* Determine the number of phrases in the query */ @@ -174527,6 +178171,10 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet( return; } + /* Limit the snippet length to 64 tokens. */ + if( nToken<-64 ) nToken = -64; + if( nToken>+64 ) nToken = +64; + for(nSnippet=1; 1; nSnippet++){ int iSnip; /* Loop counter 0..nSnippet-1 */ @@ -174628,7 +178276,7 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){ nTerm = pExpr->pPhrase->nToken; if( pList ){ fts3GetDeltaPosition(&pList, &iPos); - assert( iPos>=0 ); + assert_fts3_nc( iPos>=0 ); } for(iTerm=0; iTermpList) ){ pTerm->pList = 0; }else{ @@ -174894,7 +178542,7 @@ typedef struct unicode_cursor unicode_cursor; struct unicode_tokenizer { sqlite3_tokenizer base; - int bRemoveDiacritic; + int eRemoveDiacritic; int nException; int *aiException; }; @@ -174967,7 +178615,7 @@ static int unicodeAddExceptions( int *aNew; /* New aiException[] array */ int nNew; /* Number of valid entries in array aNew[] */ - aNew = sqlite3_realloc(p->aiException, (p->nException+nEntry)*sizeof(int)); + aNew = sqlite3_realloc64(p->aiException,(p->nException+nEntry)*sizeof(int)); if( aNew==0 ) return SQLITE_NOMEM; nNew = p->nException; @@ -175039,17 +178687,20 @@ static int unicodeCreate( pNew = (unicode_tokenizer *) sqlite3_malloc(sizeof(unicode_tokenizer)); if( pNew==NULL ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(unicode_tokenizer)); - pNew->bRemoveDiacritic = 1; + pNew->eRemoveDiacritic = 1; for(i=0; rc==SQLITE_OK && ibRemoveDiacritic = 1; + pNew->eRemoveDiacritic = 1; } else if( n==19 && memcmp("remove_diacritics=0", z, 19)==0 ){ - pNew->bRemoveDiacritic = 0; + pNew->eRemoveDiacritic = 0; + } + else if( n==19 && memcmp("remove_diacritics=2", z, 19)==0 ){ + pNew->eRemoveDiacritic = 2; } else if( n>=11 && memcmp("tokenchars=", z, 11)==0 ){ rc = unicodeAddExceptions(pNew, 1, &z[11], n-11); @@ -175153,7 +178804,7 @@ static int unicodeNext( /* Grow the output buffer if required. */ if( (zOut-pCsr->zToken)>=(pCsr->nAlloc-4) ){ - char *zNew = sqlite3_realloc(pCsr->zToken, pCsr->nAlloc+64); + char *zNew = sqlite3_realloc64(pCsr->zToken, pCsr->nAlloc+64); if( !zNew ) return SQLITE_NOMEM; zOut = &zNew[zOut - pCsr->zToken]; pCsr->zToken = zNew; @@ -175162,7 +178813,7 @@ static int unicodeNext( /* Write the folded case of the last character read to the output */ zEnd = z; - iOut = sqlite3FtsUnicodeFold((int)iCode, p->bRemoveDiacritic); + iOut = sqlite3FtsUnicodeFold((int)iCode, p->eRemoveDiacritic); if( iOut ){ WRITE_UTF8(zOut, iOut); } @@ -175207,7 +178858,7 @@ SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const * /************** End of fts3_unicode.c ****************************************/ /************** Begin file fts3_unicode2.c ***********************************/ /* -** 2012 May 25 +** 2012-05-25 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -175367,32 +179018,48 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){ ** E"). The resuls of passing a codepoint that corresponds to an ** uppercase letter are undefined. */ -static int remove_diacritic(int c){ +static int remove_diacritic(int c, int bComplex){ unsigned short aDia[] = { 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995, 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286, 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732, 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336, - 3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928, - 3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234, - 4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504, - 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529, - 61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726, - 61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122, - 62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536, - 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, - 62924, 63050, 63082, 63274, 63390, + 3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896, + 3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106, + 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344, + 4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198, + 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468, + 61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704, + 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914, + 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218, + 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554, + 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766, + 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118, + 63182, 63242, 63274, 63310, 63368, 63390, }; - char aChar[] = { - '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c', - 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r', - 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o', - 'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r', - 'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h', - 'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't', - 'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a', - 'e', 'i', 'o', 'u', 'y', +#define HIBIT ((unsigned char)0x80) + unsigned char aChar[] = { + '\0', 'a', 'c', 'e', 'i', 'n', + 'o', 'u', 'y', 'y', 'a', 'c', + 'd', 'e', 'e', 'g', 'h', 'i', + 'j', 'k', 'l', 'n', 'o', 'r', + 's', 't', 'u', 'u', 'w', 'y', + 'z', 'o', 'u', 'a', 'i', 'o', + 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o', + 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a', + 'e', 'i', 'o', 'r', 'u', 's', + 't', 'h', 'a', 'e', 'o'|HIBIT, 'o', + 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', 'a', 'b', + 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT, + 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT, + 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n', + 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's', + 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w', + 'w', 'x', 'y', 'z', 'h', 't', + 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT, + 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT, + 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y', }; unsigned int key = (((unsigned int)c)<<3) | 0x00000007; @@ -175409,7 +179076,8 @@ static int remove_diacritic(int c){ } } assert( key>=aDia[iRes] ); - return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]); + if( bComplex==0 && (aChar[iRes] & 0x80) ) return c; + return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F); } @@ -175422,8 +179090,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int c){ unsigned int mask1 = 0x000361F8; if( c<768 || c>817 ) return 0; return (c < 768+32) ? - (mask0 & (1 << (c-768))) : - (mask1 & (1 << (c-768-32))); + (mask0 & ((unsigned int)1 << (c-768))) : + (mask1 & ((unsigned int)1 << (c-768-32))); } @@ -175436,7 +179104,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int c){ ** The results are undefined if the value passed to this function ** is less than zero. */ -SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ +SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ /* Each entry in the following array defines a rule for folding a range ** of codepoints to lower case. The rule applies to a range of nRange ** codepoints starting at codepoint iCode. @@ -175559,7 +179227,9 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ assert( ret>0 ); } - if( bRemoveDiacritic ) ret = remove_diacritic(ret); + if( eRemoveDiacritic ){ + ret = remove_diacritic(ret, eRemoveDiacritic==2); + } } else if( c>=66560 && c<66600 ){ @@ -176266,7 +179936,7 @@ static JSON_NOINLINE int jsonParseAddNodeExpand( assert( pParse->nNode>=pParse->nAlloc ); if( pParse->oom ) return -1; nNew = pParse->nAlloc*2 + 10; - pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew); + pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew); if( pNew==0 ){ pParse->oom = 1; return -1; @@ -176540,7 +180210,7 @@ static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){ static int jsonParseFindParents(JsonParse *pParse){ u32 *aUp; assert( pParse->aUp==0 ); - aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode ); + aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode ); if( aUp==0 ){ pParse->oom = 1; return SQLITE_NOMEM; @@ -176602,7 +180272,7 @@ static JsonParse *jsonParseCached( pMatch->iHold = iMaxHold+1; return pMatch; } - p = sqlite3_malloc( sizeof(*p) + nJson + 1 ); + p = sqlite3_malloc64( sizeof(*p) + nJson + 1 ); if( p==0 ){ sqlite3_result_error_nomem(pCtx); return 0; @@ -176698,7 +180368,7 @@ static JsonNode *jsonLookupStep( u32 iStart, iLabel; JsonNode *pNode; iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); - iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath); + iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); zPath += i; pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); if( pParse->oom ) return 0; @@ -177569,6 +181239,9 @@ static int jsonEachConnect( #define JEACH_PARENT 5 #define JEACH_FULLKEY 6 #define JEACH_PATH 7 +/* The xBestIndex method assumes that the JSON and ROOT columns are +** the last two columns in the table. Should this ever changes, be +** sure to update the xBestIndex method. */ #define JEACH_JSON 8 #define JEACH_ROOT 9 @@ -177826,35 +181499,54 @@ static int jsonEachBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ - int i; - int jsonIdx = -1; - int rootIdx = -1; + int i; /* Loop counter or computed array index */ + int aIdx[2]; /* Index of constraints for JSON and ROOT */ + int unusableMask = 0; /* Mask of unusable JSON and ROOT constraints */ + int idxMask = 0; /* Mask of usable == constraints JSON and ROOT */ const struct sqlite3_index_constraint *pConstraint; + /* This implementation assumes that JSON and ROOT are the last two + ** columns in the table */ + assert( JEACH_ROOT == JEACH_JSON+1 ); UNUSED_PARAM(tab); + aIdx[0] = aIdx[1] = -1; pConstraint = pIdxInfo->aConstraint; for(i=0; inConstraint; i++, pConstraint++){ - if( pConstraint->usable==0 ) continue; - if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - switch( pConstraint->iColumn ){ - case JEACH_JSON: jsonIdx = i; break; - case JEACH_ROOT: rootIdx = i; break; - default: /* no-op */ break; - } - } - if( jsonIdx<0 ){ + int iCol; + int iMask; + if( pConstraint->iColumn < JEACH_JSON ) continue; + iCol = pConstraint->iColumn - JEACH_JSON; + assert( iCol==0 || iCol==1 ); + iMask = 1 << iCol; + if( pConstraint->usable==0 ){ + unusableMask |= iMask; + }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + aIdx[iCol] = i; + idxMask |= iMask; + } + } + if( (unusableMask & ~idxMask)!=0 ){ + /* If there are any unusable constraints on JSON or ROOT, then reject + ** this entire plan */ + return SQLITE_CONSTRAINT; + } + if( aIdx[0]<0 ){ + /* No JSON input. Leave estimatedCost at the huge value that it was + ** initialized to to discourage the query planner from selecting this + ** plan. */ pIdxInfo->idxNum = 0; - pIdxInfo->estimatedCost = 1e99; }else{ pIdxInfo->estimatedCost = 1.0; - pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1; - pIdxInfo->aConstraintUsage[jsonIdx].omit = 1; - if( rootIdx<0 ){ - pIdxInfo->idxNum = 1; + i = aIdx[0]; + pIdxInfo->aConstraintUsage[i].argvIndex = 1; + pIdxInfo->aConstraintUsage[i].omit = 1; + if( aIdx[1]<0 ){ + pIdxInfo->idxNum = 1; /* Only JSON supplied. Plan 1 */ }else{ - pIdxInfo->aConstraintUsage[rootIdx].argvIndex = 2; - pIdxInfo->aConstraintUsage[rootIdx].omit = 1; - pIdxInfo->idxNum = 3; + i = aIdx[1]; + pIdxInfo->aConstraintUsage[i].argvIndex = 2; + pIdxInfo->aConstraintUsage[i].omit = 1; + pIdxInfo->idxNum = 3; /* Both JSON and ROOT are supplied. Plan 3 */ } } return SQLITE_OK; @@ -177963,7 +181655,8 @@ static sqlite3_module jsonEachModule = { 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; /* The methods of the json_tree virtual table. */ @@ -177990,7 +181683,8 @@ static sqlite3_module jsonTreeModule = { 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -178158,10 +181852,6 @@ SQLITE_API int sqlite3_json_init( /* #include "sqlite3.h" */ #endif -/* #include */ -/* #include */ -/* #include */ - #ifndef SQLITE_AMALGAMATION #include "sqlite3rtree.h" typedef sqlite3_int64 i64; @@ -178169,8 +181859,18 @@ typedef sqlite3_uint64 u64; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +# define NDEBUG 1 +#endif +#if defined(NDEBUG) && defined(SQLITE_DEBUG) +# undef NDEBUG +#endif #endif +/* #include */ +/* #include */ +/* #include */ + /* The following macro is used to suppress compiler warnings. */ #ifndef UNUSED_PARAMETER @@ -178223,6 +181923,9 @@ struct Rtree { u8 inWrTrans; /* True if inside write transaction */ u8 nAux; /* # of auxiliary columns in %_rowid */ u8 nAuxNotNull; /* Number of initial not-null aux columns */ +#ifdef SQLITE_DEBUG + u8 bCorrupt; /* Shadow table corruption detected */ +#endif int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ @@ -178282,6 +181985,15 @@ struct Rtree { # define RTREE_ZERO 0.0 #endif +/* +** Set the Rtree.bCorrupt flag +*/ +#ifdef SQLITE_DEBUG +# define RTREE_IS_CORRUPT(X) ((X)->bCorrupt = 1) +#else +# define RTREE_IS_CORRUPT(X) +#endif + /* ** When doing a search of an r-tree, instances of the following structure ** record intermediate results from the tree walk. @@ -178648,8 +182360,8 @@ static void nodeZero(Rtree *pRtree, RtreeNode *p){ ** Given a node number iNode, return the corresponding key to use ** in the Rtree.aHash table. */ -static int nodeHash(i64 iNode){ - return iNode % HASHSIZE; +static unsigned int nodeHash(i64 iNode){ + return ((unsigned)iNode) % HASHSIZE; } /* @@ -178694,7 +182406,7 @@ static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){ */ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ RtreeNode *pNode; - pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize); + pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode) + pRtree->iNodeSize); if( pNode ){ memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize); pNode->zData = (u8 *)&pNode[1]; @@ -178718,6 +182430,18 @@ static void nodeBlobReset(Rtree *pRtree){ } } +/* +** Check to see if pNode is the same as pParent or any of the parents +** of pParent. +*/ +static int nodeInParentChain(const RtreeNode *pNode, const RtreeNode *pParent){ + do{ + if( pNode==pParent ) return 1; + pParent = pParent->pParent; + }while( pParent ); + return 0; +} + /* ** Obtain a reference to an r-tree node. */ @@ -178736,6 +182460,10 @@ static int nodeAcquire( if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){ assert( !pParent || !pNode->pParent || pNode->pParent==pParent ); if( pParent && !pNode->pParent ){ + if( nodeInParentChain(pNode, pParent) ){ + RTREE_IS_CORRUPT(pRtree); + return SQLITE_CORRUPT_VTAB; + } pParent->nRef++; pNode->pParent = pParent; } @@ -178766,9 +182494,12 @@ static int nodeAcquire( *ppNode = 0; /* If unable to open an sqlite3_blob on the desired row, that can only ** be because the shadow tables hold erroneous data. */ - if( rc==SQLITE_ERROR ) rc = SQLITE_CORRUPT_VTAB; + if( rc==SQLITE_ERROR ){ + rc = SQLITE_CORRUPT_VTAB; + RTREE_IS_CORRUPT(pRtree); + } }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){ - pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize); + pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode)+pRtree->iNodeSize); if( !pNode ){ rc = SQLITE_NOMEM; }else{ @@ -178781,7 +182512,6 @@ static int nodeAcquire( pNode->pNext = 0; rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData, pRtree->iNodeSize, 0); - nodeReference(pParent); } } @@ -178795,6 +182525,7 @@ static int nodeAcquire( pRtree->iDepth = readInt16(pNode->zData); if( pRtree->iDepth>RTREE_MAX_DEPTH ){ rc = SQLITE_CORRUPT_VTAB; + RTREE_IS_CORRUPT(pRtree); } } @@ -178805,14 +182536,17 @@ static int nodeAcquire( if( pNode && rc==SQLITE_OK ){ if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){ rc = SQLITE_CORRUPT_VTAB; + RTREE_IS_CORRUPT(pRtree); } } if( rc==SQLITE_OK ){ if( pNode!=0 ){ + nodeReference(pParent); nodeHashInsert(pRtree, pNode); }else{ rc = SQLITE_CORRUPT_VTAB; + RTREE_IS_CORRUPT(pRtree); } *ppNode = pNode; }else{ @@ -179038,7 +182772,7 @@ static void rtreeRelease(Rtree *pRtree){ pRtree->inWrTrans = 0; assert( pRtree->nCursor==0 ); nodeBlobReset(pRtree); - assert( pRtree->nNodeRef==0 ); + assert( pRtree->nNodeRef==0 || pRtree->bCorrupt ); sqlite3_finalize(pRtree->pWriteNode); sqlite3_finalize(pRtree->pDeleteNode); sqlite3_finalize(pRtree->pReadRowid); @@ -179097,7 +182831,7 @@ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ Rtree *pRtree = (Rtree *)pVTab; RtreeCursor *pCsr; - pCsr = (RtreeCursor *)sqlite3_malloc(sizeof(RtreeCursor)); + pCsr = (RtreeCursor *)sqlite3_malloc64(sizeof(RtreeCursor)); if( pCsr ){ memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = pVTab; @@ -179370,6 +183104,7 @@ static int nodeRowidIndex( return SQLITE_OK; } } + RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } @@ -179463,7 +183198,7 @@ static RtreeSearchPoint *rtreeEnqueue( RtreeSearchPoint *pNew; if( pCur->nPoint>=pCur->nPointAlloc ){ int nNew = pCur->nPointAlloc*2 + 8; - pNew = sqlite3_realloc(pCur->aPoint, nNew*sizeof(pCur->aPoint[0])); + pNew = sqlite3_realloc64(pCur->aPoint, nNew*sizeof(pCur->aPoint[0])); if( pNew==0 ) return 0; pCur->aPoint = pNew; pCur->nPointAlloc = nNew; @@ -179865,7 +183600,7 @@ static int rtreeFilter( */ rc = nodeAcquire(pRtree, 1, 0, &pRoot); if( rc==SQLITE_OK && argc>0 ){ - pCsr->aConstraint = sqlite3_malloc(sizeof(RtreeConstraint)*argc); + pCsr->aConstraint = sqlite3_malloc64(sizeof(RtreeConstraint)*argc); pCsr->nConstraint = argc; if( !pCsr->aConstraint ){ rc = SQLITE_NOMEM; @@ -180010,20 +183745,20 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ ){ u8 op; switch( p->op ){ - case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break; - case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break; - case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break; - case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break; - case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break; - default: - assert( p->op==SQLITE_INDEX_CONSTRAINT_MATCH ); - op = RTREE_MATCH; - break; + case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break; + case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break; + case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break; + case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break; + case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break; + case SQLITE_INDEX_CONSTRAINT_MATCH: op = RTREE_MATCH; break; + default: op = 0; break; + } + if( op ){ + zIdxStr[iIdx++] = op; + zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0'); + pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); + pIdxInfo->aConstraintUsage[ii].omit = 1; } - zIdxStr[iIdx++] = op; - zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0'); - pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); - pIdxInfo->aConstraintUsage[ii].omit = 1; } } @@ -180059,11 +183794,11 @@ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){ #endif { switch( pRtree->nDim ){ - case 5: area = p->aCoord[9].i - p->aCoord[8].i; - case 4: area *= p->aCoord[7].i - p->aCoord[6].i; - case 3: area *= p->aCoord[5].i - p->aCoord[4].i; - case 2: area *= p->aCoord[3].i - p->aCoord[2].i; - default: area *= p->aCoord[1].i - p->aCoord[0].i; + case 5: area = (i64)p->aCoord[9].i - (i64)p->aCoord[8].i; + case 4: area *= (i64)p->aCoord[7].i - (i64)p->aCoord[6].i; + case 3: area *= (i64)p->aCoord[5].i - (i64)p->aCoord[4].i; + case 2: area *= (i64)p->aCoord[3].i - (i64)p->aCoord[2].i; + default: area *= (i64)p->aCoord[1].i - (i64)p->aCoord[0].i; } } return area; @@ -180232,12 +183967,14 @@ static int AdjustTree( RtreeCell *pCell /* This cell was just inserted */ ){ RtreeNode *p = pNode; + int cnt = 0; while( p->pParent ){ RtreeNode *pParent = p->pParent; RtreeCell cell; int iCell; - if( nodeParentIndex(pRtree, p, &iCell) ){ + if( (++cnt)>1000 || nodeParentIndex(pRtree, p, &iCell) ){ + RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } @@ -180434,9 +184171,9 @@ static int splitNodeStartree( int iBestSplit = 0; RtreeDValue fBestMargin = RTREE_ZERO; - int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int)); + sqlite3_int64 nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int)); - aaSorted = (int **)sqlite3_malloc(nByte); + aaSorted = (int **)sqlite3_malloc64(nByte); if( !aaSorted ){ return SQLITE_NOMEM; } @@ -180557,7 +184294,7 @@ static int SplitNode( /* Allocate an array and populate it with a copy of pCell and ** all cells from node pLeft. Then zero the original node. */ - aCell = sqlite3_malloc((sizeof(RtreeCell)+sizeof(int))*(nCell+1)); + aCell = sqlite3_malloc64((sizeof(RtreeCell)+sizeof(int))*(nCell+1)); if( !aCell ){ rc = SQLITE_NOMEM; goto splitnode_out; @@ -180705,7 +184442,10 @@ static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){ } rc = sqlite3_reset(pRtree->pReadParent); if( rc==SQLITE_OK ) rc = rc2; - if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT_VTAB; + if( rc==SQLITE_OK && !pChild->pParent ){ + RTREE_IS_CORRUPT(pRtree); + rc = SQLITE_CORRUPT_VTAB; + } pChild = pChild->pParent; } return rc; @@ -180845,7 +184585,7 @@ static int Reinsert( /* Allocate the buffers used by this operation. The allocation is ** relinquished before this function returns. */ - aCell = (RtreeCell *)sqlite3_malloc(n * ( + aCell = (RtreeCell *)sqlite3_malloc64(n * ( sizeof(RtreeCell) + /* aCell array */ sizeof(int) + /* aOrder array */ sizeof(int) + /* aSpare array */ @@ -181019,8 +184759,12 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ rc = findLeafNode(pRtree, iDelete, &pLeaf, 0); } +#ifdef CORRUPT_DB + assert( pLeaf!=0 || rc!=SQLITE_OK || CORRUPT_DB ); +#endif + /* Delete the cell in question from the leaf node. */ - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && pLeaf ){ int rc2; rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); if( rc==SQLITE_OK ){ @@ -181292,7 +185036,7 @@ static int rtreeUpdate( rc = rc2; } } - if( pRtree->nAux ){ + if( rc==SQLITE_OK && pRtree->nAux ){ sqlite3_stmt *pUp = pRtree->pWriteAux; int jj; sqlite3_bind_int64(pUp, 1, *pRowid); @@ -181420,8 +185164,24 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ return rc; } + +/* +** Return true if zName is the extension on one of the shadow tables used +** by this module. +*/ +static int rtreeShadowName(const char *zName){ + static const char *azName[] = { + "node", "parent", "rowid" + }; + unsigned int i; + for(i=0; idb = db; @@ -181529,8 +185291,7 @@ static int rtreeSqlInit( } zSql = sqlite3_mprintf(zFormat, zDb, zPrefix); if( zSql ){ - rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT, - appStmt[i], 0); + rc = sqlite3_prepare_v3(db, zSql, -1, f, appStmt[i], 0); }else{ rc = SQLITE_NOMEM; } @@ -181560,8 +185321,7 @@ static int rtreeSqlInit( if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT, - &pRtree->pWriteAux, 0); + rc = sqlite3_prepare_v3(db, zSql, -1, f, &pRtree->pWriteAux, 0); sqlite3_free(zSql); } } @@ -181637,6 +185397,7 @@ static int getNodeSize( *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); }else if( pRtree->iNodeSize<(512-64) ){ rc = SQLITE_CORRUPT_VTAB; + RTREE_IS_CORRUPT(pRtree); *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"", pRtree->zName); } @@ -181692,7 +185453,7 @@ static int rtreeInit( /* Allocate the sqlite3_vtab structure */ nDb = (int)strlen(argv[1]); nName = (int)strlen(argv[2]); - pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); + pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); if( !pRtree ){ return SQLITE_NOMEM; } @@ -181789,49 +185550,45 @@ static int rtreeInit( ** *2 coordinates. */ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ - char *zText = 0; RtreeNode node; Rtree tree; int ii; + int nData; + int errCode; + sqlite3_str *pOut; UNUSED_PARAMETER(nArg); memset(&node, 0, sizeof(RtreeNode)); memset(&tree, 0, sizeof(Rtree)); tree.nDim = (u8)sqlite3_value_int(apArg[0]); + if( tree.nDim<1 || tree.nDim>5 ) return; tree.nDim2 = tree.nDim*2; tree.nBytesPerCell = 8 + 8 * tree.nDim; node.zData = (u8 *)sqlite3_value_blob(apArg[1]); + nData = sqlite3_value_bytes(apArg[1]); + if( nData<4 ) return; + if( nData0 ) sqlite3_str_append(pOut, " ", 1); + sqlite3_str_appendf(pOut, "{%lld", cell.iRowid); for(jj=0; jjrc==SQLITE_OK ); - if( pCheck->pGetNode==0 ){ + if( pCheck->rc==SQLITE_OK && pCheck->pGetNode==0 ){ pCheck->pGetNode = rtreeCheckPrepare(pCheck, "SELECT data FROM %Q.'%q_node' WHERE nodeno=?", pCheck->zDb, pCheck->zTab @@ -181973,7 +185729,7 @@ static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){ if( sqlite3_step(pCheck->pGetNode)==SQLITE_ROW ){ int nNode = sqlite3_column_bytes(pCheck->pGetNode, 0); const u8 *pNode = (const u8*)sqlite3_column_blob(pCheck->pGetNode, 0); - pRet = sqlite3_malloc(nNode); + pRet = sqlite3_malloc64(nNode); if( pRet==0 ){ pCheck->rc = SQLITE_NOMEM; }else{ @@ -182434,14 +186190,32 @@ typedef float GeoCoord; ** ** encoding (1 byte) 0=big-endian, 1=little-endian ** nvertex (3 bytes) Number of vertexes as a big-endian integer +** +** Enough space is allocated for 4 coordinates, to work around over-zealous +** warnings coming from some compiler (notably, clang). In reality, the size +** of each GeoPoly memory allocate is adjusted as necessary so that the +** GeoPoly.a[] array at the end is the appropriate size. */ typedef struct GeoPoly GeoPoly; struct GeoPoly { int nVertex; /* Number of vertexes */ unsigned char hdr[4]; /* Header for on-disk representation */ - GeoCoord a[2]; /* 2*nVertex values. X (longitude) first, then Y */ + GeoCoord a[8]; /* 2*nVertex values. X (longitude) first, then Y */ }; +/* The size of a memory allocation needed for a GeoPoly object sufficient +** to hold N coordinate pairs. +*/ +#define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4)) + +/* Macros to access coordinates of a GeoPoly. +** We have to use these macros, rather than just say p->a[i] in order +** to silence (incorrect) UBSAN warnings if the array index is too large. +*/ +#define GeoX(P,I) (((GeoCoord*)(P)->a)[(I)*2]) +#define GeoY(P,I) (((GeoCoord*)(P)->a)[(I)*2+1]) + + /* ** State of a parse of a GeoJSON input. */ @@ -182466,7 +186240,7 @@ static void geopolySwab32(unsigned char *a){ /* Skip whitespace. Return the next non-whitespace character. */ static char geopolySkipSpace(GeoParse *p){ - while( p->z[0] && safe_isspace(p->z[0]) ) p->z++; + while( safe_isspace(p->z[0]) ) p->z++; return p->z[0]; } @@ -182486,7 +186260,7 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ if( c=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0; for(;; j++){ c = z[j]; - if( c>='0' && c<='9' ) continue; + if( safe_isdigit(c) ) continue; if( c=='.' ){ if( z[j-1]=='-' ) return 0; if( seenDP ) return 0; @@ -182508,7 +186282,17 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ break; } if( z[j-1]<'0' ) return 0; - if( pVal ) *pVal = (GeoCoord)atof((const char*)p->z); + if( pVal ){ +#ifdef SQLITE_AMALGAMATION + /* The sqlite3AtoF() routine is much much faster than atof(), if it + ** is available */ + double r; + (void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8); + *pVal = r; +#else + *pVal = (GeoCoord)atof((const char*)p->z); +#endif + } p->z += j; return 1; } @@ -182566,12 +186350,10 @@ static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){ && s.a[1]==s.a[s.nVertex*2-1] && (s.z++, geopolySkipSpace(&s)==0) ){ - int nByte; GeoPoly *pOut; int x = 1; s.nVertex--; /* Remove the redundant vertex at the end */ - nByte = sizeof(GeoPoly) * s.nVertex*2*sizeof(GeoCoord); - pOut = sqlite3_malloc64( nByte ); + pOut = sqlite3_malloc64( GEOPOLY_SZ((sqlite3_int64)s.nVertex) ); x = 1; if( pOut==0 ) goto parse_json_err; pOut->nVertex = s.nVertex; @@ -182626,8 +186408,9 @@ static GeoPoly *geopolyFuncParam( memcpy(p->hdr, a, nByte); if( a[0] != *(unsigned char*)&x ){ int ii; - for(ii=0; iia[ii]); + for(ii=0; iihdr[0] ^= 1; } @@ -182686,9 +186469,9 @@ static void geopolyJsonFunc( int i; sqlite3_str_append(x, "[", 1); for(i=0; inVertex; i++){ - sqlite3_str_appendf(x, "[%!g,%!g],", p->a[i*2], p->a[i*2+1]); + sqlite3_str_appendf(x, "[%!g,%!g],", GeoX(p,i), GeoY(p,i)); } - sqlite3_str_appendf(x, "[%!g,%!g]]", p->a[0], p->a[1]); + sqlite3_str_appendf(x, "[%!g,%!g]]", GeoX(p,0), GeoY(p,0)); sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); sqlite3_free(p); } @@ -182705,7 +186488,9 @@ static void geopolySvgFunc( int argc, sqlite3_value **argv ){ - GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + GeoPoly *p; + if( argc<1 ) return; + p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_str *x = sqlite3_str_new(db); @@ -182713,10 +186498,10 @@ static void geopolySvgFunc( char cSep = '\''; sqlite3_str_appendf(x, "a[i*2], p->a[i*2+1]); + sqlite3_str_appendf(x, "%c%g,%g", cSep, GeoX(p,i), GeoY(p,i)); cSep = ' '; } - sqlite3_str_appendf(x, " %g,%g'", p->a[0], p->a[1]); + sqlite3_str_appendf(x, " %g,%g'", GeoX(p,0), GeoY(p,0)); for(i=1; inVertex; ii++){ - x0 = p->a[ii*2]; - y0 = p->a[ii*2+1]; + x0 = GeoX(p,ii); + y0 = GeoY(p,ii); x1 = (GeoCoord)(A*x0 + B*y0 + E); y1 = (GeoCoord)(C*x0 + D*y0 + F); - p->a[ii*2] = x1; - p->a[ii*2+1] = y1; + GeoX(p,ii) = x1; + GeoY(p,ii) = y1; } sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); @@ -182774,6 +186559,27 @@ static void geopolyXformFunc( } } +/* +** Compute the area enclosed by the polygon. +** +** This routine can also be used to detect polygons that rotate in +** the wrong direction. Polygons are suppose to be counter-clockwise (CCW). +** This routine returns a negative value for clockwise (CW) polygons. +*/ +static double geopolyArea(GeoPoly *p){ + double rArea = 0.0; + int ii; + for(ii=0; iinVertex-1; ii++){ + rArea += (GeoX(p,ii) - GeoX(p,ii+1)) /* (x0 - x1) */ + * (GeoY(p,ii) + GeoY(p,ii+1)) /* (y0 + y1) */ + * 0.5; + } + rArea += (GeoX(p,ii) - GeoX(p,0)) /* (xN - x0) */ + * (GeoY(p,ii) + GeoY(p,0)) /* (yN + y0) */ + * 0.5; + return rArea; +} + /* ** Implementation of the geopoly_area(X) function. ** @@ -182789,21 +186595,106 @@ static void geopolyAreaFunc( ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ - double rArea = 0.0; - int ii; - for(ii=0; iinVertex-1; ii++){ - rArea += (p->a[ii*2] - p->a[ii*2+2]) /* (x0 - x1) */ - * (p->a[ii*2+1] + p->a[ii*2+3]) /* (y0 + y1) */ - * 0.5; - } - rArea += (p->a[ii*2] - p->a[0]) /* (xN - x0) */ - * (p->a[ii*2+1] + p->a[1]) /* (yN + y0) */ - * 0.5; - sqlite3_result_double(context, rArea); + sqlite3_result_double(context, geopolyArea(p)); sqlite3_free(p); } } +/* +** Implementation of the geopoly_ccw(X) function. +** +** If the rotation of polygon X is clockwise (incorrect) instead of +** counter-clockwise (the correct winding order according to RFC7946) +** then reverse the order of the vertexes in polygon X. +** +** In other words, this routine returns a CCW polygon regardless of the +** winding order of its input. +** +** Use this routine to sanitize historical inputs that that sometimes +** contain polygons that wind in the wrong direction. +*/ +static void geopolyCcwFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + if( geopolyArea(p)<0.0 ){ + int ii, jj; + for(ii=1, jj=p->nVertex-1; iihdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } +} + +#define GEOPOLY_PI 3.1415926535897932385 + +/* Fast approximation for sine(X) for X between -0.5*pi and 2*pi +*/ +static double geopolySine(double r){ + assert( r>=-0.5*GEOPOLY_PI && r<=2.0*GEOPOLY_PI ); + if( r>=1.5*GEOPOLY_PI ){ + r -= 2.0*GEOPOLY_PI; + } + if( r>=0.5*GEOPOLY_PI ){ + return -geopolySine(r-GEOPOLY_PI); + }else{ + double r2 = r*r; + double r3 = r2*r; + double r5 = r3*r2; + return 0.9996949*r - 0.1656700*r3 + 0.0075134*r5; + } +} + +/* +** Function: geopoly_regular(X,Y,R,N) +** +** Construct a simple, convex, regular polygon centered at X, Y +** with circumradius R and with N sides. +*/ +static void geopolyRegularFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + double x = sqlite3_value_double(argv[0]); + double y = sqlite3_value_double(argv[1]); + double r = sqlite3_value_double(argv[2]); + int n = sqlite3_value_int(argv[3]); + int i; + GeoPoly *p; + + if( n<3 || r<=0.0 ) return; + if( n>1000 ) n = 1000; + p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) ); + if( p==0 ){ + sqlite3_result_error_nomem(context); + return; + } + i = 1; + p->hdr[0] = *(unsigned char*)&i; + p->hdr[1] = 0; + p->hdr[2] = (n>>8)&0xff; + p->hdr[3] = n&0xff; + for(i=0; ihdr, 4+8*n, SQLITE_TRANSIENT); + sqlite3_free(p); +} + /* ** If pPoly is a polygon, compute its bounding box. Then: ** @@ -182835,20 +186726,20 @@ static GeoPoly *geopolyBBox( } if( p ){ int ii; - mnX = mxX = p->a[0]; - mnY = mxY = p->a[1]; + mnX = mxX = GeoX(p,0); + mnY = mxY = GeoY(p,0); for(ii=1; iinVertex; ii++){ - double r = p->a[ii*2]; + double r = GeoX(p,ii); if( rmxX ) mxX = (float)r; - r = p->a[ii*2+1]; + r = GeoY(p,ii); if( rmxY ) mxY = (float)r; } if( pRc ) *pRc = SQLITE_OK; if( aCoord==0 ){ geopolyBboxFill: - pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6); + pOut = sqlite3_realloc64(p, GEOPOLY_SZ(4)); if( pOut==0 ){ sqlite3_free(p); if( context ) sqlite3_result_error_nomem(context); @@ -182861,14 +186752,14 @@ static GeoPoly *geopolyBBox( pOut->hdr[1] = 0; pOut->hdr[2] = 0; pOut->hdr[3] = 4; - pOut->a[0] = mnX; - pOut->a[1] = mnY; - pOut->a[2] = mxX; - pOut->a[3] = mnY; - pOut->a[4] = mxX; - pOut->a[5] = mxY; - pOut->a[6] = mnX; - pOut->a[7] = mxY; + GeoX(pOut,0) = mnX; + GeoY(pOut,0) = mnY; + GeoX(pOut,1) = mxX; + GeoY(pOut,1) = mnY; + GeoX(pOut,2) = mxX; + GeoY(pOut,2) = mxY; + GeoX(pOut,3) = mnX; + GeoY(pOut,3) = mxY; }else{ sqlite3_free(p); aCoord[0].f = mnX; @@ -183006,14 +186897,14 @@ static void geopolyContainsPointFunc( int ii; if( p1==0 ) return; for(ii=0; iinVertex-1; ii++){ - v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1], - p1->a[ii*2+2],p1->a[ii*2+3]); + v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii), + GeoX(p1,ii+1),GeoY(p1,ii+1)); if( v==2 ) break; cnt += v; } if( v!=2 ){ - v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1], - p1->a[0],p1->a[1]); + v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii), + GeoX(p1,0), GeoY(p1,0)); } if( v==2 ){ sqlite3_result_int(context, 1); @@ -183135,10 +187026,10 @@ static void geopolyAddSegments( unsigned int i; GeoCoord *x; for(i=0; i<(unsigned)pPoly->nVertex-1; i++){ - x = pPoly->a + (i*2); + x = &GeoX(pPoly,i); geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i); } - x = pPoly->a + (i*2); + x = &GeoX(pPoly,i); geopolyAddOneSegment(p, x[0], x[1], pPoly->a[0], pPoly->a[1], side, i); } @@ -183244,9 +187135,9 @@ static GeoSegment *geopolySortSegmentsByYAndC(GeoSegment *pList){ ** Determine the overlap between two polygons */ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){ - int nVertex = p1->nVertex + p2->nVertex + 2; + sqlite3_int64 nVertex = p1->nVertex + p2->nVertex + 2; GeoOverlap *p; - int nByte; + sqlite3_int64 nByte; GeoEvent *pThisEvent; double rX; int rc = 0; @@ -183258,7 +187149,7 @@ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){ nByte = sizeof(GeoEvent)*nVertex*2 + sizeof(GeoSegment)*nVertex + sizeof(GeoOverlap); - p = sqlite3_malloc( nByte ); + p = sqlite3_malloc64( nByte ); if( p==0 ) return -1; p->aEvent = (GeoEvent*)&p[1]; p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2]; @@ -183417,8 +187308,8 @@ static int geopolyInit( ){ int rc = SQLITE_OK; Rtree *pRtree; - int nDb; /* Length of string argv[1] */ - int nName; /* Length of string argv[2] */ + sqlite3_int64 nDb; /* Length of string argv[1] */ + sqlite3_int64 nName; /* Length of string argv[2] */ sqlite3_str *pSql; char *zSql; int ii; @@ -183426,9 +187317,9 @@ static int geopolyInit( sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); /* Allocate the sqlite3_vtab structure */ - nDb = (int)strlen(argv[1]); - nName = (int)strlen(argv[2]); - pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); + nDb = strlen(argv[1]); + nName = strlen(argv[2]); + pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); if( !pRtree ){ return SQLITE_NOMEM; } @@ -183876,7 +187767,16 @@ static int geopolyUpdate( if( sqlite3_value_nochange(aData[2]) ){ sqlite3_bind_null(pUp, 2); }else{ - sqlite3_bind_value(pUp, 2, aData[2]); + GeoPoly *p = 0; + if( sqlite3_value_type(aData[2])==SQLITE_TEXT + && (p = geopolyFuncParam(0, aData[2], &rc))!=0 + && rc==SQLITE_OK + ){ + sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); + }else{ + sqlite3_bind_value(pUp, 2, aData[2]); + } + sqlite3_free(p); nChange = 1; } for(jj=1; jjnAux; jj++){ @@ -183920,7 +187820,7 @@ static int geopolyFindFunction( static sqlite3_module geopolyModule = { - 2, /* iVersion */ + 3, /* iVersion */ geopolyCreate, /* xCreate - create a table */ geopolyConnect, /* xConnect - connect to an existing table */ geopolyBestIndex, /* xBestIndex - Determine search strategy */ @@ -183943,25 +187843,29 @@ static sqlite3_module geopolyModule = { rtreeSavepoint, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + rtreeShadowName /* xShadowName */ }; static int sqlite3_geopoly_init(sqlite3 *db){ int rc = SQLITE_OK; static const struct { void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - int nArg; + signed char nArg; + unsigned char bPure; const char *zName; } aFunc[] = { - { geopolyAreaFunc, 1, "geopoly_area" }, - { geopolyBlobFunc, 1, "geopoly_blob" }, - { geopolyJsonFunc, 1, "geopoly_json" }, - { geopolySvgFunc, -1, "geopoly_svg" }, - { geopolyWithinFunc, 2, "geopoly_within" }, - { geopolyContainsPointFunc, 3, "geopoly_contains_point" }, - { geopolyOverlapFunc, 2, "geopoly_overlap" }, - { geopolyDebugFunc, 1, "geopoly_debug" }, - { geopolyBBoxFunc, 1, "geopoly_bbox" }, - { geopolyXformFunc, 7, "geopoly_xform" }, + { geopolyAreaFunc, 1, 1, "geopoly_area" }, + { geopolyBlobFunc, 1, 1, "geopoly_blob" }, + { geopolyJsonFunc, 1, 1, "geopoly_json" }, + { geopolySvgFunc, -1, 1, "geopoly_svg" }, + { geopolyWithinFunc, 2, 1, "geopoly_within" }, + { geopolyContainsPointFunc, 3, 1, "geopoly_contains_point" }, + { geopolyOverlapFunc, 2, 1, "geopoly_overlap" }, + { geopolyDebugFunc, 1, 0, "geopoly_debug" }, + { geopolyBBoxFunc, 1, 1, "geopoly_bbox" }, + { geopolyXformFunc, 7, 1, "geopoly_xform" }, + { geopolyRegularFunc, 4, 1, "geopoly_regular" }, + { geopolyCcwFunc, 1, 1, "geopoly_ccw" }, }; static const struct { void (*xStep)(sqlite3_context*,int,sqlite3_value**); @@ -183972,8 +187876,9 @@ static int sqlite3_geopoly_init(sqlite3 *db){ }; int i; for(i=0; i0 ){ n = strlen(argv[0])+1; } - p = (IcuTokenizer *)sqlite3_malloc(sizeof(IcuTokenizer)+n); + p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); if( !p ){ return SQLITE_NOMEM; } @@ -184842,7 +188747,7 @@ static int icuOpen( nInput = strlen(zInput); } nChar = nInput+1; - pCsr = (IcuCursor *)sqlite3_malloc( + pCsr = (IcuCursor *)sqlite3_malloc64( sizeof(IcuCursor) + /* IcuCursor */ ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ @@ -185414,7 +189319,11 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open( ** name of the state database is "-vacuum", where ** is the name of the target database file. In this case, on UNIX, if the ** state database is not already present in the file-system, it is created -** with the same permissions as the target db is made. +** with the same permissions as the target db is made. +** +** With an RBU vacuum, it is an SQLITE_MISUSE error if the name of the +** state database ends with "-vactmp". This name is reserved for internal +** use. ** ** This function does not delete the state database after an RBU vacuum ** is completed, even if it created it. However, if the call to @@ -185835,6 +189744,11 @@ struct RbuUpdateStmt { ** it points to an array of flags nTblCol elements in size. The flag is ** set for each column that is either a part of the PK or a part of an ** index. Or clear otherwise. +** +** If there are one or more partial indexes on the table, all fields of +** this array set set to 1. This is because in that case, the module has +** no way to tell which fields will be required to add and remove entries +** from the partial indexes. ** */ struct RbuObjIter { @@ -186000,7 +189914,8 @@ struct rbu_vfs { sqlite3_vfs *pRealVfs; /* Underlying VFS */ sqlite3_mutex *mutex; /* Mutex to protect pMain */ sqlite3rbu *pRbu; /* Owner RBU object */ - rbu_file *pMain; /* Linked list of main db files */ + rbu_file *pMain; /* List of main db files */ + rbu_file *pMainRbu; /* List of main db files with pRbu!=0 */ }; /* @@ -186029,6 +189944,7 @@ struct rbu_file { const char *zWal; /* Wal filename for this main db file */ rbu_file *pWalFd; /* Wal file descriptor for this main db */ rbu_file *pMainNext; /* Next MAIN_DB file */ + rbu_file *pMainRbuNext; /* Next MAIN_DB file with pRbu!=0 */ }; /* @@ -186277,6 +190193,7 @@ static void rbuFossilDeltaFunc( }else{ nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut); if( nOut2!=nOut ){ + sqlite3_free(aOut); sqlite3_result_error(context, "corrupt fossil delta", -1); }else{ sqlite3_result_blob(context, aOut, nOut, sqlite3_free); @@ -186517,7 +190434,8 @@ static void rbuTargetNameFunc( zIn = (const char*)sqlite3_value_text(argv[0]); if( zIn ){ if( rbuIsVacuum(p) ){ - if( argc==1 || 0==sqlite3_value_int(argv[1]) ){ + assert( argc==2 ); + if( 0==sqlite3_value_int(argv[1]) ){ sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC); } }else{ @@ -186627,7 +190545,7 @@ static int rbuMPrintfExec(sqlite3rbu *p, sqlite3 *db, const char *zFmt, ...){ ** immediately without attempting the allocation or modifying the stored ** error code. */ -static void *rbuMalloc(sqlite3rbu *p, int nByte){ +static void *rbuMalloc(sqlite3rbu *p, sqlite3_int64 nByte){ void *pRet = 0; if( p->rc==SQLITE_OK ){ assert( nByte>0 ); @@ -186648,7 +190566,7 @@ static void *rbuMalloc(sqlite3rbu *p, int nByte){ ** error code in the RBU handle passed as the first argument. */ static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){ - int nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol; + sqlite3_int64 nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol; char **azNew; azNew = (char**)rbuMalloc(p, nByte); @@ -186842,8 +190760,12 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){ pIter->nIndex = 0; while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){ const char *zIdx = (const char*)sqlite3_column_text(pList, 1); + int bPartial = sqlite3_column_int(pList, 4); sqlite3_stmt *pXInfo = 0; if( zIdx==0 ) break; + if( bPartial ){ + memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol); + } p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) ); @@ -186964,7 +190886,8 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ } pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc); - pIter->abTblPk[iOrder] = (iPk!=0); + assert( iPk>=0 ); + pIter->abTblPk[iOrder] = (u8)iPk; pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0); iOrder++; } @@ -186999,6 +190922,213 @@ static char *rbuObjIterGetCollist( return zList; } +/* +** Return a comma separated list of the quoted PRIMARY KEY column names, +** in order, for the current table. Before each column name, add the text +** zPre. After each column name, add the zPost text. Use zSeparator as +** the separator text (usually ", "). +*/ +static char *rbuObjIterGetPkList( + sqlite3rbu *p, /* RBU object */ + RbuObjIter *pIter, /* Object iterator for column names */ + const char *zPre, /* Before each quoted column name */ + const char *zSeparator, /* Separator to use between columns */ + const char *zPost /* After each quoted column name */ +){ + int iPk = 1; + char *zRet = 0; + const char *zSep = ""; + while( 1 ){ + int i; + for(i=0; inTblCol; i++){ + if( (int)pIter->abTblPk[i]==iPk ){ + const char *zCol = pIter->azTblCol[i]; + zRet = rbuMPrintf(p, "%z%s%s\"%w\"%s", zRet, zSep, zPre, zCol, zPost); + zSep = zSeparator; + break; + } + } + if( i==pIter->nTblCol ) break; + iPk++; + } + return zRet; +} + +/* +** This function is called as part of restarting an RBU vacuum within +** stage 1 of the process (while the *-oal file is being built) while +** updating a table (not an index). The table may be a rowid table or +** a WITHOUT ROWID table. It queries the target database to find the +** largest key that has already been written to the target table and +** constructs a WHERE clause that can be used to extract the remaining +** rows from the source table. For a rowid table, the WHERE clause +** is of the form: +** +** "WHERE _rowid_ > ?" +** +** and for WITHOUT ROWID tables: +** +** "WHERE (key1, key2) > (?, ?)" +** +** Instead of "?" placeholders, the actual WHERE clauses created by +** this function contain literal SQL values. +*/ +static char *rbuVacuumTableStart( + sqlite3rbu *p, /* RBU handle */ + RbuObjIter *pIter, /* RBU iterator object */ + int bRowid, /* True for a rowid table */ + const char *zWrite /* Target table name prefix */ +){ + sqlite3_stmt *pMax = 0; + char *zRet = 0; + if( bRowid ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg, + sqlite3_mprintf( + "SELECT max(_rowid_) FROM \"%s%w\"", zWrite, pIter->zTbl + ) + ); + if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ + sqlite3_int64 iMax = sqlite3_column_int64(pMax, 0); + zRet = rbuMPrintf(p, " WHERE _rowid_ > %lld ", iMax); + } + rbuFinalize(p, pMax); + }else{ + char *zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", " DESC"); + char *zSelect = rbuObjIterGetPkList(p, pIter, "quote(", "||','||", ")"); + char *zList = rbuObjIterGetPkList(p, pIter, "", ", ", ""); + + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg, + sqlite3_mprintf( + "SELECT %s FROM \"%s%w\" ORDER BY %s LIMIT 1", + zSelect, zWrite, pIter->zTbl, zOrder + ) + ); + if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ + const char *zVal = (const char*)sqlite3_column_text(pMax, 0); + zRet = rbuMPrintf(p, " WHERE (%s) > (%s) ", zList, zVal); + } + rbuFinalize(p, pMax); + } + + sqlite3_free(zOrder); + sqlite3_free(zSelect); + sqlite3_free(zList); + } + return zRet; +} + +/* +** This function is called as part of restating an RBU vacuum when the +** current operation is writing content to an index. If possible, it +** queries the target index b-tree for the largest key already written to +** it, then composes and returns an expression that can be used in a WHERE +** clause to select the remaining required rows from the source table. +** It is only possible to return such an expression if: +** +** * The index contains no DESC columns, and +** * The last key written to the index before the operation was +** suspended does not contain any NULL values. +** +** The expression is of the form: +** +** (index-field1, index-field2, ...) > (?, ?, ...) +** +** except that the "?" placeholders are replaced with literal values. +** +** If the expression cannot be created, NULL is returned. In this case, +** the caller has to use an OFFSET clause to extract only the required +** rows from the sourct table, just as it does for an RBU update operation. +*/ +char *rbuVacuumIndexStart( + sqlite3rbu *p, /* RBU handle */ + RbuObjIter *pIter /* RBU iterator object */ +){ + char *zOrder = 0; + char *zLhs = 0; + char *zSelect = 0; + char *zVector = 0; + char *zRet = 0; + int bFailed = 0; + const char *zSep = ""; + int iCol = 0; + sqlite3_stmt *pXInfo = 0; + + p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, + sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx) + ); + while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ + int iCid = sqlite3_column_int(pXInfo, 1); + const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); + const char *zCol; + if( sqlite3_column_int(pXInfo, 3) ){ + bFailed = 1; + break; + } + + if( iCid<0 ){ + if( pIter->eType==RBU_PK_IPK ){ + int i; + for(i=0; pIter->abTblPk[i]==0; i++); + assert( inTblCol ); + zCol = pIter->azTblCol[i]; + }else{ + zCol = "_rowid_"; + } + }else{ + zCol = pIter->azTblCol[iCid]; + } + + zLhs = rbuMPrintf(p, "%z%s \"%w\" COLLATE %Q", + zLhs, zSep, zCol, zCollate + ); + zOrder = rbuMPrintf(p, "%z%s \"rbu_imp_%d%w\" COLLATE %Q DESC", + zOrder, zSep, iCol, zCol, zCollate + ); + zSelect = rbuMPrintf(p, "%z%s quote(\"rbu_imp_%d%w\")", + zSelect, zSep, iCol, zCol + ); + zSep = ", "; + iCol++; + } + rbuFinalize(p, pXInfo); + if( bFailed ) goto index_start_out; + + if( p->rc==SQLITE_OK ){ + sqlite3_stmt *pSel = 0; + + p->rc = prepareFreeAndCollectError(p->dbMain, &pSel, &p->zErrmsg, + sqlite3_mprintf("SELECT %s FROM \"rbu_imp_%w\" ORDER BY %s LIMIT 1", + zSelect, pIter->zTbl, zOrder + ) + ); + if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSel) ){ + zSep = ""; + for(iCol=0; iColnCol; iCol++){ + const char *zQuoted = (const char*)sqlite3_column_text(pSel, iCol); + if( zQuoted[0]=='N' ){ + bFailed = 1; + break; + } + zVector = rbuMPrintf(p, "%z%s%s", zVector, zSep, zQuoted); + zSep = ", "; + } + + if( !bFailed ){ + zRet = rbuMPrintf(p, "(%s) > (%s)", zLhs, zVector); + } + } + rbuFinalize(p, pSel); + } + + index_start_out: + sqlite3_free(zOrder); + sqlite3_free(zSelect); + sqlite3_free(zVector); + sqlite3_free(zLhs); + return zRet; +} + /* ** This function is used to create a SELECT list (the list of SQL ** expressions that follows a SELECT keyword) for a SELECT statement @@ -187288,7 +191418,7 @@ static char *rbuObjIterGetSetlist( */ static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){ char *zRet = 0; - int nByte = nBind*2 + 1; + sqlite3_int64 nByte = 2*(sqlite3_int64)nBind + 1; zRet = (char*)rbuMalloc(p, nByte); if( zRet ){ @@ -187550,6 +191680,62 @@ static void rbuTmpInsertFunc( } } +static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ + sqlite3_stmt *pStmt = 0; + int rc = p->rc; + char *zRet = 0; + + if( rc==SQLITE_OK ){ + rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, + "SELECT trim(sql) FROM sqlite_master WHERE type='index' AND name=?" + ); + } + if( rc==SQLITE_OK ){ + int rc2; + rc = sqlite3_bind_text(pStmt, 1, pIter->zIdx, -1, SQLITE_STATIC); + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + const char *zSql = (const char*)sqlite3_column_text(pStmt, 0); + if( zSql ){ + int nParen = 0; /* Number of open parenthesis */ + int i; + for(i=0; zSql[i]; i++){ + char c = zSql[i]; + if( c=='(' ){ + nParen++; + } + else if( c==')' ){ + nParen--; + if( nParen==0 ){ + i++; + break; + } + }else if( c=='"' || c=='\'' || c=='`' ){ + for(i++; 1; i++){ + if( zSql[i]==c ){ + if( zSql[i+1]!=c ) break; + i++; + } + } + }else if( c=='[' ){ + for(i++; 1; i++){ + if( zSql[i]==']' ) break; + } + } + } + if( zSql[i] ){ + zRet = rbuStrndup(&zSql[i], &rc); + } + } + } + + rc2 = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ) rc = rc2; + } + + p->rc = rc; + return zRet; +} + /* ** Ensure that the SQLite statement handles required to update the ** target database object currently indicated by the iterator passed @@ -187579,6 +191765,7 @@ static int rbuObjIterPrepareAll( char *zImposterPK = 0; /* Primary key declaration for imposter */ char *zWhere = 0; /* WHERE clause on PK columns */ char *zBind = 0; + char *zPart = 0; int nBind = 0; assert( pIter->eType!=RBU_PK_VTAB ); @@ -187586,6 +191773,7 @@ static int rbuObjIterPrepareAll( p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind ); zBind = rbuObjIterGetBindlist(p, nBind); + zPart = rbuObjIterGetIndexWhere(p, pIter); /* Create the imposter table used to write to this index. */ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1); @@ -187617,39 +191805,58 @@ static int rbuObjIterPrepareAll( if( p->rc==SQLITE_OK ){ char *zSql; if( rbuIsVacuum(p) ){ + char *zStart = 0; + if( nOffset ){ + zStart = rbuVacuumIndexStart(p, pIter); + if( zStart ){ + sqlite3_free(zLimit); + zLimit = 0; + } + } + zSql = sqlite3_mprintf( - "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s", + "SELECT %s, 0 AS rbu_control FROM '%q' %s %s %s ORDER BY %s%s", zCollist, pIter->zDataTbl, + zPart, + (zStart ? (zPart ? "AND" : "WHERE") : ""), zStart, zCollist, zLimit ); + sqlite3_free(zStart); }else if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ zSql = sqlite3_mprintf( - "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s", + "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s ORDER BY %s%s", zCollist, p->zStateDb, pIter->zDataTbl, - zCollist, zLimit + zPart, zCollist, zLimit ); }else{ zSql = sqlite3_mprintf( - "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' " + "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s " "UNION ALL " "SELECT %s, rbu_control FROM '%q' " - "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 " + "%s %s typeof(rbu_control)='integer' AND rbu_control!=1 " "ORDER BY %s%s", - zCollist, p->zStateDb, pIter->zDataTbl, + zCollist, p->zStateDb, pIter->zDataTbl, zPart, zCollist, pIter->zDataTbl, + zPart, + (zPart ? "AND" : "WHERE"), zCollist, zLimit ); } - p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, zSql); + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbRbu,&pIter->pSelect,pz,zSql); + }else{ + sqlite3_free(zSql); + } } sqlite3_free(zImposterCols); sqlite3_free(zImposterPK); sqlite3_free(zWhere); sqlite3_free(zBind); + sqlite3_free(zPart); }else{ int bRbuRowid = (pIter->eType==RBU_PK_VTAB) ||(pIter->eType==RBU_PK_NONE) @@ -187742,18 +191949,42 @@ static int rbuObjIterPrepareAll( /* Create the SELECT statement to read keys from data_xxx */ if( p->rc==SQLITE_OK ){ const char *zRbuRowid = ""; + char *zStart = 0; + char *zOrder = 0; if( bRbuRowid ){ zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid"; } - p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, - sqlite3_mprintf( - "SELECT %s,%s rbu_control%s FROM '%q'%s", - zCollist, - (rbuIsVacuum(p) ? "0 AS " : ""), - zRbuRowid, - pIter->zDataTbl, zLimit - ) - ); + + if( rbuIsVacuum(p) ){ + if( nOffset ){ + zStart = rbuVacuumTableStart(p, pIter, bRbuRowid, zWrite); + if( zStart ){ + sqlite3_free(zLimit); + zLimit = 0; + } + } + if( bRbuRowid ){ + zOrder = rbuMPrintf(p, "_rowid_"); + }else{ + zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", ""); + } + } + + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, + sqlite3_mprintf( + "SELECT %s,%s rbu_control%s FROM '%q'%s %s %s %s", + zCollist, + (rbuIsVacuum(p) ? "0 AS " : ""), + zRbuRowid, + pIter->zDataTbl, (zStart ? zStart : ""), + (zOrder ? "ORDER BY" : ""), zOrder, + zLimit + ) + ); + } + sqlite3_free(zStart); + sqlite3_free(zOrder); } sqlite3_free(zWhere); @@ -188070,7 +192301,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){ if( *zExtra=='\0' ) zExtra = 0; } - zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s", + zTarget = sqlite3_mprintf("file:%s-vactmp?rbu_memory=1%s%s", sqlite3_db_filename(p->dbRbu, "main"), (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra) ); @@ -189336,6 +193567,12 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( const char *zState ){ if( zTarget==0 ){ return rbuMisuseError(); } + if( zState ){ + int n = strlen(zState); + if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){ + return rbuMisuseError(); + } + } /* TODO: Check that both arguments are non-NULL */ return openRbuHandle(0, zTarget, zState); } @@ -189532,7 +193769,10 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){ if( p->eStage==RBU_STAGE_OAL ){ assert( rc!=SQLITE_DONE ); if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0); - if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, 0); + if( rc==SQLITE_OK ){ + const char *zBegin = rbuIsVacuum(p) ? "BEGIN" : "BEGIN IMMEDIATE"; + rc = sqlite3_exec(p->dbRbu, zBegin, 0, 0, 0); + } if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0); } @@ -189625,6 +193865,69 @@ static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){ return SQLITE_OK; } +/* +** Add an item to the main-db lists, if it is not already present. +** +** There are two main-db lists. One for all file descriptors, and one +** for all file descriptors with rbu_file.pDb!=0. If the argument has +** rbu_file.pDb!=0, then it is assumed to already be present on the +** main list and is only added to the pDb!=0 list. +*/ +static void rbuMainlistAdd(rbu_file *p){ + rbu_vfs *pRbuVfs = p->pRbuVfs; + rbu_file *pIter; + assert( (p->openFlags & SQLITE_OPEN_MAIN_DB) ); + sqlite3_mutex_enter(pRbuVfs->mutex); + if( p->pRbu==0 ){ + for(pIter=pRbuVfs->pMain; pIter; pIter=pIter->pMainNext); + p->pMainNext = pRbuVfs->pMain; + pRbuVfs->pMain = p; + }else{ + for(pIter=pRbuVfs->pMainRbu; pIter && pIter!=p; pIter=pIter->pMainRbuNext){} + if( pIter==0 ){ + p->pMainRbuNext = pRbuVfs->pMainRbu; + pRbuVfs->pMainRbu = p; + } + } + sqlite3_mutex_leave(pRbuVfs->mutex); +} + +/* +** Remove an item from the main-db lists. +*/ +static void rbuMainlistRemove(rbu_file *p){ + rbu_file **pp; + sqlite3_mutex_enter(p->pRbuVfs->mutex); + for(pp=&p->pRbuVfs->pMain; *pp && *pp!=p; pp=&((*pp)->pMainNext)){} + if( *pp ) *pp = p->pMainNext; + p->pMainNext = 0; + for(pp=&p->pRbuVfs->pMainRbu; *pp && *pp!=p; pp=&((*pp)->pMainRbuNext)){} + if( *pp ) *pp = p->pMainRbuNext; + p->pMainRbuNext = 0; + sqlite3_mutex_leave(p->pRbuVfs->mutex); +} + +/* +** Given that zWal points to a buffer containing a wal file name passed to +** either the xOpen() or xAccess() VFS method, search the main-db list for +** a file-handle opened by the same database connection on the corresponding +** database file. +** +** If parameter bRbu is true, only search for file-descriptors with +** rbu_file.pDb!=0. +*/ +static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal, int bRbu){ + rbu_file *pDb; + sqlite3_mutex_enter(pRbuVfs->mutex); + if( bRbu ){ + for(pDb=pRbuVfs->pMainRbu; pDb && pDb->zWal!=zWal; pDb=pDb->pMainRbuNext){} + }else{ + for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){} + } + sqlite3_mutex_leave(pRbuVfs->mutex); + return pDb; +} + /* ** Close an rbu file. */ @@ -189642,17 +193945,14 @@ static int rbuVfsClose(sqlite3_file *pFile){ sqlite3_free(p->zDel); if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ - rbu_file **pp; - sqlite3_mutex_enter(p->pRbuVfs->mutex); - for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext)); - *pp = p->pMainNext; - sqlite3_mutex_leave(p->pRbuVfs->mutex); + rbuMainlistRemove(p); rbuUnlockShm(p); p->pReal->pMethods->xShmUnmap(p->pReal, 0); } else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){ rbuUpdateTempSize(p, 0); } + assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p ); /* Close the underlying file handle */ rc = p->pReal->pMethods->xClose(p->pReal); @@ -189911,6 +194211,7 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){ }else if( rc==SQLITE_NOTFOUND ){ pRbu->pTargetFd = p; p->pRbu = pRbu; + rbuMainlistAdd(p); if( p->pWalFd ) p->pWalFd->pRbu = pRbu; rc = SQLITE_OK; } @@ -189973,10 +194274,7 @@ static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){ if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY; }else{ int bCapture = 0; - if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE) - && pRbu && pRbu->eStage==RBU_STAGE_CAPTURE - && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0) - ){ + if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){ bCapture = 1; } @@ -190009,20 +194307,24 @@ static int rbuVfsShmMap( ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space ** instead of a file on disk. */ assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); - if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){ - if( iRegion<=p->nShm ){ - int nByte = (iRegion+1) * sizeof(char*); - char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte); - if( apNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm)); - p->apShm = apNew; - p->nShm = iRegion+1; - } + if( eStage==RBU_STAGE_OAL ){ + sqlite3_int64 nByte = (iRegion+1) * sizeof(char*); + char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte); + + /* This is an RBU connection that uses its own heap memory for the + ** pages of the *-shm file. Since no other process can have run + ** recovery, the connection must request *-shm pages in order + ** from start to finish. */ + assert( iRegion==p->nShm ); + if( apNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm)); + p->apShm = apNew; + p->nShm = iRegion+1; } - if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){ + if( rc==SQLITE_OK ){ char *pNew = (char*)sqlite3_malloc64(szRegion); if( pNew==0 ){ rc = SQLITE_NOMEM; @@ -190072,20 +194374,6 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){ return rc; } -/* -** Given that zWal points to a buffer containing a wal file name passed to -** either the xOpen() or xAccess() VFS method, return a pointer to the -** file-handle opened by the same database connection on the corresponding -** database file. -*/ -static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){ - rbu_file *pDb; - sqlite3_mutex_enter(pRbuVfs->mutex); - for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){} - sqlite3_mutex_leave(pRbuVfs->mutex); - return pDb; -} - /* ** A main database named zName has just been opened. The following ** function returns a pointer to a buffer owned by SQLite that contains @@ -190164,7 +194452,7 @@ static int rbuVfsOpen( pFd->zWal = rbuMainToWal(zName, flags); } else if( flags & SQLITE_OPEN_WAL ){ - rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName); + rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0); if( pDb ){ if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ /* This call is to open a *-wal file. Intead, open the *-oal. This @@ -190216,10 +194504,7 @@ static int rbuVfsOpen( ** mutex protected linked list of all such files. */ pFile->pMethods = &rbuvfs_io_methods; if( flags & SQLITE_OPEN_MAIN_DB ){ - sqlite3_mutex_enter(pRbuVfs->mutex); - pFd->pMainNext = pRbuVfs->pMain; - pRbuVfs->pMain = pFd; - sqlite3_mutex_leave(pRbuVfs->mutex); + rbuMainlistAdd(pFd); } }else{ sqlite3_free(pFd->zDel); @@ -190267,8 +194552,9 @@ static int rbuVfsAccess( ** file opened instead. */ if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){ - rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath); - if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ + rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1); + if( pDb && pDb->pRbu->eStage==RBU_STAGE_OAL ){ + assert( pDb->pRbu ); if( *pResOut ){ rc = SQLITE_CANTOPEN; }else{ @@ -190680,17 +194966,15 @@ static int statDisconnect(sqlite3_vtab *pVtab){ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; - pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */ - /* Look for a valid schema=? constraint. If found, change the idxNum to ** 1 and request the value of that constraint be sent to xFilter. And ** lower the cost estimate to encourage the constrained version to be ** used. */ for(i=0; inConstraint; i++){ - if( pIdxInfo->aConstraint[i].usable==0 ) continue; - if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; if( pIdxInfo->aConstraint[i].iColumn!=10 ) continue; + if( pIdxInfo->aConstraint[i].usable==0 ) return SQLITE_CONSTRAINT; + if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; pIdxInfo->idxNum = 1; pIdxInfo->estimatedCost = 1.0; pIdxInfo->aConstraintUsage[i].argvIndex = 1; @@ -190740,7 +195024,7 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ return SQLITE_OK; } -static void statClearPage(StatPage *p){ +static void statClearCells(StatPage *p){ int i; if( p->aCell ){ for(i=0; inCell; i++){ @@ -190748,6 +195032,12 @@ static void statClearPage(StatPage *p){ } sqlite3_free(p->aCell); } + p->nCell = 0; + p->aCell = 0; +} + +static void statClearPage(StatPage *p){ + statClearCells(p); sqlite3PagerUnref(p->pPg); sqlite3_free(p->zPath); memset(p, 0, sizeof(StatPage)); @@ -190810,22 +195100,33 @@ static int statDecodePage(Btree *pBt, StatPage *p){ u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; p->flags = aHdr[0]; + if( p->flags==0x0A || p->flags==0x0D ){ + isLeaf = 1; + nHdr = 8; + }else if( p->flags==0x05 || p->flags==0x02 ){ + isLeaf = 0; + nHdr = 12; + }else{ + goto statPageIsCorrupt; + } + if( p->iPgno==1 ) nHdr += 100; p->nCell = get2byte(&aHdr[3]); p->nMxPayload = 0; - - isLeaf = (p->flags==0x0A || p->flags==0x0D); - nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100; + szPage = sqlite3BtreeGetPageSize(pBt); nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell; nUnused += (int)aHdr[7]; iOff = get2byte(&aHdr[1]); while( iOff ){ + int iNext; + if( iOff>=szPage ) goto statPageIsCorrupt; nUnused += get2byte(&aData[iOff+2]); - iOff = get2byte(&aData[iOff]); + iNext = get2byte(&aData[iOff]); + if( iNext0 ) goto statPageIsCorrupt; + iOff = iNext; } p->nUnused = nUnused; p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]); - szPage = sqlite3BtreeGetPageSize(pBt); if( p->nCell ){ int i; /* Used to iterate through cells */ @@ -190842,6 +195143,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ StatCell *pCell = &p->aCell[i]; iOff = get2byte(&aData[nHdr+i*2]); + if( iOff=szPage ) goto statPageIsCorrupt; if( !isLeaf ){ pCell->iChildPg = sqlite3Get4byte(&aData[iOff]); iOff += 4; @@ -190858,13 +195160,14 @@ static int statDecodePage(Btree *pBt, StatPage *p){ } if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload; getLocalPayload(nUsable, p->flags, nPayload, &nLocal); + if( nLocal<0 ) goto statPageIsCorrupt; pCell->nLocal = nLocal; - assert( nLocal>=0 ); assert( nPayload>=(u32)nLocal ); assert( nLocal<=(nUsable-35) ); if( nPayload>(u32)nLocal ){ int j; int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); + if( iOff+nLocal>nUsable ) goto statPageIsCorrupt; pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); pCell->nOvfl = nOvfl; pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl); @@ -190888,6 +195191,11 @@ static int statDecodePage(Btree *pBt, StatPage *p){ } return SQLITE_OK; + +statPageIsCorrupt: + p->flags = 0; + statClearCells(p); + return SQLITE_OK; } /* @@ -190995,6 +195303,10 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ goto statNextRestart; /* Tail recursion */ } pCsr->iPage++; + if( pCsr->iPage>=ArraySize(pCsr->aPage) ){ + statResetCsr(pCsr); + return SQLITE_CORRUPT_BKPT; + } assert( p==&pCsr->aPage[pCsr->iPage-1] ); if( p->iCell==p->nCell ){ @@ -191066,7 +195378,6 @@ static int statFilter( StatTable *pTab = (StatTable*)(pCursor->pVtab); char *zSql; int rc = SQLITE_OK; - char *zMaster; if( idxNum==1 ){ const char *zDbase = (const char*)sqlite3_value_text(argv[0]); @@ -191082,13 +195393,12 @@ static int statFilter( statResetCsr(pCsr); sqlite3_finalize(pCsr->pStmt); pCsr->pStmt = 0; - zMaster = pCsr->iDb==1 ? "sqlite_temp_master" : "sqlite_master"; zSql = sqlite3_mprintf( "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type" " UNION ALL " "SELECT name, rootpage, type" - " FROM \"%w\".%s WHERE rootpage!=0" - " ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster); + " FROM \"%w\".sqlite_master WHERE rootpage!=0" + " ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName); if( zSql==0 ){ return SQLITE_NOMEM_BKPT; }else{ @@ -191183,6 +195493,7 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0 /* xShadowName */ }; return sqlite3_create_module(db, "dbstat", &dbstat_module, 0); } @@ -191313,9 +195624,8 @@ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue; if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; if( !p->usable ){ - /* No solution. Use the default SQLITE_BIG_DBL cost */ - pIdxInfo->estimatedRows = 0x7fffffff; - return SQLITE_OK; + /* No solution. */ + return SQLITE_CONSTRAINT; } iPlan = 2; pIdxInfo->aConstraintUsage[i].argvIndex = 1; @@ -191507,6 +195817,10 @@ static int dbpageUpdate( Pager *pPager; int szPage; + if( pTab->db->flags & SQLITE_Defensive ){ + zErr = "read-only"; + goto update_fail; + } if( argc==1 ){ zErr = "cannot delete"; goto update_fail; @@ -191597,6 +195911,7 @@ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0 /* xShadowName */ }; return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); } @@ -191633,6 +195948,8 @@ typedef struct SessionInput SessionInput; # endif #endif +static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE; + typedef struct SessionHook SessionHook; struct SessionHook { void *pCtx; @@ -191695,6 +196012,7 @@ struct sqlite3_changeset_iter { SessionInput in; /* Input buffer or stream */ SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */ int bPatchset; /* True if this is a patchset */ + int bInvert; /* True to invert changeset */ int rc; /* Iterator error code */ sqlite3_stmt *pConflict; /* Points to conflicting row, if any */ char *zTab; /* Current table */ @@ -191851,6 +196169,42 @@ struct SessionTable { ** The records associated with INSERT changes are in the same format as for ** changesets. It is not possible for a record associated with an INSERT ** change to contain a field set to "undefined". +** +** REBASE BLOB FORMAT: +** +** A rebase blob may be output by sqlite3changeset_apply_v2() and its +** streaming equivalent for use with the sqlite3_rebaser APIs to rebase +** existing changesets. A rebase blob contains one entry for each conflict +** resolved using either the OMIT or REPLACE strategies within the apply_v2() +** call. +** +** The format used for a rebase blob is very similar to that used for +** changesets. All entries related to a single table are grouped together. +** +** Each group of entries begins with a table header in changeset format: +** +** 1 byte: Constant 0x54 (capital 'T') +** Varint: Number of columns in the table. +** nCol bytes: 0x01 for PK columns, 0x00 otherwise. +** N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated. +** +** Followed by one or more entries associated with the table. +** +** 1 byte: Either SQLITE_INSERT (0x12), DELETE (0x09). +** 1 byte: Flag. 0x01 for REPLACE, 0x00 for OMIT. +** record: (in the record format defined above). +** +** In a rebase blob, the first field is set to SQLITE_INSERT if the change +** that caused the conflict was an INSERT or UPDATE, or to SQLITE_DELETE if +** it was a DELETE. The second field is set to 0x01 if the conflict +** resolution strategy was REPLACE, or 0x00 if it was OMIT. +** +** If the change that caused the conflict was a DELETE, then the single +** record is a copy of the old.* record from the original changeset. If it +** was an INSERT, then the single record is a copy of the new.* record. If +** the conflicting change was an UPDATE, then the single record is a copy +** of the new.* record with the PK fields filled in based on the original +** old.* record. */ /* @@ -191932,7 +196286,7 @@ static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){ static int sessionSerializeValue( u8 *aBuf, /* If non-NULL, write serialized value here */ sqlite3_value *pValue, /* Value to serialize */ - int *pnWrite /* IN/OUT: Increment by bytes written */ + sqlite3_int64 *pnWrite /* IN/OUT: Increment by bytes written */ ){ int nByte; /* Size of serialized value in bytes */ @@ -192471,9 +196825,9 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){ if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){ int i; SessionChange **apNew; - int nNew = (pTab->nChange ? pTab->nChange : 128) * 2; + sqlite3_int64 nNew = 2*(sqlite3_int64)(pTab->nChange ? pTab->nChange : 128); - apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew); + apNew = (SessionChange **)sqlite3_malloc64(sizeof(SessionChange *) * nNew); if( apNew==0 ){ if( pTab->nChange==0 ){ return SQLITE_ERROR; @@ -192539,7 +196893,7 @@ static int sessionTableInfo( char *zPragma; sqlite3_stmt *pStmt; int rc; - int nByte; + sqlite3_int64 nByte; int nDbCol = 0; int nThis; int i; @@ -192582,7 +196936,7 @@ static int sessionTableInfo( if( rc==SQLITE_OK ){ nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1); - pAlloc = sqlite3_malloc(nByte); + pAlloc = sqlite3_malloc64(nByte); if( pAlloc==0 ){ rc = SQLITE_NOMEM; } @@ -192723,7 +197077,7 @@ static void sessionPreupdateOneChange( int iHash; int bNull = 0; int rc = SQLITE_OK; - SessionStat1Ctx stat1 = {0}; + SessionStat1Ctx stat1 = {{0,0,0,0,0},0}; if( pSession->rc ) return; @@ -192780,7 +197134,7 @@ static void sessionPreupdateOneChange( ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK ** values (if this is an INSERT). */ SessionChange *pChange; /* New change object */ - int nByte; /* Number of bytes to allocate */ + sqlite3_int64 nByte; /* Number of bytes to allocate */ int i; /* Used to iterate through columns */ assert( rc==SQLITE_OK ); @@ -192805,7 +197159,7 @@ static void sessionPreupdateOneChange( } /* Allocate the change object */ - pChange = (SessionChange *)sqlite3_malloc(nByte); + pChange = (SessionChange *)sqlite3_malloc64(nByte); if( !pChange ){ rc = SQLITE_NOMEM; goto error_out; @@ -193193,7 +197547,9 @@ SQLITE_API int sqlite3session_diff( } sqlite3_free((char*)azCol); if( bMismatch ){ - *pzErrMsg = sqlite3_mprintf("table schemas do not match"); + if( pzErrMsg ){ + *pzErrMsg = sqlite3_mprintf("table schemas do not match"); + } rc = SQLITE_SCHEMA; } if( bHasPk==0 ){ @@ -193249,7 +197605,7 @@ SQLITE_API int sqlite3session_create( *ppSession = 0; /* Allocate and populate the new session object. */ - pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1); + pNew = (sqlite3_session *)sqlite3_malloc64(sizeof(sqlite3_session) + nDb + 1); if( !pNew ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(sqlite3_session)); pNew->db = db; @@ -193368,7 +197724,7 @@ SQLITE_API int sqlite3session_attach( if( !pTab ){ /* Allocate new SessionTable object. */ - pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1); + pTab = (SessionTable *)sqlite3_malloc64(sizeof(SessionTable) + nName + 1); if( !pTab ){ rc = SQLITE_NOMEM; }else{ @@ -193398,15 +197754,15 @@ SQLITE_API int sqlite3session_attach( ** If successful, return zero. Otherwise, if an OOM condition is encountered, ** set *pRc to SQLITE_NOMEM and return non-zero. */ -static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){ - if( *pRc==SQLITE_OK && p->nAlloc-p->nBufnAlloc-p->nBuf)nAlloc ? p->nAlloc : 128; + i64 nNew = p->nAlloc ? p->nAlloc : 128; do { nNew = nNew*2; - }while( nNew<(p->nBuf+nByte) ); + }while( (nNew-p->nBuf)aBuf, nNew); + aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew); if( 0==aNew ){ *pRc = SQLITE_NOMEM; }else{ @@ -193428,7 +197784,7 @@ static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){ static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){ int rc = *pRc; if( rc==SQLITE_OK ){ - int nByte = 0; + sqlite3_int64 nByte = 0; rc = sessionSerializeValue(0, pVal, &nByte); sessionBufferGrow(p, nByte, &rc); if( rc==SQLITE_OK ){ @@ -194004,12 +198360,12 @@ static int sessionGenerateChangeset( rc = sqlite3_reset(pSel); } - /* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass + /* If the buffer is now larger than sessions_strm_chunk_size, pass ** its contents to the xOutput() callback. */ if( xOutput && rc==SQLITE_OK && buf.nBuf>nNoop - && buf.nBuf>SESSIONS_STRM_CHUNK_SIZE + && buf.nBuf>sessions_strm_chunk_size ){ rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf); nNoop = -1; @@ -194148,7 +198504,8 @@ static int sessionChangesetStart( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int nChangeset, /* Size of buffer pChangeset in bytes */ - void *pChangeset /* Pointer to buffer containing changeset */ + void *pChangeset, /* Pointer to buffer containing changeset */ + int bInvert /* True to invert changeset */ ){ sqlite3_changeset_iter *pRet; /* Iterator to return */ int nByte; /* Number of bytes to allocate for iterator */ @@ -194168,6 +198525,7 @@ static int sessionChangesetStart( pRet->in.xInput = xInput; pRet->in.pIn = pIn; pRet->in.bEof = (xInput ? 0 : 1); + pRet->bInvert = bInvert; /* Populate the output variable and return success. */ *pp = pRet; @@ -194182,7 +198540,16 @@ SQLITE_API int sqlite3changeset_start( int nChangeset, /* Size of buffer pChangeset in bytes */ void *pChangeset /* Pointer to buffer containing changeset */ ){ - return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset); + return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0); +} +SQLITE_API int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int nChangeset, /* Size of buffer pChangeset in bytes */ + void *pChangeset, /* Pointer to buffer containing changeset */ + int flags +){ + int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); + return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert); } /* @@ -194193,7 +198560,16 @@ SQLITE_API int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ){ - return sessionChangesetStart(pp, xInput, pIn, 0, 0); + return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0); +} +SQLITE_API int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +){ + int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); + return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert); } /* @@ -194201,7 +198577,7 @@ SQLITE_API int sqlite3changeset_start_strm( ** object and the buffer is full, discard some data to free up space. */ static void sessionDiscardData(SessionInput *pIn){ - if( pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){ + if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){ int nMove = pIn->buf.nBuf - pIn->iNext; assert( nMove>=0 ); if( nMove>0 ){ @@ -194224,7 +198600,7 @@ static int sessionInputBuffer(SessionInput *pIn, int nByte){ int rc = SQLITE_OK; if( pIn->xInput ){ while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){ - int nNew = SESSIONS_STRM_CHUNK_SIZE; + int nNew = sessions_strm_chunk_size; if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn); if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){ @@ -194284,7 +198660,7 @@ static int sessionValueSetStr( ** argument to sqlite3ValueSetStr() and have the copy created ** automatically. But doing so makes it difficult to detect any OOM ** error. Hence the code to create the copy externally. */ - u8 *aCopy = sqlite3_malloc(nData+1); + u8 *aCopy = sqlite3_malloc64((sqlite3_int64)nData+1); if( aCopy==0 ) return SQLITE_NOMEM; memcpy(aCopy, aData, nData); sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free); @@ -194496,7 +198872,7 @@ static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){ } if( rc==SQLITE_OK ){ - int iPK = sizeof(sqlite3_value*)*p->nCol*2; + size_t iPK = sizeof(sqlite3_value*)*p->nCol*2; memset(p->tblhdr.aBuf, 0, iPK); memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy); p->in.iNext += nCopy; @@ -194572,10 +198948,10 @@ static int sessionChangesetNext( op = p->in.aData[p->in.iNext++]; } - if( p->zTab==0 ){ + if( p->zTab==0 || (p->bPatchset && p->bInvert) ){ /* The first record in the changeset is not a table header. Must be a ** corrupt changeset. */ - assert( p->in.iNext==1 ); + assert( p->in.iNext==1 || p->zTab ); return (p->rc = SQLITE_CORRUPT_BKPT); } @@ -194600,33 +198976,39 @@ static int sessionChangesetNext( *paRec = &p->in.aData[p->in.iNext]; p->in.iNext += *pnRec; }else{ + sqlite3_value **apOld = (p->bInvert ? &p->apValue[p->nCol] : p->apValue); + sqlite3_value **apNew = (p->bInvert ? p->apValue : &p->apValue[p->nCol]); /* If this is an UPDATE or DELETE, read the old.* record. */ if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){ u8 *abPK = p->bPatchset ? p->abPK : 0; - p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue); + p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld); if( p->rc!=SQLITE_OK ) return p->rc; } /* If this is an INSERT or UPDATE, read the new.* record. */ if( p->op!=SQLITE_DELETE ){ - p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]); + p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew); if( p->rc!=SQLITE_OK ) return p->rc; } - if( p->bPatchset && p->op==SQLITE_UPDATE ){ + if( (p->bPatchset || p->bInvert) && p->op==SQLITE_UPDATE ){ /* If this is an UPDATE that is part of a patchset, then all PK and ** modified fields are present in the new.* record. The old.* record ** is currently completely empty. This block shifts the PK fields from ** new.* to old.*, to accommodate the code that reads these arrays. */ for(i=0; inCol; i++){ - assert( p->apValue[i]==0 ); + assert( p->bPatchset==0 || p->apValue[i]==0 ); if( p->abPK[i] ){ + assert( p->apValue[i]==0 ); p->apValue[i] = p->apValue[i+p->nCol]; if( p->apValue[i]==0 ) return (p->rc = SQLITE_CORRUPT_BKPT); p->apValue[i+p->nCol] = 0; } } + }else if( p->bInvert ){ + if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE; + else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT; } } @@ -194891,7 +199273,7 @@ static int sessionChangesetInvert( int iCol; if( 0==apVal ){ - apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2); + apVal = (sqlite3_value **)sqlite3_malloc64(sizeof(apVal[0])*nCol*2); if( 0==apVal ){ rc = SQLITE_NOMEM; goto finished_invert; @@ -194943,7 +199325,7 @@ static int sessionChangesetInvert( } assert( rc==SQLITE_OK ); - if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){ + if( xOutput && sOut.nBuf>=sessions_strm_chunk_size ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); sOut.nBuf = 0; if( rc!=SQLITE_OK ) goto finished_invert; @@ -195022,7 +199404,8 @@ struct SessionApplyCtx { int bDeferConstraints; /* True to defer constraints */ SessionBuffer constraints; /* Deferred constraints are stored here */ SessionBuffer rebase; /* Rebase information (if any) here */ - int bRebaseStarted; /* If table header is already in rebase */ + u8 bRebaseStarted; /* If table header is already in rebase */ + u8 bRebase; /* True to collect rebase information */ }; /* @@ -195404,7 +199787,7 @@ static int sessionSeekToRow( } /* -** This function is called from within sqlite3changset_apply_v2() when +** This function is called from within sqlite3changeset_apply_v2() when ** a conflict is encountered and resolved using conflict resolution ** mode eType (either SQLITE_CHANGESET_OMIT or SQLITE_CHANGESET_REPLACE).. ** It adds a conflict resolution record to the buffer in @@ -195419,35 +199802,36 @@ static int sessionRebaseAdd( sqlite3_changeset_iter *pIter /* Iterator pointing at current change */ ){ int rc = SQLITE_OK; - int i; - int eOp = pIter->op; - if( p->bRebaseStarted==0 ){ - /* Append a table-header to the rebase buffer */ - const char *zTab = pIter->zTab; - sessionAppendByte(&p->rebase, 'T', &rc); - sessionAppendVarint(&p->rebase, p->nCol, &rc); - sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc); - sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc); - p->bRebaseStarted = 1; - } - - assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT ); - assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE ); - - sessionAppendByte(&p->rebase, - (eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc - ); - sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc); - for(i=0; inCol; i++){ - sqlite3_value *pVal = 0; - if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){ - sqlite3changeset_old(pIter, i, &pVal); - }else{ - sqlite3changeset_new(pIter, i, &pVal); + if( p->bRebase ){ + int i; + int eOp = pIter->op; + if( p->bRebaseStarted==0 ){ + /* Append a table-header to the rebase buffer */ + const char *zTab = pIter->zTab; + sessionAppendByte(&p->rebase, 'T', &rc); + sessionAppendVarint(&p->rebase, p->nCol, &rc); + sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc); + sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc); + p->bRebaseStarted = 1; } - sessionAppendValue(&p->rebase, pVal, &rc); - } + assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT ); + assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE ); + + sessionAppendByte(&p->rebase, + (eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc + ); + sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc); + for(i=0; inCol; i++){ + sqlite3_value *pVal = 0; + if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){ + sqlite3changeset_old(pIter, i, &pVal); + }else{ + sqlite3changeset_new(pIter, i, &pVal); + } + sessionAppendValue(&p->rebase, pVal, &rc); + } + } return rc; } @@ -195790,9 +200174,9 @@ static int sessionRetryConstraints( SessionBuffer cons = pApply->constraints; memset(&pApply->constraints, 0, sizeof(SessionBuffer)); - rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf); + rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0); if( rc==SQLITE_OK ){ - int nByte = 2*pApply->nCol*sizeof(sqlite3_value*); + size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*); int rc2; pIter2->bPatchset = bPatchset; pIter2->zTab = (char*)zTab; @@ -195856,6 +200240,7 @@ static int sessionChangesetApply( pIter->in.bNoDiscard = 1; memset(&sApply, 0, sizeof(sApply)); + sApply.bRebase = (ppRebase && pnRebase); sqlite3_mutex_enter(sqlite3_db_mutex(db)); if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); @@ -196006,7 +200391,8 @@ static int sessionChangesetApply( } } - if( rc==SQLITE_OK && bPatchset==0 && ppRebase && pnRebase ){ + assert( sApply.bRebase || sApply.rebase.nBuf==0 ); + if( rc==SQLITE_OK && bPatchset==0 && sApply.bRebase ){ *ppRebase = (void*)sApply.rebase.aBuf; *pnRebase = sApply.rebase.nBuf; sApply.rebase.aBuf = 0; @@ -196044,7 +200430,8 @@ SQLITE_API int sqlite3changeset_apply_v2( int flags ){ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ - int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); + int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); + int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset,bInverse); if( rc==SQLITE_OK ){ rc = sessionChangesetApply( db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags @@ -196101,7 +200488,8 @@ SQLITE_API int sqlite3changeset_apply_v2_strm( int flags ){ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ - int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn); + int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); + int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse); if( rc==SQLITE_OK ){ rc = sessionChangesetApply( db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags @@ -196158,7 +200546,7 @@ static int sessionChangeMerge( int rc = SQLITE_OK; if( !pExist ){ - pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec); + pNew = (SessionChange *)sqlite3_malloc64(sizeof(SessionChange) + nRec); if( !pNew ){ return SQLITE_NOMEM; } @@ -196191,8 +200579,8 @@ static int sessionChangeMerge( if( pExist->op==SQLITE_DELETE && pExist->bIndirect ){ *ppNew = pExist; }else{ - int nByte = nRec + pExist->nRecord + sizeof(SessionChange); - pNew = (SessionChange*)sqlite3_malloc(nByte); + sqlite3_int64 nByte = nRec + pExist->nRecord + sizeof(SessionChange); + pNew = (SessionChange*)sqlite3_malloc64(nByte); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ @@ -196252,14 +200640,14 @@ static int sessionChangeMerge( assert( pNew==0 ); }else{ u8 *aExist = pExist->aRecord; - int nByte; + sqlite3_int64 nByte; u8 *aCsr; /* Allocate a new SessionChange object. Ensure that the aRecord[] ** buffer of the new object is large enough to hold any record that ** may be generated by combining the input records. */ nByte = sizeof(SessionChange) + pExist->nRecord + nRec; - pNew = (SessionChange *)sqlite3_malloc(nByte); + pNew = (SessionChange *)sqlite3_malloc64(nByte); if( !pNew ){ sqlite3_free(pExist); return SQLITE_NOMEM; @@ -196365,7 +200753,7 @@ static int sessionChangesetToHash( if( !pTab ){ SessionTable **ppTab; - pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1); + pTab = sqlite3_malloc64(sizeof(SessionTable) + nCol + nNew+1); if( !pTab ){ rc = SQLITE_NOMEM; break; @@ -196474,13 +200862,12 @@ static int sessionChangegroupOutput( sessionAppendByte(&buf, p->op, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc); + if( rc==SQLITE_OK && xOutput && buf.nBuf>=sessions_strm_chunk_size ){ + rc = xOutput(pOut, buf.aBuf, buf.nBuf); + buf.nBuf = 0; + } } } - - if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){ - rc = xOutput(pOut, buf.aBuf, buf.nBuf); - buf.nBuf = 0; - } } if( rc==SQLITE_OK ){ @@ -196871,7 +201258,7 @@ static int sessionRebase( sessionAppendByte(&sOut, pIter->bIndirect, &rc); sessionAppendBlob(&sOut, aRec, nRec, &rc); } - if( rc==SQLITE_OK && xOutput && sOut.nBuf>SESSIONS_STRM_CHUNK_SIZE ){ + if( rc==SQLITE_OK && xOutput && sOut.nBuf>sessions_strm_chunk_size ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); sOut.nBuf = 0; } @@ -196982,6 +201369,27 @@ SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p){ } } +/* +** Global configuration +*/ +SQLITE_API int sqlite3session_config(int op, void *pArg){ + int rc = SQLITE_OK; + switch( op ){ + case SQLITE_SESSION_CONFIG_STRMSIZE: { + int *pInt = (int*)pArg; + if( *pInt>0 ){ + sessions_strm_chunk_size = *pInt; + } + *pInt = sessions_strm_chunk_size; + break; + } + default: + rc = SQLITE_MISUSE; + break; + } + return rc; +} + #endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */ /************** End of sqlite3session.c **************************************/ @@ -197119,12 +201527,8 @@ struct Fts5PhraseIter { ** ** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. The exception is if the table was created -** with the offsets=0 option specified. In this case *piOff is always -** set to -1. -** -** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) -** if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. @@ -197165,7 +201569,7 @@ struct Fts5PhraseIter { ** Save the pointer passed as the second argument as the extension functions ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of -** of the same MATCH query using the xGetAuxdata() API. +** the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for ** each FTS query (MATCH expression). If the extension function is invoked @@ -197180,7 +201584,7 @@ struct Fts5PhraseIter { ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** -** If an error (e.g. an OOM condition) occurs within this function, an +** If an error (e.g. an OOM condition) occurs within this function, ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. @@ -197413,11 +201817,11 @@ struct Fts5ExtensionApi { ** the tokenizer substitutes "first" for "1st" and the query works ** as expected. ** -**
  • By adding multiple synonyms for a single term to the FTS index. -** In this case, when tokenizing query text, the tokenizer may -** provide multiple synonyms for a single term within the document. -** FTS5 then queries the index for each synonym individually. For -** example, faced with the query: +**
  • By querying the index for all synonyms of each query term +** separately. In this case, when tokenizing query text, the +** tokenizer may provide multiple synonyms for a single term +** within the document. FTS5 then queries the index for each +** synonym individually. For example, faced with the query: ** ** ** ... MATCH 'first place' @@ -197441,7 +201845,7 @@ struct Fts5ExtensionApi { ** "place". ** ** This way, even if the tokenizer does not provide synonyms -** when tokenizing query text (it should not - to do would be +** when tokenizing query text (it should not - to do so would be ** inefficient), it doesn't matter if the user queries for ** 'first + place' or '1st + place', as there are entries in the ** FTS index corresponding to both forms of the first token. @@ -197666,6 +202070,12 @@ SQLITE_API extern int sqlite3_fts5_may_be_corrupt; # define assert_nc(x) assert(x) #endif +/* +** A version of memcmp() that does not cause asan errors if one of the pointer +** parameters is NULL and the number of bytes to compare is zero. +*/ +#define fts5Memcmp(s1, s2, n) ((n)==0 ? 0 : memcmp((s1), (s2), (n))) + /* Mark a function parameter as unused, to suppress nuisance compiler ** warnings. */ #ifndef UNUSED_PARAM @@ -197853,7 +202263,7 @@ static void sqlite3Fts5Put32(u8*, int); static int sqlite3Fts5Get32(const u8*); #define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32) -#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0xFFFFFFFF) +#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF) typedef struct Fts5PoslistReader Fts5PoslistReader; struct Fts5PoslistReader { @@ -197888,7 +202298,7 @@ static int sqlite3Fts5PoslistNext64( ); /* Malloc utility */ -static void *sqlite3Fts5MallocZero(int *pRc, int nByte); +static void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte); static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn); /* Character set tests (like isspace(), isalpha() etc.) */ @@ -198099,9 +202509,19 @@ static int sqlite3Fts5PutVarint(unsigned char *p, u64 v); /************************************************************************** -** Interface to code in fts5.c. +** Interface to code in fts5_main.c. */ +/* +** Virtual-table object. +*/ +typedef struct Fts5Table Fts5Table; +struct Fts5Table { + sqlite3_vtab base; /* Base class used by SQLite core */ + Fts5Config *pConfig; /* Virtual table configuration */ + Fts5Index *pIndex; /* Full-text index */ +}; + static int sqlite3Fts5GetTokenizer( Fts5Global*, const char **azArg, @@ -198111,7 +202531,9 @@ static int sqlite3Fts5GetTokenizer( char **pzErr ); -static Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, Fts5Config **); +static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64); + +static int sqlite3Fts5FlushToDisk(Fts5Table*); /* ** End of interface to code in fts5.c. @@ -198144,8 +202566,9 @@ static void sqlite3Fts5HashClear(Fts5Hash*); static int sqlite3Fts5HashQuery( Fts5Hash*, /* Hash table to query */ + int nPre, const char *pTerm, int nTerm, /* Query term */ - const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */ + void **ppObj, /* OUT: Pointer to doclist for pTerm */ int *pnDoclist /* OUT: Size of doclist in bytes */ ); @@ -198367,7 +202790,7 @@ static int sqlite3Fts5UnicodeIsdiacritic(int c); static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); static int sqlite3Fts5UnicodeCatParse(const char*, u8*); -static int sqlite3Fts5UnicodeCategory(int iCode); +static int sqlite3Fts5UnicodeCategory(u32 iCode); static void sqlite3Fts5UnicodeAscii(u8*, u8*); /* ** End of interface to code in fts5_unicode2.c. @@ -198416,6 +202839,7 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*); ** input grammar file: */ /* #include */ +/* #include */ /************ Begin %include sections from the grammar ************************/ /* #include "fts5Int.h" */ @@ -199270,41 +203694,70 @@ static void fts5yy_shift( fts5yyTraceShift(fts5yypParser, fts5yyNewState, "Shift"); } -/* The following table contains information about every rule that -** is used during the reduce. -*/ -static const struct { - fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ - signed char nrhs; /* Negative of the number of RHS symbols in the rule */ -} fts5yyRuleInfo[] = { - { 16, -1 }, /* (0) input ::= expr */ - { 20, -4 }, /* (1) colset ::= MINUS LCP colsetlist RCP */ - { 20, -3 }, /* (2) colset ::= LCP colsetlist RCP */ - { 20, -1 }, /* (3) colset ::= STRING */ - { 20, -2 }, /* (4) colset ::= MINUS STRING */ - { 21, -2 }, /* (5) colsetlist ::= colsetlist STRING */ - { 21, -1 }, /* (6) colsetlist ::= STRING */ - { 17, -3 }, /* (7) expr ::= expr AND expr */ - { 17, -3 }, /* (8) expr ::= expr OR expr */ - { 17, -3 }, /* (9) expr ::= expr NOT expr */ - { 17, -5 }, /* (10) expr ::= colset COLON LP expr RP */ - { 17, -3 }, /* (11) expr ::= LP expr RP */ - { 17, -1 }, /* (12) expr ::= exprlist */ - { 19, -1 }, /* (13) exprlist ::= cnearset */ - { 19, -2 }, /* (14) exprlist ::= exprlist cnearset */ - { 18, -1 }, /* (15) cnearset ::= nearset */ - { 18, -3 }, /* (16) cnearset ::= colset COLON nearset */ - { 22, -1 }, /* (17) nearset ::= phrase */ - { 22, -2 }, /* (18) nearset ::= CARET phrase */ - { 22, -5 }, /* (19) nearset ::= STRING LP nearphrases neardist_opt RP */ - { 23, -1 }, /* (20) nearphrases ::= phrase */ - { 23, -2 }, /* (21) nearphrases ::= nearphrases phrase */ - { 25, 0 }, /* (22) neardist_opt ::= */ - { 25, -2 }, /* (23) neardist_opt ::= COMMA STRING */ - { 24, -4 }, /* (24) phrase ::= phrase PLUS STRING star_opt */ - { 24, -2 }, /* (25) phrase ::= STRING star_opt */ - { 26, -1 }, /* (26) star_opt ::= STAR */ - { 26, 0 }, /* (27) star_opt ::= */ +/* For rule J, fts5yyRuleInfoLhs[J] contains the symbol on the left-hand side +** of that rule */ +static const fts5YYCODETYPE fts5yyRuleInfoLhs[] = { + 16, /* (0) input ::= expr */ + 20, /* (1) colset ::= MINUS LCP colsetlist RCP */ + 20, /* (2) colset ::= LCP colsetlist RCP */ + 20, /* (3) colset ::= STRING */ + 20, /* (4) colset ::= MINUS STRING */ + 21, /* (5) colsetlist ::= colsetlist STRING */ + 21, /* (6) colsetlist ::= STRING */ + 17, /* (7) expr ::= expr AND expr */ + 17, /* (8) expr ::= expr OR expr */ + 17, /* (9) expr ::= expr NOT expr */ + 17, /* (10) expr ::= colset COLON LP expr RP */ + 17, /* (11) expr ::= LP expr RP */ + 17, /* (12) expr ::= exprlist */ + 19, /* (13) exprlist ::= cnearset */ + 19, /* (14) exprlist ::= exprlist cnearset */ + 18, /* (15) cnearset ::= nearset */ + 18, /* (16) cnearset ::= colset COLON nearset */ + 22, /* (17) nearset ::= phrase */ + 22, /* (18) nearset ::= CARET phrase */ + 22, /* (19) nearset ::= STRING LP nearphrases neardist_opt RP */ + 23, /* (20) nearphrases ::= phrase */ + 23, /* (21) nearphrases ::= nearphrases phrase */ + 25, /* (22) neardist_opt ::= */ + 25, /* (23) neardist_opt ::= COMMA STRING */ + 24, /* (24) phrase ::= phrase PLUS STRING star_opt */ + 24, /* (25) phrase ::= STRING star_opt */ + 26, /* (26) star_opt ::= STAR */ + 26, /* (27) star_opt ::= */ +}; + +/* For rule J, fts5yyRuleInfoNRhs[J] contains the negative of the number +** of symbols on the right-hand side of that rule. */ +static const signed char fts5yyRuleInfoNRhs[] = { + -1, /* (0) input ::= expr */ + -4, /* (1) colset ::= MINUS LCP colsetlist RCP */ + -3, /* (2) colset ::= LCP colsetlist RCP */ + -1, /* (3) colset ::= STRING */ + -2, /* (4) colset ::= MINUS STRING */ + -2, /* (5) colsetlist ::= colsetlist STRING */ + -1, /* (6) colsetlist ::= STRING */ + -3, /* (7) expr ::= expr AND expr */ + -3, /* (8) expr ::= expr OR expr */ + -3, /* (9) expr ::= expr NOT expr */ + -5, /* (10) expr ::= colset COLON LP expr RP */ + -3, /* (11) expr ::= LP expr RP */ + -1, /* (12) expr ::= exprlist */ + -1, /* (13) exprlist ::= cnearset */ + -2, /* (14) exprlist ::= exprlist cnearset */ + -1, /* (15) cnearset ::= nearset */ + -3, /* (16) cnearset ::= colset COLON nearset */ + -1, /* (17) nearset ::= phrase */ + -2, /* (18) nearset ::= CARET phrase */ + -5, /* (19) nearset ::= STRING LP nearphrases neardist_opt RP */ + -1, /* (20) nearphrases ::= phrase */ + -2, /* (21) nearphrases ::= nearphrases phrase */ + 0, /* (22) neardist_opt ::= */ + -2, /* (23) neardist_opt ::= COMMA STRING */ + -4, /* (24) phrase ::= phrase PLUS STRING star_opt */ + -2, /* (25) phrase ::= STRING star_opt */ + -1, /* (26) star_opt ::= STAR */ + 0, /* (27) star_opt ::= */ }; static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */ @@ -199336,7 +203789,7 @@ static fts5YYACTIONTYPE fts5yy_reduce( fts5yymsp = fts5yypParser->fts5yytos; #ifndef NDEBUG if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){ - fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs; + fts5yysize = fts5yyRuleInfoNRhs[fts5yyruleno]; if( fts5yysize ){ fprintf(fts5yyTraceFILE, "%sReduce %d [%s], go to state %d.\n", fts5yyTracePrompt, @@ -199351,7 +203804,7 @@ static fts5YYACTIONTYPE fts5yy_reduce( /* Check that the stack is large enough to grow by a single entry ** if the RHS of the rule is empty. This ensures that there is room ** enough on the stack to push the LHS value */ - if( fts5yyRuleInfo[fts5yyruleno].nrhs==0 ){ + if( fts5yyRuleInfoNRhs[fts5yyruleno]==0 ){ #ifdef fts5YYTRACKMAXSTACKDEPTH if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){ fts5yypParser->fts5yyhwm++; @@ -199535,9 +203988,9 @@ static fts5YYACTIONTYPE fts5yy_reduce( break; /********** End reduce actions ************************************************/ }; - assert( fts5yyrulenofts5yytos >= fts5yypParser->fts5yystack - && fts5yymx != fts5YYERRORSYMBOL && (fts5yyact = fts5yy_find_reduce_action( fts5yypParser->fts5yytos->stateno, - fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE + fts5YYERRORSYMBOL)) > fts5YY_MAX_SHIFTREDUCE ){ fts5yy_pop_parser_stack(fts5yypParser); } @@ -199969,7 +204421,7 @@ static void fts5HighlightAppend( HighlightContext *p, const char *z, int n ){ - if( *pRc==SQLITE_OK ){ + if( *pRc==SQLITE_OK && z ){ if( n<0 ) n = (int)strlen(z); p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z); if( p->zOut==0 ) *pRc = SQLITE_NOMEM; @@ -200101,7 +204553,7 @@ static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){ int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64; int *aNew; - aNew = (int*)sqlite3_realloc(p->aFirst, nNew*sizeof(int)); + aNew = (int*)sqlite3_realloc64(p->aFirst, nNew*sizeof(int)); if( aNew==0 ) return SQLITE_NOMEM; p->aFirst = aNew; p->nFirstAlloc = nNew; @@ -200168,11 +204620,12 @@ static int fts5SnippetScore( int nInst; int nScore = 0; int iLast = 0; + sqlite3_int64 iEnd = (sqlite3_int64)iPos + nToken; rc = pApi->xInstCount(pFts, &nInst); for(i=0; ixInst(pFts, i, &ip, &ic, &iOff); - if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<(iPos+nToken) ){ + if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOffnDocsize ) iAdj = nDocsize - nToken; if( iAdj<0 ) iAdj = 0; - *piPos = iAdj; + *piPos = (int)iAdj; } return rc; @@ -200275,7 +204728,9 @@ static void fts5SnippetFunction( int jj; rc = pApi->xInst(pFts, ii, &ip, &ic, &io); - if( ic!=i || rc!=SQLITE_OK ) continue; + if( ic!=i ) continue; + if( io>nDocsize ) rc = FTS5_CORRUPT; + if( rc!=SQLITE_OK ) continue; memset(aSeen, 0, nPhrase); rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i, io, nToken, &nScore, &iAdj @@ -200401,17 +204856,17 @@ static int fts5Bm25GetData( int nPhrase; /* Number of phrases in query */ sqlite3_int64 nRow = 0; /* Number of rows in table */ sqlite3_int64 nToken = 0; /* Number of tokens in table */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ int i; /* Allocate the Fts5Bm25Data object */ nPhrase = pApi->xPhraseCount(pFts); nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double); - p = (Fts5Bm25Data*)sqlite3_malloc(nByte); + p = (Fts5Bm25Data*)sqlite3_malloc64(nByte); if( p==0 ){ rc = SQLITE_NOMEM; }else{ - memset(p, 0, nByte); + memset(p, 0, (size_t)nByte); p->nPhrase = nPhrase; p->aIDF = (double*)&p[1]; p->aFreq = &p->aIDF[nPhrase]; @@ -200419,6 +204874,7 @@ static int fts5Bm25GetData( /* Calculate the average document length for this FTS5 table */ if( rc==SQLITE_OK ) rc = pApi->xRowCount(pFts, &nRow); + assert( rc!=SQLITE_OK || nRow>0 ); if( rc==SQLITE_OK ) rc = pApi->xColumnTotalSize(pFts, -1, &nToken); if( rc==SQLITE_OK ) p->avgdl = (double)nToken / (double)nRow; @@ -200544,8 +205000,6 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){ return rc; } - - /* ** 2014 May 31 ** @@ -200565,17 +205019,17 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){ static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){ if( (u32)pBuf->nSpacenSpace ? pBuf->nSpace : 64; + u64 nNew = pBuf->nSpace ? pBuf->nSpace : 64; u8 *pNew; while( nNewp, nNew); + pNew = sqlite3_realloc64(pBuf->p, nNew); if( pNew==0 ){ *pRc = SQLITE_NOMEM; return 1; }else{ - pBuf->nSpace = nNew; + pBuf->nSpace = (int)nNew; pBuf->p = pNew; } } @@ -200600,7 +205054,7 @@ static void sqlite3Fts5Put32(u8 *aBuf, int iVal){ } static int sqlite3Fts5Get32(const u8 *aBuf){ - return (aBuf[0] << 24) + (aBuf[1] << 16) + (aBuf[2] << 8) + aBuf[3]; + return (int)((((u32)aBuf[0])<<24) + (aBuf[1]<<16) + (aBuf[2]<<8) + aBuf[3]); } /* @@ -200726,12 +205180,21 @@ static int sqlite3Fts5PoslistNext64( i64 iOff = *piOff; int iVal; fts5FastGetVarint32(a, i, iVal); - if( iVal==1 ){ + if( iVal<=1 ){ + if( iVal==0 ){ + *pi = i; + return 0; + } fts5FastGetVarint32(a, i, iVal); iOff = ((i64)iVal) << 32; fts5FastGetVarint32(a, i, iVal); + if( iVal<2 ){ + /* This is a corrupt record. So stop parsing it here. */ + *piOff = -1; + return 1; + } } - *piOff = iOff + (iVal-2); + *piOff = iOff + ((iVal-2) & 0x7FFFFFFF); *pi = i; return 0; } @@ -200792,14 +205255,14 @@ static int sqlite3Fts5PoslistWriterAppend( return SQLITE_OK; } -static void *sqlite3Fts5MallocZero(int *pRc, int nByte){ +static void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte){ void *pRet = 0; if( *pRc==SQLITE_OK ){ - pRet = sqlite3_malloc(nByte); + pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ if( nByte>0 ) *pRc = SQLITE_NOMEM; }else{ - memset(pRet, 0, nByte); + memset(pRet, 0, (size_t)nByte); } } return pRet; @@ -201238,7 +205701,7 @@ static int fts5ConfigParseSpecial( if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){ const char *p = (const char*)zArg; - int nArg = (int)strlen(zArg) + 1; + sqlite3_int64 nArg = strlen(zArg) + 1; char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg); char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2); char *pSpace = pDel; @@ -201268,7 +205731,7 @@ static int fts5ConfigParseSpecial( rc = SQLITE_ERROR; }else{ rc = sqlite3Fts5GetTokenizer(pGlobal, - (const char**)azArg, nArg, &pConfig->pTok, &pConfig->pTokApi, + (const char**)azArg, (int)nArg, &pConfig->pTok, &pConfig->pTokApi, pzErr ); } @@ -201368,8 +205831,8 @@ static const char *fts5ConfigGobbleWord( ){ const char *zRet = 0; - int nIn = (int)strlen(zIn); - char *zOut = sqlite3_malloc(nIn+1); + sqlite3_int64 nIn = strlen(zIn); + char *zOut = sqlite3_malloc64(nIn+1); assert( *pRc==SQLITE_OK ); *pbQuoted = 0; @@ -201378,7 +205841,7 @@ static const char *fts5ConfigGobbleWord( if( zOut==0 ){ *pRc = SQLITE_NOMEM; }else{ - memcpy(zOut, zIn, nIn+1); + memcpy(zOut, zIn, (size_t)(nIn+1)); if( fts5_isopenquote(zOut[0]) ){ int ii = fts5Dequote(zOut); zRet = &zIn[ii]; @@ -201472,7 +205935,7 @@ static int sqlite3Fts5ConfigParse( int rc = SQLITE_OK; /* Return code */ Fts5Config *pRet; /* New object to return */ int i; - int nByte; + sqlite3_int64 nByte; *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config)); if( pRet==0 ) return SQLITE_NOMEM; @@ -202116,7 +206579,7 @@ static int fts5ExprGetToken( return tok; } -static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); } +static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc64((sqlite3_int64)t);} static void fts5ParseFree(void *p){ sqlite3_free(p); } static int sqlite3Fts5ExprNew( @@ -202261,8 +206724,8 @@ static int fts5ExprSynonymList( if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){ if( pIter->nData==0 ) continue; if( nIter==nAlloc ){ - int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2; - Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte); + sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nAlloc * 2; + Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc64(nByte); if( aNew==0 ){ rc = SQLITE_NOMEM; goto synonym_poslist_out; @@ -202342,8 +206805,8 @@ static int fts5ExprPhraseIsMatch( /* If the aStatic[] array is not large enough, allocate a large array ** using sqlite3_malloc(). This approach could be improved upon. */ if( pPhrase->nTerm>ArraySize(aStatic) ){ - int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm; - aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte); + sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm; + aIter = (Fts5PoslistReader*)sqlite3_malloc64(nByte); if( !aIter ) return SQLITE_NOMEM; } memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm); @@ -202477,7 +206940,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){ /* If the aStatic[] array is not large enough, allocate a large array ** using sqlite3_malloc(). This approach could be improved upon. */ if( pNear->nPhrase>ArraySize(aStatic) ){ - int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase; + sqlite3_int64 nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase; a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte); }else{ memset(aStatic, 0, sizeof(aStatic)); @@ -203386,18 +207849,20 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( return pNear; } if( pNear==0 ){ - int nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); - pRet = sqlite3_malloc(nByte); + sqlite3_int64 nByte; + nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); + pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; }else{ - memset(pRet, 0, nByte); + memset(pRet, 0, (size_t)nByte); } }else if( (pNear->nPhrase % SZALLOC)==0 ){ int nNew = pNear->nPhrase + SZALLOC; - int nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*); + sqlite3_int64 nByte; - pRet = (Fts5ExprNearset*)sqlite3_realloc(pNear, nByte); + nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*); + pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; } @@ -203461,12 +207926,12 @@ static int fts5ParseTokenize( if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){ Fts5ExprTerm *pSyn; - int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1; - pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte); + sqlite3_int64 nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1; + pSyn = (Fts5ExprTerm*)sqlite3_malloc64(nByte); if( pSyn==0 ){ rc = SQLITE_NOMEM; }else{ - memset(pSyn, 0, nByte); + memset(pSyn, 0, (size_t)nByte); pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); memcpy(pSyn->zTerm, pToken, nToken); pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; @@ -203478,7 +207943,7 @@ static int fts5ParseTokenize( Fts5ExprPhrase *pNew; int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0); - pNew = (Fts5ExprPhrase*)sqlite3_realloc(pPhrase, + pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase, sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew ); if( pNew==0 ){ @@ -203564,9 +208029,9 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( if( pAppend==0 ){ if( (pParse->nPhrase % 8)==0 ){ - int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); + sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); Fts5ExprPhrase **apNew; - apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte); + apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte); if( apNew==0 ){ pParse->rc = SQLITE_NOMEM; fts5ExprPhraseFree(sCtx.pPhrase); @@ -203621,10 +208086,12 @@ static int sqlite3Fts5ExprClonePhrase( if( rc==SQLITE_OK ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ - int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); - Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); + sqlite3_int64 nByte; + Fts5Colset *pColset; + nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); + pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); if( pColset ){ - memcpy(pColset, pColsetOrig, nByte); + memcpy(pColset, pColsetOrig, (size_t)nByte); } pNew->pRoot->pNear->pColset = pColset; } @@ -203742,7 +208209,7 @@ static Fts5Colset *fts5ParseColset( assert( pParse->rc==SQLITE_OK ); assert( iCol>=0 && iColpConfig->nCol ); - pNew = sqlite3_realloc(p, sizeof(Fts5Colset) + sizeof(int)*nCol); + pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol); if( pNew==0 ){ pParse->rc = SQLITE_NOMEM; }else{ @@ -203838,10 +208305,10 @@ static Fts5Colset *sqlite3Fts5ParseColset( static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){ Fts5Colset *pRet; if( pOrig ){ - int nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int); + sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int); pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte); if( pRet ){ - memcpy(pRet, pOrig, nByte); + memcpy(pRet, pOrig, (size_t)nByte); } }else{ pRet = 0; @@ -203992,7 +208459,7 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( if( pParse->rc==SQLITE_OK ){ int nChild = 0; /* Number of children of returned node */ - int nByte; /* Bytes of space to allocate for this node */ + sqlite3_int64 nByte; /* Bytes of space to allocate for this node */ assert( (eType!=FTS5_STRING && !pNear) || (eType==FTS5_STRING && !pLeft && !pRight) @@ -204124,7 +208591,7 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( } static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ - int nByte = 0; + sqlite3_int64 nByte = 0; Fts5ExprTerm *p; char *zQuoted; @@ -204132,7 +208599,7 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ for(p=pTerm; p; p=p->pSynonym){ nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2; } - zQuoted = sqlite3_malloc(nByte); + zQuoted = sqlite3_malloc64(nByte); if( zQuoted ){ int i = 0; @@ -204372,7 +208839,7 @@ static void fts5ExprFunction( } nConfig = 3 + (nArg-iArg); - azConfig = (const char**)sqlite3_malloc(sizeof(char*) * nConfig); + azConfig = (const char**)sqlite3_malloc64(sizeof(char*) * nConfig); if( azConfig==0 ){ sqlite3_result_error_nomem(pCtx); return; @@ -204458,7 +208925,7 @@ static void fts5ExprIsAlnum( sqlite3Fts5UnicodeCatParse("N*", aArr); sqlite3Fts5UnicodeCatParse("Co", aArr); iCode = sqlite3_value_int(apVal[0]); - sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory(iCode)]); + sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory((u32)iCode)]); } static void fts5ExprFold( @@ -204553,7 +209020,7 @@ struct Fts5PoslistPopulator { static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){ Fts5PoslistPopulator *pRet; - pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); + pRet = sqlite3_malloc64(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); if( pRet ){ int i; memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); @@ -204753,7 +209220,6 @@ static int sqlite3Fts5ExprPhraseCollist( return rc; } - /* ** 2014 August 11 ** @@ -204846,20 +209312,20 @@ static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ - int nByte; + sqlite3_int64 nByte; memset(pNew, 0, sizeof(Fts5Hash)); pNew->pnByte = pnByte; pNew->eDetail = pConfig->eDetail; pNew->nSlot = 1024; nByte = sizeof(Fts5HashEntry*) * pNew->nSlot; - pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte); + pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc64(nByte); if( pNew->aSlot==0 ){ sqlite3_free(pNew); *ppNew = 0; rc = SQLITE_NOMEM; }else{ - memset(pNew->aSlot, 0, nByte); + memset(pNew->aSlot, 0, (size_t)nByte); } } return rc; @@ -204921,7 +209387,7 @@ static int fts5HashResize(Fts5Hash *pHash){ Fts5HashEntry **apNew; Fts5HashEntry **apOld = pHash->aSlot; - apNew = (Fts5HashEntry**)sqlite3_malloc(nNew*sizeof(Fts5HashEntry*)); + apNew = (Fts5HashEntry**)sqlite3_malloc64(nNew*sizeof(Fts5HashEntry*)); if( !apNew ) return SQLITE_NOMEM; memset(apNew, 0, nNew*sizeof(Fts5HashEntry*)); @@ -204943,19 +209409,25 @@ static int fts5HashResize(Fts5Hash *pHash){ return SQLITE_OK; } -static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ +static int fts5HashAddPoslistSize( + Fts5Hash *pHash, + Fts5HashEntry *p, + Fts5HashEntry *p2 +){ + int nRet = 0; if( p->iSzPoslist ){ - u8 *pPtr = (u8*)p; + u8 *pPtr = p2 ? (u8*)p2 : (u8*)p; + int nData = p->nData; if( pHash->eDetail==FTS5_DETAIL_NONE ){ - assert( p->nData==p->iSzPoslist ); + assert( nData==p->iSzPoslist ); if( p->bDel ){ - pPtr[p->nData++] = 0x00; + pPtr[nData++] = 0x00; if( p->bContent ){ - pPtr[p->nData++] = 0x00; + pPtr[nData++] = 0x00; } } }else{ - int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ + int nSz = (nData - p->iSzPoslist - 1); /* Size in bytes */ int nPos = nSz*2 + p->bDel; /* Value of nPos field */ assert( p->bDel==0 || p->bDel==1 ); @@ -204965,14 +209437,19 @@ static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ int nByte = sqlite3Fts5GetVarintLen((u32)nPos); memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); - p->nData += (nByte-1); + nData += (nByte-1); } } - p->iSzPoslist = 0; - p->bDel = 0; - p->bContent = 0; + nRet = nData - p->nData; + if( p2==0 ){ + p->iSzPoslist = 0; + p->bDel = 0; + p->bContent = 0; + p->nData = nData; + } } + return nRet; } /* @@ -205015,7 +209492,7 @@ static int sqlite3Fts5HashWrite( if( p==0 ){ /* Figure out how much space to allocate */ char *zKey; - int nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64; + sqlite3_int64 nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64; if( nByte<128 ) nByte = 128; /* Grow the Fts5Hash.aSlot[] array if necessary. */ @@ -205026,10 +209503,10 @@ static int sqlite3Fts5HashWrite( } /* Allocate new Fts5HashEntry and add it to the hash table. */ - p = (Fts5HashEntry*)sqlite3_malloc(nByte); + p = (Fts5HashEntry*)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, sizeof(Fts5HashEntry)); - p->nAlloc = nByte; + p->nAlloc = (int)nByte; zKey = fts5EntryKey(p); zKey[0] = bByte; memcpy(&zKey[1], pToken, nToken); @@ -205065,12 +209542,12 @@ static int sqlite3Fts5HashWrite( ** + 5 bytes for the new position offset (32-bit max). */ if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ - int nNew = p->nAlloc * 2; + sqlite3_int64 nNew = p->nAlloc * 2; Fts5HashEntry *pNew; Fts5HashEntry **pp; - pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); + pNew = (Fts5HashEntry*)sqlite3_realloc64(p, nNew); if( pNew==0 ) return SQLITE_NOMEM; - pNew->nAlloc = nNew; + pNew->nAlloc = (int)nNew; for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); *pp = pNew; p = pNew; @@ -205084,7 +209561,7 @@ static int sqlite3Fts5HashWrite( /* If this is a new rowid, append the 4-byte size field for the previous ** entry, and the new rowid for this entry. */ if( iRowid!=p->iRowid ){ - fts5HashAddPoslistSize(pHash, p); + fts5HashAddPoslistSize(pHash, p, 0); p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); p->iRowid = iRowid; bNew = 1; @@ -205194,14 +209671,16 @@ static int fts5HashEntrySort( int i; *ppSorted = 0; - ap = sqlite3_malloc(sizeof(Fts5HashEntry*) * nMergeSlot); + ap = sqlite3_malloc64(sizeof(Fts5HashEntry*) * nMergeSlot); if( !ap ) return SQLITE_NOMEM; memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot); for(iSlot=0; iSlotnSlot; iSlot++){ Fts5HashEntry *pIter; for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){ - if( pTerm==0 || 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm) ){ + if( pTerm==0 + || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm)) + ){ Fts5HashEntry *pEntry = pIter; pEntry->pScanNext = 0; for(i=0; ap[i]; i++){ @@ -205229,8 +209708,9 @@ static int fts5HashEntrySort( */ static int sqlite3Fts5HashQuery( Fts5Hash *pHash, /* Hash table to query */ + int nPre, const char *pTerm, int nTerm, /* Query term */ - const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */ + void **ppOut, /* OUT: Pointer to new object */ int *pnDoclist /* OUT: Size of doclist in bytes */ ){ unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm); @@ -205239,15 +209719,25 @@ static int sqlite3Fts5HashQuery( for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ zKey = fts5EntryKey(p); - if( memcmp(zKey, pTerm, nTerm)==0 && zKey[nTerm]==0 ) break; + assert( p->nKey+1==(int)strlen(zKey) ); + if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break; } if( p ){ - fts5HashAddPoslistSize(pHash, p); - *ppDoclist = (const u8*)&zKey[nTerm+1]; - *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); + int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1; + int nList = p->nData - nHashPre; + u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10)); + if( pRet ){ + Fts5HashEntry *pFaux = (Fts5HashEntry*)&pRet[nPre-nHashPre]; + memcpy(&pRet[nPre], &((u8*)p)[nHashPre], nList); + nList += fts5HashAddPoslistSize(pHash, p, pFaux); + *pnDoclist = nList; + }else{ + *pnDoclist = 0; + return SQLITE_NOMEM; + } }else{ - *ppDoclist = 0; + *ppOut = 0; *pnDoclist = 0; } @@ -205280,7 +209770,7 @@ static void sqlite3Fts5HashScanEntry( if( (p = pHash->pScan) ){ char *zKey = fts5EntryKey(p); int nTerm = (int)strlen(zKey); - fts5HashAddPoslistSize(pHash, p); + fts5HashAddPoslistSize(pHash, p, 0); *pzTerm = zKey; *ppDoclist = (const u8*)&zKey[nTerm+1]; *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); @@ -205291,7 +209781,6 @@ static void sqlite3Fts5HashScanEntry( } } - /* ** 2014 May 31 ** @@ -205806,7 +210295,6 @@ struct Fts5Iter { Fts5IndexIter base; /* Base class containing output vars */ Fts5Index *pIndex; /* Index that owns this iterator */ - Fts5Structure *pStruct; /* Database structure for this iterator */ Fts5Buffer poslist; /* Buffer containing current poslist */ Fts5Colset *pColset; /* Restrict matches to these columns */ @@ -205867,7 +210355,7 @@ static u16 fts5GetU16(const u8 *aIn){ ** If an OOM error is encountered, return NULL and set the error code in ** the Fts5Index handle passed as the first argument. */ -static void *fts5IdxMalloc(Fts5Index *p, int nByte){ +static void *fts5IdxMalloc(Fts5Index *p, sqlite3_int64 nByte){ return sqlite3Fts5MallocZero(&p->rc, nByte); } @@ -205901,7 +210389,7 @@ static int fts5BufferCompareBlob( */ static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){ int nCmp = MIN(pLeft->n, pRight->n); - int res = memcmp(pLeft->p, pRight->p, nCmp); + int res = fts5Memcmp(pLeft->p, pRight->p, nCmp); return (res==0 ? (pLeft->n - pRight->n) : res); } @@ -205967,8 +210455,8 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ if( rc==SQLITE_OK ){ u8 *aOut = 0; /* Read blob data into this buffer */ int nByte = sqlite3_blob_bytes(p->pReader); - int nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING; - pRet = (Fts5Data*)sqlite3_malloc(nAlloc); + sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING; + pRet = (Fts5Data*)sqlite3_malloc64(nAlloc); if( pRet ){ pRet->nn = nByte; aOut = pRet->p = (u8*)&pRet[1]; @@ -205984,6 +210472,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ pRet = 0; }else{ /* TODO1: Fix this */ + pRet->p[nByte] = 0x00; pRet->szLeaf = fts5GetU16(&pRet->p[2]); } } @@ -206023,7 +210512,8 @@ static int fts5IndexPrepareStmt( if( p->rc==SQLITE_OK ){ if( zSql ){ p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1, - SQLITE_PREPARE_PERSISTENT, ppStmt, 0); + SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB, + ppStmt, 0); }else{ p->rc = SQLITE_NOMEM; } @@ -206064,23 +210554,12 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){ if( p->rc!=SQLITE_OK ) return; if( p->pDeleter==0 ){ - int rc; Fts5Config *pConfig = p->pConfig; char *zSql = sqlite3_mprintf( "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?", pConfig->zDb, pConfig->zName ); - if( zSql==0 ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, - SQLITE_PREPARE_PERSISTENT, &p->pDeleter, 0); - sqlite3_free(zSql); - } - if( rc!=SQLITE_OK ){ - p->rc = rc; - return; - } + if( fts5IndexPrepareStmt(p, &p->pDeleter, zSql) ) return; } sqlite3_bind_int64(p->pDeleter, 1, iFirst); @@ -206152,7 +210631,7 @@ static int fts5StructureDecode( int iLvl; int nLevel = 0; int nSegment = 0; - int nByte; /* Bytes of space to allocate at pRet */ + sqlite3_int64 nByte; /* Bytes of space to allocate at pRet */ Fts5Structure *pRet = 0; /* Structure object to return */ /* Grab the cookie value */ @@ -206163,6 +210642,11 @@ static int fts5StructureDecode( ** structure record. */ i += fts5GetVarint32(&pData[i], nLevel); i += fts5GetVarint32(&pData[i], nSegment); + if( nLevel>FTS5_MAX_SEGMENT || nLevel<0 + || nSegment>FTS5_MAX_SEGMENT || nSegment<0 + ){ + return FTS5_CORRUPT; + } nByte = ( sizeof(Fts5Structure) + /* Main structure */ sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */ @@ -206185,25 +210669,35 @@ static int fts5StructureDecode( }else{ i += fts5GetVarint32(&pData[i], pLvl->nMerge); i += fts5GetVarint32(&pData[i], nTotal); - assert( nTotal>=pLvl->nMerge ); + if( nTotalnMerge ) rc = FTS5_CORRUPT; pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, nTotal * sizeof(Fts5StructureSegment) ); + nSegment -= nTotal; } if( rc==SQLITE_OK ){ pLvl->nSeg = nTotal; for(iSeg=0; iSegaSeg[iSeg]; if( i>=nData ){ rc = FTS5_CORRUPT; break; } - i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid); - i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst); - i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast); + i += fts5GetVarint32(&pData[i], pSeg->iSegid); + i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst); + i += fts5GetVarint32(&pData[i], pSeg->pgnoLast); + if( pSeg->pgnoLastpgnoFirst ){ + rc = FTS5_CORRUPT; + break; + } } + if( iLvl>0 && pLvl[-1].nMerge && nTotal==0 ) rc = FTS5_CORRUPT; + if( iLvl==nLevel-1 && pLvl->nMerge ) rc = FTS5_CORRUPT; } } + if( nSegment!=0 && rc==SQLITE_OK ) rc = FTS5_CORRUPT; + if( rc!=SQLITE_OK ){ fts5StructureRelease(pRet); pRet = 0; @@ -206221,12 +210715,12 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){ if( *pRc==SQLITE_OK ){ Fts5Structure *pStruct = *ppStruct; int nLevel = pStruct->nLevel; - int nByte = ( + sqlite3_int64 nByte = ( sizeof(Fts5Structure) + /* Main structure */ sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */ ); - pStruct = sqlite3_realloc(pStruct, nByte); + pStruct = sqlite3_realloc64(pStruct, nByte); if( pStruct ){ memset(&pStruct->aLevel[nLevel], 0, sizeof(Fts5StructureLevel)); pStruct->nLevel++; @@ -206251,10 +210745,10 @@ static void fts5StructureExtendLevel( if( *pRc==SQLITE_OK ){ Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; Fts5StructureSegment *aNew; - int nByte; + sqlite3_int64 nByte; nByte = (pLvl->nSeg + nExtra) * sizeof(Fts5StructureSegment); - aNew = sqlite3_realloc(pLvl->aSeg, nByte); + aNew = sqlite3_realloc64(pLvl->aSeg, nByte); if( aNew ){ if( bInsert==0 ){ memset(&aNew[pLvl->nSeg], 0, sizeof(Fts5StructureSegment) * nExtra); @@ -206281,7 +210775,7 @@ static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){ /* TODO: Do we need this if the leaf-index is appended? Probably... */ memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING); p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet); - if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){ + if( p->rc==SQLITE_OK && (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){ p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); } fts5DataRelease(pData); @@ -206768,10 +211262,10 @@ static Fts5DlidxIter *fts5DlidxIterInit( int bDone = 0; for(i=0; p->rc==SQLITE_OK && bDone==0; i++){ - int nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl); + sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl); Fts5DlidxIter *pNew; - pNew = (Fts5DlidxIter*)sqlite3_realloc(pIter, nByte); + pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte); if( pNew==0 ){ p->rc = SQLITE_NOMEM; }else{ @@ -206941,12 +211435,13 @@ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){ int nNew; /* Bytes of new data */ iOff += fts5GetVarint32(&a[iOff], nNew); - if( iOff+nNew>pIter->pLeaf->nn ){ + if( iOff+nNew>pIter->pLeaf->szLeaf || nKeep>pIter->term.n || nNew==0 ){ p->rc = FTS5_CORRUPT; return; } pIter->term.n = nKeep; fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]); + assert( pIter->term.n<=pIter->term.nSpace ); iOff += nNew; pIter->iTermLeafOffset = iOff; pIter->iTermLeafPgno = pIter->iLeafPgno; @@ -207011,7 +211506,7 @@ static void fts5SegIterInit( if( p->rc==SQLITE_OK ){ pIter->iLeafOffset = 4; assert_nc( pIter->pLeaf->nn>4 ); - assert( fts5LeafFirstTermOff(pIter->pLeaf)==4 ); + assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 ); pIter->iPgidxOff = pIter->pLeaf->szLeaf+1; fts5SegIterLoadTerm(p, pIter, 0); fts5SegIterLoadNPos(p, pIter); @@ -207067,7 +211562,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ /* If necessary, grow the pIter->aRowidOffset[] array. */ if( iRowidOffset>=pIter->nRowidOffset ){ int nNew = pIter->nRowidOffset + 8; - int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int)); + int *aNew = (int*)sqlite3_realloc64(pIter->aRowidOffset,nNew*sizeof(int)); if( aNew==0 ){ p->rc = SQLITE_NOMEM; break; @@ -207521,10 +212016,10 @@ static void fts5LeafSeek( int szLeaf = pIter->pLeaf->szLeaf; int n = pIter->pLeaf->nn; - int nMatch = 0; - int nKeep = 0; - int nNew = 0; - int iTermOff; + u32 nMatch = 0; + u32 nKeep = 0; + u32 nNew = 0; + u32 iTermOff; int iPgidx; /* Current offset in pgidx */ int bEndOfPage = 0; @@ -207548,15 +212043,15 @@ static void fts5LeafSeek( assert( nKeep>=nMatch ); if( nKeep==nMatch ){ - int nCmp; - int i; - nCmp = MIN(nNew, nTerm-nMatch); + u32 nCmp; + u32 i; + nCmp = (u32)MIN(nNew, nTerm-nMatch); for(i=0; ipLeaf->p[iPgidx], iOff); if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){ p->rc = FTS5_CORRUPT; + return; }else{ nKeep = 0; iTermOff = iOff; @@ -207612,8 +212108,11 @@ static void fts5LeafSeek( } search_success: - pIter->iLeafOffset = iOff + nNew; + if( pIter->iLeafOffset>n || nNew<1 ){ + p->rc = FTS5_CORRUPT; + return; + } pIter->iTermLeafOffset = pIter->iLeafOffset; pIter->iTermLeafPgno = pIter->iLeafPgno; @@ -207720,7 +212219,7 @@ static void fts5SegIterSeekInit( ** 4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points ** to an entry with a term greater than or equal to (pTerm/nTerm). */ - assert( p->rc!=SQLITE_OK /* 1 */ + assert_nc( p->rc!=SQLITE_OK /* 1 */ || pIter->pLeaf==0 /* 2 */ || fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */ || (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */ @@ -207741,31 +212240,40 @@ static void fts5SegIterHashInit( int flags, /* Mask of FTS5INDEX_XXX flags */ Fts5SegIter *pIter /* Object to populate */ ){ - const u8 *pList = 0; int nList = 0; const u8 *z = 0; int n = 0; + Fts5Data *pLeaf = 0; assert( p->pHash ); assert( p->rc==SQLITE_OK ); if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){ + const u8 *pList = 0; + p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm); sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList); n = (z ? (int)strlen((const char*)z) : 0); + if( pList ){ + pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); + if( pLeaf ){ + pLeaf->p = (u8*)pList; + } + } }else{ - pIter->flags |= FTS5_SEGITER_ONETERM; - sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList); + p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data), + (const char*)pTerm, nTerm, (void**)&pLeaf, &nList + ); + if( pLeaf ){ + pLeaf->p = (u8*)&pLeaf[1]; + } z = pTerm; n = nTerm; + pIter->flags |= FTS5_SEGITER_ONETERM; } - if( pList ){ - Fts5Data *pLeaf; + if( pLeaf ){ sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z); - pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); - if( pLeaf==0 ) return; - pLeaf->p = (u8*)pList; pLeaf->nn = pLeaf->szLeaf = nList; pIter->pLeaf = pLeaf; pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid); @@ -207818,7 +212326,7 @@ static void fts5AssertComparisonResult( assert( pRes->iFirst==i1 ); }else{ int nMin = MIN(p1->term.n, p2->term.n); - int res = memcmp(p1->term.p, p2->term.p, nMin); + int res = fts5Memcmp(p1->term.p, p2->term.p, nMin); if( res==0 ) res = p1->term.n - p2->term.n; if( res==0 ){ @@ -207918,8 +212426,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){ }else{ int res = fts5BufferCompare(&p1->term, &p2->term); if( res==0 ){ - assert( i2>i1 ); - assert( i2!=0 ); + assert_nc( i2>i1 ); + assert_nc( i2!=0 ); pRes->bTermEq = 1; if( p1->iRowid==p2->iRowid ){ p1->bDel = p2->bDel; @@ -208041,7 +212549,6 @@ static void fts5MultiIterFree(Fts5Iter *pIter){ for(i=0; inSeg; i++){ fts5SegIterClear(&pIter->aSeg[i]); } - fts5StructureRelease(pIter->pStruct); fts5BufferFree(&pIter->poslist); sqlite3_free(pIter); } @@ -208389,7 +212896,8 @@ static void fts5SegiterPoslist( Fts5Colset *pColset, Fts5Buffer *pBuf ){ - if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){ + if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+FTS5_DATA_ZERO_PADDING) ){ + memset(&pBuf->p[pBuf->n+pSeg->nPos], 0, FTS5_DATA_ZERO_PADDING); if( pColset==0 ){ fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback); }else{ @@ -208687,9 +213195,7 @@ static void fts5MultiIterNew( if( pNew==0 ) return; pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC)); pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY)); - pNew->pStruct = pStruct; pNew->pColset = pColset; - fts5StructureRef(pStruct); if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){ fts5IterSetOutputCb(&p->rc, pNew); } @@ -208867,24 +213373,24 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){ for(iLvl=0; iLvlnLevel; iLvl++){ for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid; - if( iId<=FTS5_MAX_SEGMENT ){ - aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32); + if( iId<=FTS5_MAX_SEGMENT && iId>0 ){ + aUsed[(iId-1) / 32] |= (u32)1 << ((iId-1) % 32); } } } for(i=0; aUsed[i]==0xFFFFFFFF; i++); mask = aUsed[i]; - for(iSegid=0; mask & (1 << iSegid); iSegid++); + for(iSegid=0; mask & ((u32)1 << iSegid); iSegid++); iSegid += 1 + i*32; #ifdef SQLITE_DEBUG for(iLvl=0; iLvlnLevel; iLvl++){ for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ - assert( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ); + assert_nc( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ); } } - assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT ); + assert_nc( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT ); { sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p); @@ -208892,7 +213398,7 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){ u8 aBlob[2] = {0xff, 0xff}; sqlite3_bind_int(pIdxSelect, 1, iSegid); sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC); - assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW ); + assert_nc( sqlite3_step(pIdxSelect)!=SQLITE_ROW ); p->rc = sqlite3_reset(pIdxSelect); sqlite3_bind_null(pIdxSelect, 2); } @@ -208962,13 +213468,13 @@ static int fts5WriteDlidxGrow( int nLvl ){ if( p->rc==SQLITE_OK && nLvl>=pWriter->nDlidx ){ - Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc( + Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc64( pWriter->aDlidx, sizeof(Fts5DlidxWriter) * nLvl ); if( aDlidx==0 ){ p->rc = SQLITE_NOMEM; }else{ - int nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx); + size_t nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx); memset(&aDlidx[pWriter->nDlidx], 0, nByte); pWriter->aDlidx = aDlidx; pWriter->nDlidx = nLvl; @@ -209041,8 +213547,10 @@ static void fts5WriteBtreeTerm( int nTerm, const u8 *pTerm /* First term on new page */ ){ fts5WriteFlushBtree(p, pWriter); - fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm); - pWriter->iBtPage = pWriter->writer.pgno; + if( p->rc==SQLITE_OK ){ + fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm); + pWriter->iBtPage = pWriter->writer.pgno; + } } /* @@ -209193,6 +213701,7 @@ static void fts5WriteAppendTerm( int nPrefix; /* Bytes of prefix compression for term */ Fts5PageWriter *pPage = &pWriter->writer; Fts5Buffer *pPgidx = &pWriter->writer.pgidx; + int nMin = MIN(pPage->term.n, nTerm); assert( p->rc==SQLITE_OK ); assert( pPage->buf.n>=4 ); @@ -209202,6 +213711,7 @@ static void fts5WriteAppendTerm( if( (pPage->buf.n + pPgidx->n + nTerm + 2)>=p->pConfig->pgsz ){ if( pPage->buf.n>4 ){ fts5WriteFlushLeaf(p, pWriter); + if( p->rc!=SQLITE_OK ) return; } fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING); } @@ -209234,13 +213744,14 @@ static void fts5WriteAppendTerm( ** inefficient, but still correct. */ int n = nTerm; if( pPage->term.n ){ - n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm); + n = 1 + fts5PrefixCompress(nMin, pPage->term.p, pTerm); } fts5WriteBtreeTerm(p, pWriter, n, pTerm); + if( p->rc!=SQLITE_OK ) return; pPage = &pWriter->writer; } }else{ - nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm); + nPrefix = fts5PrefixCompress(nMin, pPage->term.p, pTerm); fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix); } @@ -209287,7 +213798,7 @@ static void fts5WriteAppendRowid( if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){ fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid); }else{ - assert( p->rc || iRowid>pWriter->iPrevRowid ); + assert_nc( p->rc || iRowid>pWriter->iPrevRowid ); fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid); } pWriter->iPrevRowid = iRowid; @@ -209409,7 +213920,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ int i; Fts5Buffer buf; memset(&buf, 0, sizeof(Fts5Buffer)); - for(i=0; inSeg; i++){ + for(i=0; inSeg && p->rc==SQLITE_OK; i++){ Fts5SegIter *pSeg = &pIter->aSeg[i]; if( pSeg->pSeg==0 ){ /* no-op */ @@ -209427,35 +213938,44 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ u8 aHdr[4] = {0x00, 0x00, 0x00, 0x00}; iLeafRowid = FTS5_SEGMENT_ROWID(iId, pSeg->iTermLeafPgno); - pData = fts5DataRead(p, iLeafRowid); + pData = fts5LeafRead(p, iLeafRowid); if( pData ){ - fts5BufferZero(&buf); - fts5BufferGrow(&p->rc, &buf, pData->nn); - fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr); - fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n); - fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p); - fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff, &pData->p[iOff]); - if( p->rc==SQLITE_OK ){ - /* Set the szLeaf field */ - fts5PutU16(&buf.p[2], (u16)buf.n); - } + if( iOff>pData->szLeaf ){ + /* This can occur if the pages that the segments occupy overlap - if + ** a single page has been assigned to more than one segment. In + ** this case a prior iteration of this loop may have corrupted the + ** segment currently being trimmed. */ + p->rc = FTS5_CORRUPT; + }else{ + fts5BufferZero(&buf); + fts5BufferGrow(&p->rc, &buf, pData->nn); + fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr); + fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n); + fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p); + fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]); + if( p->rc==SQLITE_OK ){ + /* Set the szLeaf field */ + fts5PutU16(&buf.p[2], (u16)buf.n); + } - /* Set up the new page-index array */ - fts5BufferAppendVarint(&p->rc, &buf, 4); - if( pSeg->iLeafPgno==pSeg->iTermLeafPgno - && pSeg->iEndofDoclistszLeaf - ){ - int nDiff = pData->szLeaf - pSeg->iEndofDoclist; - fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4); - fts5BufferAppendBlob(&p->rc, &buf, - pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff] - ); - } + /* Set up the new page-index array */ + fts5BufferAppendVarint(&p->rc, &buf, 4); + if( pSeg->iLeafPgno==pSeg->iTermLeafPgno + && pSeg->iEndofDoclistszLeaf + && pSeg->iPgidxOff<=pData->nn + ){ + int nDiff = pData->szLeaf - pSeg->iEndofDoclist; + fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4); + fts5BufferAppendBlob(&p->rc, &buf, + pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff] + ); + } + pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno; + fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid); + fts5DataWrite(p, iLeafRowid, buf.p, buf.n); + } fts5DataRelease(pData); - pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno; - fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid); - fts5DataWrite(p, iLeafRowid, buf.p, buf.n); } } } @@ -209547,7 +214067,7 @@ static void fts5IndexMergeLevel( const u8 *pTerm; pTerm = fts5MultiIterTerm(pIter, &nTerm); - if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){ + if( nTerm!=term.n || fts5Memcmp(pTerm, term.p, nTerm) ){ if( pnRem && writer.nLeafWritten>nRem ){ break; } @@ -209802,6 +214322,7 @@ static void fts5FlushOneHash(Fts5Index *p){ /* Write the term for this entry to disk. */ sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist); fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm); + if( p->rc!=SQLITE_OK ) break; assert( writer.bFirstRowidInPage==0 ); if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){ @@ -209824,6 +214345,7 @@ static void fts5FlushOneHash(Fts5Index *p){ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid); writer.bFirstRowidInPage = 0; fts5WriteDlidxAppend(p, &writer, iRowid); + if( p->rc!=SQLITE_OK ) break; }else{ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta); } @@ -209881,7 +214403,7 @@ static void fts5FlushOneHash(Fts5Index *p){ /* TODO2: Doclist terminator written here. */ /* pBuf->p[pBuf->n++] = '\0'; */ assert( pBuf->n<=pBuf->nSpace ); - sqlite3Fts5HashScanNext(pHash); + if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash); } sqlite3Fts5HashClear(pHash); fts5WriteFinish(p, &writer, &pgnoLast); @@ -209925,7 +214447,7 @@ static Fts5Structure *fts5IndexOptimizeStruct( Fts5Structure *pStruct ){ Fts5Structure *pNew = 0; - int nByte = sizeof(Fts5Structure); + sqlite3_int64 nByte = sizeof(Fts5Structure); int nSeg = pStruct->nSegment; int i; @@ -210055,11 +214577,13 @@ static void fts5AppendPoslist( Fts5Buffer *pBuf ){ int nData = pMulti->base.nData; + int nByte = nData + 9 + 9 + FTS5_DATA_ZERO_PADDING; assert( nData>0 ); - if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nData+9+9) ){ + if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nByte) ){ fts5BufferSafeAppendVarint(pBuf, iDelta); fts5BufferSafeAppendVarint(pBuf, nData*2); fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData); + memset(&pBuf->p[pBuf->n], 0, FTS5_DATA_ZERO_PADDING); } } @@ -210212,8 +214736,14 @@ static void fts5MergePrefixLists( ** first rowid in one input is a large negative number, and the first in ** the other a non-negative number, the delta for the non-negative ** number will be larger on disk than the literal integer value - ** was. */ - if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9) ) return; + ** was. + ** + ** Or, if the input position-lists are corrupt, then the output might + ** include up to 2 extra 10-byte positions created by interpreting -1 + ** (the value PoslistNext64() uses for EOF) as a position and appending + ** it to the output. This can happen at most once for each input + ** position-list, hence two 10 byte paddings. */ + if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9+10+10) ) return; fts5DoclistIterInit(p1, &i1); fts5DoclistIterInit(p2, &i2); @@ -210224,6 +214754,7 @@ static void fts5MergePrefixLists( fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize); fts5DoclistIterNext(&i1); if( i1.aPoslist==0 ) break; + assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) ); } else if( i2.iRowid!=i1.iRowid ){ /* Copy entry from i2 */ @@ -210231,6 +214762,7 @@ static void fts5MergePrefixLists( fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize); fts5DoclistIterNext(&i2); if( i2.aPoslist==0 ) break; + assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) ); } else{ /* Merge the two position lists. */ @@ -210240,6 +214772,8 @@ static void fts5MergePrefixLists( int iOff2 = 0; u8 *a1 = &i1.aPoslist[i1.nSize]; u8 *a2 = &i2.aPoslist[i2.nSize]; + int nCopy; + u8 *aCopy; i64 iPrev = 0; Fts5PoslistWriter writer; @@ -210252,7 +214786,7 @@ static void fts5MergePrefixLists( sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); - assert( iPos1>=0 && iPos2>=0 ); + assert_nc( iPos1>=0 && iPos2>=0 ); if( iPos1=0 && iPos2>=0 ){ while( 1 ){ if( iPos1=0 && iPos2!=iPrev ); + assert_nc( iPos2>=0 && iPos2!=iPrev ); sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2); - fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2); + aCopy = &a2[iOff2]; + nCopy = i2.nPoslist - iOff2; + } + if( nCopy>0 ){ + fts5BufferSafeAppendBlob(&tmp, aCopy, nCopy); } /* WRITEPOSLISTSIZE */ @@ -210295,7 +214833,9 @@ static void fts5MergePrefixLists( fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); fts5DoclistIterNext(&i1); fts5DoclistIterNext(&i2); + assert_nc( out.n<=(p1->n+p2->n+9) ); if( i1.aPoslist==0 || i2.aPoslist==0 ) break; + assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) ); } } @@ -210307,7 +214847,7 @@ static void fts5MergePrefixLists( fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist); } - assert( out.n<=(p1->n+p2->n+9) ); + assert_nc( out.n<=(p1->n+p2->n+9) ); fts5BufferSet(&p->rc, p1, out.n, out.p); fts5BufferFree(&tmp); @@ -210396,7 +214936,7 @@ static void fts5SetupPrefixIter( } fts5MultiIterFree(p1); - pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n); + pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING); if( pData ){ pData->p = (u8*)&pData[1]; pData->nn = pData->szLeaf = doclist.n; @@ -210696,7 +215236,7 @@ static int sqlite3Fts5IndexQuery( fts5CloseReader(p); } - *ppIter = &pRet->base; + *ppIter = (Fts5IndexIter*)pRet; sqlite3Fts5BufferFree(&buf); } return fts5IndexReturn(p); @@ -211158,11 +215698,11 @@ static void fts5IndexIntegrityCheckSegment( iOff = fts5LeafFirstTermOff(pLeaf); iRowidOff = fts5LeafFirstRowidOff(pLeaf); - if( iRowidOff>=iOff ){ + if( iRowidOff>=iOff || iOff>=pLeaf->szLeaf ){ p->rc = FTS5_CORRUPT; }else{ iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm); - res = memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); + res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); if( res==0 ) res = nTerm - nIdxTerm; if( res<0 ) p->rc = FTS5_CORRUPT; } @@ -211557,7 +216097,7 @@ static void fts5DecodeFunction( u8 *a = 0; Fts5Buffer s; /* Build up text to return here */ int rc = SQLITE_OK; /* Return code */ - int nSpace = 0; + sqlite3_int64 nSpace = 0; int eDetailNone = (sqlite3_user_data(pCtx)!=0); assert( nArg==2 ); @@ -211573,8 +216113,7 @@ static void fts5DecodeFunction( nSpace = n + FTS5_DATA_ZERO_PADDING; a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace); if( a==0 ) goto decode_out; - memcpy(a, aBlob, n); - + if( n>0 ) memcpy(a, aBlob, n); fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno); @@ -211669,6 +216208,9 @@ static void fts5DecodeFunction( iPgidxOff = szLeaf = fts5GetU16(&a[2]); if( iPgidxOffn ){ + rc = FTS5_CORRUPT; + goto decode_out; } } @@ -211680,14 +216222,22 @@ static void fts5DecodeFunction( }else{ iOff = szLeaf; } + if( iOff>n ){ + rc = FTS5_CORRUPT; + goto decode_out; + } fts5DecodePoslist(&rc, &s, &a[4], iOff-4); /* Decode any more doclist data that appears on the page before the ** first term. */ nDoclist = (iTermOff ? iTermOff : szLeaf) - iOff; + if( nDoclist+iOff>n ){ + rc = FTS5_CORRUPT; + goto decode_out; + } fts5DecodeDoclist(&rc, &s, &a[iOff], nDoclist); - while( iPgidxOffszLeaf ){ + rc = FTS5_CORRUPT; + break; + } if( bFirst==0 ){ iOff += fts5GetVarint32(&a[iOff], nByte); + if( nByte>term.n ){ + rc = FTS5_CORRUPT; + break; + } term.n = nByte; } iOff += fts5GetVarint32(&a[iOff], nByte); + if( iOff+nByte>n ){ + rc = FTS5_CORRUPT; + break; + } fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]); iOff += nByte; @@ -211831,8 +216393,8 @@ SQLITE_API int sqlite3_fts5_may_be_corrupt = 1; typedef struct Fts5Auxdata Fts5Auxdata; typedef struct Fts5Auxiliary Fts5Auxiliary; typedef struct Fts5Cursor Fts5Cursor; +typedef struct Fts5FullTable Fts5FullTable; typedef struct Fts5Sorter Fts5Sorter; -typedef struct Fts5Table Fts5Table; typedef struct Fts5TokenizerModule Fts5TokenizerModule; /* @@ -211913,13 +216475,8 @@ struct Fts5TokenizerModule { Fts5TokenizerModule *pNext; /* Next registered tokenizer module */ }; -/* -** Virtual-table object. -*/ -struct Fts5Table { - sqlite3_vtab base; /* Base class used by SQLite core */ - Fts5Config *pConfig; /* Virtual table configuration */ - Fts5Index *pIndex; /* Full-text index */ +struct Fts5FullTable { + Fts5Table p; /* Public class members from fts5Int.h */ Fts5Storage *pStorage; /* Document store */ Fts5Global *pGlobal; /* Global (connection wide) data */ Fts5Cursor *pSortCsr; /* Sort data from this cursor */ @@ -212057,7 +216614,7 @@ struct Fts5Auxdata { #define FTS5_SAVEPOINT 5 #define FTS5_RELEASE 6 #define FTS5_ROLLBACKTO 7 -static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){ +static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){ switch( op ){ case FTS5_BEGIN: assert( p->ts.eState==0 ); @@ -212096,7 +216653,7 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){ case FTS5_ROLLBACKTO: assert( p->ts.eState==1 ); - assert( iSavepoint>=0 ); + assert( iSavepoint>=-1 ); assert( iSavepoint<=p->ts.iSavepoint ); p->ts.iSavepoint = iSavepoint; break; @@ -212109,18 +216666,18 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){ /* ** Return true if pTab is a contentless table. */ -static int fts5IsContentless(Fts5Table *pTab){ - return pTab->pConfig->eContent==FTS5_CONTENT_NONE; +static int fts5IsContentless(Fts5FullTable *pTab){ + return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE; } /* ** Delete a virtual table handle allocated by fts5InitVtab(). */ -static void fts5FreeVtab(Fts5Table *pTab){ +static void fts5FreeVtab(Fts5FullTable *pTab){ if( pTab ){ - sqlite3Fts5IndexClose(pTab->pIndex); + sqlite3Fts5IndexClose(pTab->p.pIndex); sqlite3Fts5StorageClose(pTab->pStorage); - sqlite3Fts5ConfigFree(pTab->pConfig); + sqlite3Fts5ConfigFree(pTab->p.pConfig); sqlite3_free(pTab); } } @@ -212129,7 +216686,7 @@ static void fts5FreeVtab(Fts5Table *pTab){ ** The xDisconnect() virtual table method. */ static int fts5DisconnectMethod(sqlite3_vtab *pVtab){ - fts5FreeVtab((Fts5Table*)pVtab); + fts5FreeVtab((Fts5FullTable*)pVtab); return SQLITE_OK; } @@ -212140,7 +216697,7 @@ static int fts5DestroyMethod(sqlite3_vtab *pVtab){ Fts5Table *pTab = (Fts5Table*)pVtab; int rc = sqlite3Fts5DropAll(pTab->pConfig); if( rc==SQLITE_OK ){ - fts5FreeVtab((Fts5Table*)pVtab); + fts5FreeVtab((Fts5FullTable*)pVtab); } return rc; } @@ -212169,28 +216726,28 @@ static int fts5InitVtab( const char **azConfig = (const char**)argv; int rc = SQLITE_OK; /* Return code */ Fts5Config *pConfig = 0; /* Results of parsing argc/argv */ - Fts5Table *pTab = 0; /* New virtual table object */ + Fts5FullTable *pTab = 0; /* New virtual table object */ /* Allocate the new vtab object and parse the configuration */ - pTab = (Fts5Table*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Table)); + pTab = (Fts5FullTable*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5FullTable)); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr); assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 ); } if( rc==SQLITE_OK ){ - pTab->pConfig = pConfig; + pTab->p.pConfig = pConfig; pTab->pGlobal = pGlobal; } /* Open the index sub-system */ if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->pIndex, pzErr); + rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->p.pIndex, pzErr); } /* Open the storage sub-system */ if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageOpen( - pConfig, pTab->pIndex, bCreate, &pTab->pStorage, pzErr + pConfig, pTab->p.pIndex, bCreate, &pTab->pStorage, pzErr ); } @@ -212203,8 +216760,8 @@ static int fts5InitVtab( if( rc==SQLITE_OK ){ assert( pConfig->pzErrmsg==0 ); pConfig->pzErrmsg = pzErr; - rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex); - sqlite3Fts5IndexRollback(pTab->pIndex); + rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); + sqlite3Fts5IndexRollback(pTab->p.pIndex); pConfig->pzErrmsg = 0; } @@ -212417,7 +216974,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ return SQLITE_OK; } -static int fts5NewTransaction(Fts5Table *pTab){ +static int fts5NewTransaction(Fts5FullTable *pTab){ Fts5Cursor *pCsr; for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK; @@ -212429,19 +216986,19 @@ static int fts5NewTransaction(Fts5Table *pTab){ ** Implementation of xOpen method. */ static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ - Fts5Table *pTab = (Fts5Table*)pVTab; - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)pVTab; + Fts5Config *pConfig = pTab->p.pConfig; Fts5Cursor *pCsr = 0; /* New cursor object */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ int rc; /* Return code */ rc = fts5NewTransaction(pTab); if( rc==SQLITE_OK ){ nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int); - pCsr = (Fts5Cursor*)sqlite3_malloc(nByte); + pCsr = (Fts5Cursor*)sqlite3_malloc64(nByte); if( pCsr ){ Fts5Global *pGlobal = pTab->pGlobal; - memset(pCsr, 0, nByte); + memset(pCsr, 0, (size_t)nByte); pCsr->aColumnSize = (int*)&pCsr[1]; pCsr->pNext = pGlobal->pCsr; pGlobal->pCsr = pCsr; @@ -212476,7 +217033,7 @@ static void fts5CsrNewrow(Fts5Cursor *pCsr){ } static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); Fts5Auxdata *pData; Fts5Auxdata *pNext; @@ -212520,7 +217077,7 @@ static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ */ static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){ if( pCursor ){ - Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab); Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; Fts5Cursor **pp; @@ -212577,7 +217134,7 @@ static int fts5SorterNext(Fts5Cursor *pCsr){ ** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors ** open on table pTab. */ -static void fts5TripCursors(Fts5Table *pTab){ +static void fts5TripCursors(Fts5FullTable *pTab){ Fts5Cursor *pCsr; for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ if( pCsr->ePlan==FTS5_PLAN_MATCH @@ -212604,11 +217161,11 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ int rc = SQLITE_OK; assert( *pbSkip==0 ); if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){ - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); int bDesc = pCsr->bDesc; i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr); - rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc); + rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->p.pIndex, iRowid, bDesc); if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){ *pbSkip = 1; } @@ -212705,20 +217262,24 @@ static int fts5PrepareStatement( return rc; } -static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ - Fts5Config *pConfig = pTab->pConfig; +static int fts5CursorFirstSorted( + Fts5FullTable *pTab, + Fts5Cursor *pCsr, + int bDesc +){ + Fts5Config *pConfig = pTab->p.pConfig; Fts5Sorter *pSorter; int nPhrase; - int nByte; + sqlite3_int64 nByte; int rc; const char *zRank = pCsr->zRank; const char *zRankArgs = pCsr->zRankArgs; nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); - pSorter = (Fts5Sorter*)sqlite3_malloc(nByte); + pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte); if( pSorter==0 ) return SQLITE_NOMEM; - memset(pSorter, 0, nByte); + memset(pSorter, 0, (size_t)nByte); pSorter->nIdx = nPhrase; /* TODO: It would be better to have some system for reusing statement @@ -212753,10 +217314,10 @@ static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ return rc; } -static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ +static int fts5CursorFirst(Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc){ int rc; Fts5Expr *pExpr = pCsr->pExpr; - rc = sqlite3Fts5ExprFirst(pExpr, pTab->pIndex, pCsr->iFirstRowid, bDesc); + rc = sqlite3Fts5ExprFirst(pExpr, pTab->p.pIndex, pCsr->iFirstRowid, bDesc); if( sqlite3Fts5ExprEof(pExpr) ){ CsrFlagSet(pCsr, FTS5CSR_EOF); } @@ -212771,7 +217332,7 @@ static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ ** parameters. */ static int fts5SpecialMatch( - Fts5Table *pTab, + Fts5FullTable *pTab, Fts5Cursor *pCsr, const char *zQuery ){ @@ -212782,18 +217343,18 @@ static int fts5SpecialMatch( while( z[0]==' ' ) z++; for(n=0; z[n] && z[n]!=' '; n++); - assert( pTab->base.zErrMsg==0 ); + assert( pTab->p.base.zErrMsg==0 ); pCsr->ePlan = FTS5_PLAN_SPECIAL; if( 0==sqlite3_strnicmp("reads", z, n) ){ - pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->pIndex); + pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->p.pIndex); } else if( 0==sqlite3_strnicmp("id", z, n) ){ pCsr->iSpecial = pCsr->iCsrId; } else{ /* An unrecognized directive. Return an error message. */ - pTab->base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z); + pTab->p.base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z); rc = SQLITE_ERROR; } @@ -212805,7 +217366,7 @@ static int fts5SpecialMatch( ** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary ** structure. Otherwise, if no such function exists, return NULL. */ -static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){ +static Fts5Auxiliary *fts5FindAuxiliary(Fts5FullTable *pTab, const char *zName){ Fts5Auxiliary *pAux; for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){ @@ -212818,8 +217379,8 @@ static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){ static int fts5FindRankFunction(Fts5Cursor *pCsr){ - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); + Fts5Config *pConfig = pTab->p.pConfig; int rc = SQLITE_OK; Fts5Auxiliary *pAux = 0; const char *zRank = pCsr->zRank; @@ -212835,7 +217396,7 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){ assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 ); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pStmt) ){ - int nByte; + sqlite3_int64 nByte; pCsr->nRankArg = sqlite3_column_count(pStmt); nByte = sizeof(sqlite3_value*)*pCsr->nRankArg; pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte); @@ -212857,8 +217418,8 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){ if( rc==SQLITE_OK ){ pAux = fts5FindAuxiliary(pTab, zRank); if( pAux==0 ){ - assert( pTab->base.zErrMsg==0 ); - pTab->base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank); + assert( pTab->p.base.zErrMsg==0 ); + pTab->p.base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank); rc = SQLITE_ERROR; } } @@ -212933,8 +217494,8 @@ static int fts5FilterMethod( int nVal, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ - Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab); + Fts5Config *pConfig = pTab->p.pConfig; Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; int rc = SQLITE_OK; /* Error code */ int iVal = 0; /* Counter for apVal[] */ @@ -212963,8 +217524,8 @@ static int fts5FilterMethod( assert( pCsr->zRank==0 ); assert( pCsr->zRankArgs==0 ); - assert( pzErrmsg==0 || pzErrmsg==&pTab->base.zErrMsg ); - pConfig->pzErrmsg = &pTab->base.zErrMsg; + assert( pzErrmsg==0 || pzErrmsg==&pTab->p.base.zErrMsg ); + pConfig->pzErrmsg = &pTab->p.base.zErrMsg; /* Decode the arguments passed through to this function. ** @@ -213030,7 +217591,7 @@ static int fts5FilterMethod( ** but a request for an internal parameter. */ rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]); }else{ - char **pzErr = &pTab->base.zErrMsg; + char **pzErr = &pTab->p.base.zErrMsg; rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr); if( rc==SQLITE_OK ){ if( bOrderByRank ){ @@ -213053,7 +217614,7 @@ static int fts5FilterMethod( ** by rowid (ePlan==FTS5_PLAN_ROWID). */ pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN); rc = sqlite3Fts5StorageStmt( - pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->base.zErrMsg + pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->p.base.zErrMsg ); if( rc==SQLITE_OK ){ if( pCsr->ePlan==FTS5_PLAN_ROWID ){ @@ -213136,12 +217697,12 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ /* If the cursor does not yet have a statement handle, obtain one now. */ if( pCsr->pStmt==0 ){ - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); int eStmt = fts5StmtType(pCsr); rc = sqlite3Fts5StorageStmt( - pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->base.zErrMsg:0) + pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->p.base.zErrMsg:0) ); - assert( rc!=SQLITE_OK || pTab->base.zErrMsg==0 ); + assert( rc!=SQLITE_OK || pTab->p.base.zErrMsg==0 ); assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ); } @@ -213163,11 +217724,11 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ return rc; } -static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){ +static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){ va_list ap; /* ... printf arguments */ va_start(ap, zFormat); - assert( p->base.zErrMsg==0 ); - p->base.zErrMsg = sqlite3_vmprintf(zFormat, ap); + assert( p->p.base.zErrMsg==0 ); + p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap); va_end(ap); } @@ -213187,11 +217748,11 @@ static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){ ** more commands are added to this function. */ static int fts5SpecialInsert( - Fts5Table *pTab, /* Fts5 table object */ + Fts5FullTable *pTab, /* Fts5 table object */ const char *zCmd, /* Text inserted into table-name column */ sqlite3_value *pVal /* Value inserted into rank column */ ){ - Fts5Config *pConfig = pTab->pConfig; + Fts5Config *pConfig = pTab->p.pConfig; int rc = SQLITE_OK; int bError = 0; @@ -213226,9 +217787,9 @@ static int fts5SpecialInsert( pConfig->bPrefixIndex = sqlite3_value_int(pVal); #endif }else{ - rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex); + rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError); + rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError); } if( rc==SQLITE_OK ){ if( bError ){ @@ -213242,7 +217803,7 @@ static int fts5SpecialInsert( } static int fts5SpecialDelete( - Fts5Table *pTab, + Fts5FullTable *pTab, sqlite3_value **apVal ){ int rc = SQLITE_OK; @@ -213256,7 +217817,7 @@ static int fts5SpecialDelete( static void fts5StorageInsert( int *pRc, - Fts5Table *pTab, + Fts5FullTable *pTab, sqlite3_value **apVal, i64 *piRowid ){ @@ -213290,8 +217851,8 @@ static int fts5UpdateMethod( sqlite3_value **apVal, /* Array of arguments */ sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ - Fts5Table *pTab = (Fts5Table*)pVtab; - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; + Fts5Config *pConfig = pTab->p.pConfig; int eType0; /* value_type() of apVal[0] */ int rc = SQLITE_OK; /* Return code */ @@ -213300,12 +217861,11 @@ static int fts5UpdateMethod( assert( pVtab->zErrMsg==0 ); assert( nArg==1 || nArg==(2+pConfig->nCol+2) ); - assert( nArg==1 - || sqlite3_value_type(apVal[1])==SQLITE_INTEGER - || sqlite3_value_type(apVal[1])==SQLITE_NULL + assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER + || sqlite3_value_type(apVal[0])==SQLITE_NULL ); - assert( pTab->pConfig->pzErrmsg==0 ); - pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; + assert( pTab->p.pConfig->pzErrmsg==0 ); + pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg; /* Put any active cursors into REQUIRE_SEEK state. */ fts5TripCursors(pTab); @@ -213346,7 +217906,7 @@ static int fts5UpdateMethod( /* Filter out attempts to run UPDATE or DELETE on contentless tables. ** This is not suported. */ if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){ - pTab->base.zErrMsg = sqlite3_mprintf( + pTab->p.base.zErrMsg = sqlite3_mprintf( "cannot %s contentless fts5 table: %s", (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName ); @@ -213359,46 +217919,52 @@ static int fts5UpdateMethod( rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); } - /* INSERT */ - else if( eType0!=SQLITE_INTEGER ){ - /* If this is a REPLACE, first remove the current entry (if any) */ - if( eConflict==SQLITE_REPLACE - && sqlite3_value_type(apVal[1])==SQLITE_INTEGER - ){ - i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + /* INSERT or UPDATE */ + else{ + int eType1 = sqlite3_value_numeric_type(apVal[1]); + + if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){ + rc = SQLITE_MISMATCH; } - fts5StorageInsert(&rc, pTab, apVal, pRowid); - } - /* UPDATE */ - else{ - i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ - i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ - if( iOld!=iNew ){ - if( eConflict==SQLITE_REPLACE ){ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); - } - fts5StorageInsert(&rc, pTab, apVal, pRowid); - }else{ - rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); - if( rc==SQLITE_OK ){ + else if( eType0!=SQLITE_INTEGER ){ + /* If this is a REPLACE, first remove the current entry (if any) */ + if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){ + i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + } + fts5StorageInsert(&rc, pTab, apVal, pRowid); + } + + /* UPDATE */ + else{ + i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ + i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ + if( eType1==SQLITE_INTEGER && iOld!=iNew ){ + if( eConflict==SQLITE_REPLACE ){ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + } + fts5StorageInsert(&rc, pTab, apVal, pRowid); + }else{ + rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid); + } } - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid); - } + }else{ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + fts5StorageInsert(&rc, pTab, apVal, pRowid); } - }else{ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); - fts5StorageInsert(&rc, pTab, apVal, pRowid); } } } - pTab->pConfig->pzErrmsg = 0; + pTab->p.pConfig->pzErrmsg = 0; return rc; } @@ -213407,12 +217973,12 @@ static int fts5UpdateMethod( */ static int fts5SyncMethod(sqlite3_vtab *pVtab){ int rc; - Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; fts5CheckTransactionState(pTab, FTS5_SYNC, 0); - pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; + pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg; fts5TripCursors(pTab); rc = sqlite3Fts5StorageSync(pTab->pStorage); - pTab->pConfig->pzErrmsg = 0; + pTab->p.pConfig->pzErrmsg = 0; return rc; } @@ -213420,8 +217986,8 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){ ** Implementation of xBegin() method. */ static int fts5BeginMethod(sqlite3_vtab *pVtab){ - fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0); - fts5NewTransaction((Fts5Table*)pVtab); + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0); + fts5NewTransaction((Fts5FullTable*)pVtab); return SQLITE_OK; } @@ -213432,7 +217998,7 @@ static int fts5BeginMethod(sqlite3_vtab *pVtab){ */ static int fts5CommitMethod(sqlite3_vtab *pVtab){ UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */ - fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0); + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_COMMIT, 0); return SQLITE_OK; } @@ -213442,7 +218008,7 @@ static int fts5CommitMethod(sqlite3_vtab *pVtab){ */ static int fts5RollbackMethod(sqlite3_vtab *pVtab){ int rc; - Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0); rc = sqlite3Fts5StorageRollback(pTab->pStorage); return rc; @@ -213466,13 +218032,13 @@ static int fts5ApiColumnTotalSize( sqlite3_int64 *pnToken ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken); } static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow); } @@ -213507,7 +218073,9 @@ static int fts5ApiColumnText( ){ int rc = SQLITE_OK; Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ + if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) + || pCsr->ePlan==FTS5_PLAN_SPECIAL + ){ *pz = 0; *pn = 0; }else{ @@ -213576,10 +218144,11 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ int rc = SQLITE_OK; Fts5PoslistReader *aIter; /* One iterator for each phrase */ int nIter; /* Number of iterators/phrases */ + int nCol = ((Fts5Table*)pCsr->base.pVtab)->pConfig->nCol; nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); if( pCsr->aInstIter==0 ){ - int nByte = sizeof(Fts5PoslistReader) * nIter; + sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nIter; pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte); } aIter = pCsr->aInstIter; @@ -213614,7 +218183,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ nInst++; if( nInst>=pCsr->nInstAlloc ){ pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; - aInst = (int*)sqlite3_realloc( + aInst = (int*)sqlite3_realloc64( pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3 ); if( aInst ){ @@ -213629,6 +218198,10 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ aInst[0] = iBest; aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); + if( aInst[1]<0 || aInst[1]>=nCol ){ + rc = FTS5_CORRUPT; + break; + } sqlite3Fts5PoslistReaderNext(&aIter[iBest]); } } @@ -213701,8 +218274,8 @@ static int fts5ColumnSizeCb( static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); + Fts5Config *pConfig = pTab->p.pConfig; int rc = SQLITE_OK; if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){ @@ -213958,7 +218531,7 @@ static int fts5ApiQueryPhrase( int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*) ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); int rc; Fts5Cursor *pNew = 0; @@ -214035,25 +218608,19 @@ static void fts5ApiCallback( /* -** Given cursor id iId, return a pointer to the corresponding Fts5Index +** Given cursor id iId, return a pointer to the corresponding Fts5Table ** object. Or NULL If the cursor id does not exist. -** -** If successful, set *ppConfig to point to the associated config object -** before returning. */ -static Fts5Index *sqlite3Fts5IndexFromCsrid( +static Fts5Table *sqlite3Fts5TableFromCsrid( Fts5Global *pGlobal, /* FTS5 global context for db handle */ - i64 iCsrId, /* Id of cursor to find */ - Fts5Config **ppConfig /* OUT: Configuration object */ + i64 iCsrId /* Id of cursor to find */ ){ Fts5Cursor *pCsr; - Fts5Table *pTab; - pCsr = fts5CursorFromCsrid(pGlobal, iCsrId); - pTab = (Fts5Table*)pCsr->base.pVtab; - *ppConfig = pTab->pConfig; - - return pTab->pIndex; + if( pCsr ){ + return (Fts5Table*)pCsr->base.pVtab; + } + return 0; } /* @@ -214133,8 +218700,8 @@ static int fts5ColumnMethod( sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ int iCol /* Index of column to read value from */ ){ - Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab); + Fts5Config *pConfig = pTab->p.pConfig; Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; int rc = SQLITE_OK; @@ -214186,7 +218753,7 @@ static int fts5FindFunctionMethod( void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ void **ppArg /* OUT: User data for *pxFunc */ ){ - Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; Fts5Auxiliary *pAux; UNUSED_PARAM(nUnused); @@ -214208,21 +218775,24 @@ static int fts5RenameMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ const char *zName /* New name of table */ ){ - Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; return sqlite3Fts5StorageRename(pTab->pStorage, zName); } +static int sqlite3Fts5FlushToDisk(Fts5Table *pTab){ + fts5TripCursors((Fts5FullTable*)pTab); + return sqlite3Fts5StorageSync(((Fts5FullTable*)pTab)->pStorage); +} + /* ** The xSavepoint() method. ** ** Flush the contents of the pending-terms table to disk. */ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts5Table *pTab = (Fts5Table*)pVtab; UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ - fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); - fts5TripCursors(pTab); - return sqlite3Fts5StorageSync(pTab->pStorage); + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint); + return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); } /* @@ -214231,11 +218801,9 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ ** This is a no-op. */ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts5Table *pTab = (Fts5Table*)pVtab; UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ - fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint); - fts5TripCursors(pTab); - return sqlite3Fts5StorageSync(pTab->pStorage); + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint); + return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); } /* @@ -214244,7 +218812,7 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ ** Discard the contents of the pending terms table. */ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); fts5TripCursors(pTab); @@ -214265,14 +218833,14 @@ static int fts5CreateAux( int rc = sqlite3_overload_function(pGlobal->db, zName, -1); if( rc==SQLITE_OK ){ Fts5Auxiliary *pAux; - int nName; /* Size of zName in bytes, including \0 */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nName; /* Size of zName in bytes, including \0 */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ - nName = (int)strlen(zName) + 1; + nName = strlen(zName) + 1; nByte = sizeof(Fts5Auxiliary) + nName; - pAux = (Fts5Auxiliary*)sqlite3_malloc(nByte); + pAux = (Fts5Auxiliary*)sqlite3_malloc64(nByte); if( pAux ){ - memset(pAux, 0, nByte); + memset(pAux, 0, (size_t)nByte); pAux->zFunc = (char*)&pAux[1]; memcpy(pAux->zFunc, zName, nName); pAux->pGlobal = pGlobal; @@ -214302,15 +218870,15 @@ static int fts5CreateTokenizer( ){ Fts5Global *pGlobal = (Fts5Global*)pApi; Fts5TokenizerModule *pNew; - int nName; /* Size of zName and its \0 terminator */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nName; /* Size of zName and its \0 terminator */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ int rc = SQLITE_OK; - nName = (int)strlen(zName) + 1; + nName = strlen(zName) + 1; nByte = sizeof(Fts5TokenizerModule) + nName; - pNew = (Fts5TokenizerModule*)sqlite3_malloc(nByte); + pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte); if( pNew ){ - memset(pNew, 0, nByte); + memset(pNew, 0, (size_t)nByte); pNew->zName = (char*)&pNew[1]; memcpy(pNew->zName, zName, nName); pNew->pUserData = pUserData; @@ -214445,12 +219013,27 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2018-09-25 19:08:10 fb90e7189ae6d62e77ba3a308ca5d683f90bbe633cf681865365b8e92792d1c7", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88bfa6", -1, SQLITE_TRANSIENT); +} + +/* +** Return true if zName is the extension on one of the shadow tables used +** by this module. +*/ +static int fts5ShadowName(const char *zName){ + static const char *azName[] = { + "config", "content", "data", "docsize", "idx" + }; + unsigned int i; + for(i=0; idb, zSql, -1, - SQLITE_PREPARE_PERSISTENT, &p->aStmt[eStmt], 0); + int f = SQLITE_PREPARE_PERSISTENT; + if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB; + rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0); sqlite3_free(zSql); if( rc!=SQLITE_OK && pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); @@ -214844,14 +219429,14 @@ static int sqlite3Fts5StorageOpen( ){ int rc = SQLITE_OK; Fts5Storage *p; /* New object */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ nByte = sizeof(Fts5Storage) /* Fts5Storage object */ + pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */ - *pp = p = (Fts5Storage*)sqlite3_malloc(nByte); + *pp = p = (Fts5Storage*)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; - memset(p, 0, nByte); + memset(p, 0, (size_t)nByte); p->aTotalSize = (i64*)&p[1]; p->pConfig = pConfig; p->pIndex = pIndex; @@ -214859,7 +219444,7 @@ static int sqlite3Fts5StorageOpen( if( bCreate ){ if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ int nDefn = 32 + pConfig->nCol*10; - char *zDefn = sqlite3_malloc(32 + pConfig->nCol * 10); + char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10); if( zDefn==0 ){ rc = SQLITE_NOMEM; }else{ @@ -215150,7 +219735,7 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){ Fts5Config *pConfig = p->pConfig; sqlite3_stmt *pScan = 0; Fts5InsertCtx ctx; - int rc; + int rc, rc2; memset(&ctx, 0, sizeof(Fts5InsertCtx)); ctx.pStorage = p; @@ -215189,6 +219774,8 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){ } } sqlite3_free(buf.p); + rc2 = sqlite3_reset(pScan); + if( rc==SQLITE_OK ) rc = rc2; /* Write the averages record */ if( rc==SQLITE_OK ){ @@ -215438,7 +220025,7 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){ memset(&ctx, 0, sizeof(Fts5IntegrityCtx)); ctx.pConfig = p->pConfig; - aTotalSize = (i64*)sqlite3_malloc(pConfig->nCol * (sizeof(int)+sizeof(i64))); + aTotalSize = (i64*)sqlite3_malloc64(pConfig->nCol*(sizeof(int)+sizeof(i64))); if( !aTotalSize ) return SQLITE_NOMEM; aColSize = (int*)&aTotalSize[pConfig->nCol]; memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol); @@ -215638,7 +220225,13 @@ static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){ static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){ int rc = fts5StorageLoadTotals(p, 0); if( rc==SQLITE_OK ){ + /* nTotalRow being zero does not necessarily indicate a corrupt + ** database - it might be that the FTS5 table really does contain zero + ** rows. However this function is only called from the xRowCount() API, + ** and there is no way for that API to be invoked if the table contains + ** no rows. Hence the FTS5_CORRUPT return. */ *pnRow = p->nTotalRow; + if( p->nTotalRow<=0 ) rc = FTS5_CORRUPT; } return rc; } @@ -215848,7 +220441,7 @@ static int fts5AsciiTokenize( nByte = ie-is; if( nByte>nFold ){ if( pFold!=aFold ) sqlite3_free(pFold); - pFold = sqlite3_malloc(nByte*2); + pFold = sqlite3_malloc64((sqlite3_int64)nByte*2); if( pFold==0 ){ rc = SQLITE_NOMEM; break; @@ -215930,13 +220523,18 @@ struct Unicode61Tokenizer { unsigned char aTokenChar[128]; /* ASCII range token characters */ char *aFold; /* Buffer to fold text into */ int nFold; /* Size of aFold[] in bytes */ - int bRemoveDiacritic; /* True if remove_diacritics=1 is set */ + int eRemoveDiacritic; /* True if remove_diacritics=1 is set */ int nException; int *aiException; unsigned char aCategory[32]; /* True for token char categories */ }; +/* Values for eRemoveDiacritic (must match internals of fts5_unicode2.c) */ +#define FTS5_REMOVE_DIACRITICS_NONE 0 +#define FTS5_REMOVE_DIACRITICS_SIMPLE 1 +#define FTS5_REMOVE_DIACRITICS_COMPLEX 2 + static int fts5UnicodeAddExceptions( Unicode61Tokenizer *p, /* Tokenizer object */ const char *z, /* Characters to treat as exceptions */ @@ -215947,13 +220545,14 @@ static int fts5UnicodeAddExceptions( int *aNew; if( n>0 ){ - aNew = (int*)sqlite3_realloc(p->aiException, (n+p->nException)*sizeof(int)); + aNew = (int*)sqlite3_realloc64(p->aiException, + (n+p->nException)*sizeof(int)); if( aNew ){ int nNew = p->nException; const unsigned char *zCsr = (const unsigned char*)z; const unsigned char *zTerm = (const unsigned char*)&z[n]; while( zCsriCode ) break; + if( (u32)aNew[i]>iCode ) break; } memmove(&aNew[i+1], &aNew[i], (nNew-i)*sizeof(int)); aNew[i] = iCode; @@ -216057,9 +220656,9 @@ static int fts5UnicodeCreate( int i; memset(p, 0, sizeof(Unicode61Tokenizer)); - p->bRemoveDiacritic = 1; + p->eRemoveDiacritic = FTS5_REMOVE_DIACRITICS_SIMPLE; p->nFold = 64; - p->aFold = sqlite3_malloc(p->nFold * sizeof(char)); + p->aFold = sqlite3_malloc64(p->nFold * sizeof(char)); if( p->aFold==0 ){ rc = SQLITE_NOMEM; } @@ -216078,10 +220677,15 @@ static int fts5UnicodeCreate( for(i=0; rc==SQLITE_OK && ieRemoveDiacritic = (zArg[0] - '0'); + assert( p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_NONE + || p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_SIMPLE + || p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_COMPLEX + ); } - p->bRemoveDiacritic = (zArg[0]=='1'); }else if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){ rc = fts5UnicodeAddExceptions(p, zArg, 1); @@ -216115,7 +220719,7 @@ static int fts5UnicodeCreate( */ static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){ return ( - p->aCategory[sqlite3Fts5UnicodeCategory(iCode)] + p->aCategory[sqlite3Fts5UnicodeCategory((u32)iCode)] ^ fts5UnicodeIsException(p, iCode) ); } @@ -216144,7 +220748,7 @@ static int fts5UnicodeTokenize( /* Each iteration of this loop gobbles up a contiguous run of separators, ** then the next token. */ while( rc==SQLITE_OK ){ - int iCode; /* non-ASCII codepoint read from input */ + u32 iCode; /* non-ASCII codepoint read from input */ char *zOut = aFold; int is; int ie; @@ -216176,7 +220780,7 @@ static int fts5UnicodeTokenize( /* Grow the output buffer so that there is sufficient space to fit the ** largest possible utf-8 character. */ if( zOut>pEnd ){ - aFold = sqlite3_malloc(nFold*2); + aFold = sqlite3_malloc64((sqlite3_int64)nFold*2); if( aFold==0 ){ rc = SQLITE_NOMEM; goto tokenize_done; @@ -216195,7 +220799,7 @@ static int fts5UnicodeTokenize( READ_UTF8(zCsr, zTerm, iCode); if( fts5UnicodeIsAlnum(p,iCode)||sqlite3Fts5UnicodeIsdiacritic(iCode) ){ non_ascii_tokenchar: - iCode = sqlite3Fts5UnicodeFold(iCode, p->bRemoveDiacritic); + iCode = sqlite3Fts5UnicodeFold(iCode, p->eRemoveDiacritic); if( iCode ) WRITE_UTF8(zOut, iCode); }else{ break; @@ -216971,10 +221575,8 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ return rc; } - - /* -** 2012 May 25 +** 2012-05-25 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -217003,32 +221605,48 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ ** E"). The resuls of passing a codepoint that corresponds to an ** uppercase letter are undefined. */ -static int fts5_remove_diacritic(int c){ +static int fts5_remove_diacritic(int c, int bComplex){ unsigned short aDia[] = { 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995, 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286, 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732, 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336, - 3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928, - 3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234, - 4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504, - 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529, - 61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726, - 61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122, - 62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536, - 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, - 62924, 63050, 63082, 63274, 63390, + 3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896, + 3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106, + 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344, + 4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198, + 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468, + 61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704, + 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914, + 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218, + 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554, + 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766, + 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118, + 63182, 63242, 63274, 63310, 63368, 63390, }; - char aChar[] = { - '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c', - 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r', - 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o', - 'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r', - 'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h', - 'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't', - 'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a', - 'e', 'i', 'o', 'u', 'y', +#define HIBIT ((unsigned char)0x80) + unsigned char aChar[] = { + '\0', 'a', 'c', 'e', 'i', 'n', + 'o', 'u', 'y', 'y', 'a', 'c', + 'd', 'e', 'e', 'g', 'h', 'i', + 'j', 'k', 'l', 'n', 'o', 'r', + 's', 't', 'u', 'u', 'w', 'y', + 'z', 'o', 'u', 'a', 'i', 'o', + 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o', + 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a', + 'e', 'i', 'o', 'r', 'u', 's', + 't', 'h', 'a', 'e', 'o'|HIBIT, 'o', + 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', 'a', 'b', + 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT, + 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT, + 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n', + 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's', + 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w', + 'w', 'x', 'y', 'z', 'h', 't', + 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT, + 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT, + 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y', }; unsigned int key = (((unsigned int)c)<<3) | 0x00000007; @@ -217045,7 +221663,8 @@ static int fts5_remove_diacritic(int c){ } } assert( key>=aDia[iRes] ); - return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]); + if( bComplex==0 && (aChar[iRes] & 0x80) ) return c; + return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F); } @@ -217058,8 +221677,8 @@ static int sqlite3Fts5UnicodeIsdiacritic(int c){ unsigned int mask1 = 0x000361F8; if( c<768 || c>817 ) return 0; return (c < 768+32) ? - (mask0 & (1 << (c-768))) : - (mask1 & (1 << (c-768-32))); + (mask0 & ((unsigned int)1 << (c-768))) : + (mask1 & ((unsigned int)1 << (c-768-32))); } @@ -217072,7 +221691,7 @@ static int sqlite3Fts5UnicodeIsdiacritic(int c){ ** The results are undefined if the value passed to this function ** is less than zero. */ -static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){ +static int sqlite3Fts5UnicodeFold(int c, int eRemoveDiacritic){ /* Each entry in the following array defines a rule for folding a range ** of codepoints to lower case. The rule applies to a range of nRange ** codepoints starting at codepoint iCode. @@ -217195,7 +221814,9 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){ assert( ret>0 ); } - if( bRemoveDiacritic ) ret = fts5_remove_diacritic(ret); + if( eRemoveDiacritic ){ + ret = fts5_remove_diacritic(ret, eRemoveDiacritic==2); + } } else if( c>=66560 && c<66600 ){ @@ -217206,12 +221827,6 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){ } -#if 0 -static int sqlite3Fts5UnicodeNCat(void) { - return 32; -} -#endif - static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){ aArray[0] = 1; switch( zCat[0] ){ @@ -217693,7 +222308,7 @@ static u16 aFts5UnicodeData[] = { 34, 3074, 7692, 63, 63, }; -static int sqlite3Fts5UnicodeCategory(int iCode) { +static int sqlite3Fts5UnicodeCategory(u32 iCode) { int iRes = -1; int iHi; int iLo; @@ -217737,7 +222352,6 @@ static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ } } - /* ** 2015 May 30 ** @@ -217816,7 +222430,7 @@ static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v){ u8 n; p -= 2; n = sqlite3Fts5GetVarint(p, &v64); - *v = (u32)v64; + *v = ((u32)v64) & 0x7FFFFFFF; assert( n>3 && n<=9 ); return n; } @@ -218083,7 +222697,6 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){ return 5; } - /* ** 2015 May 08 ** @@ -218141,7 +222754,7 @@ struct Fts5VocabTable { struct Fts5VocabCursor { sqlite3_vtab_cursor base; sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */ - Fts5Index *pIndex; /* Associated FTS5 index */ + Fts5Table *pFts5; /* Associated FTS5 table */ int bEof; /* True if this cursor is at EOF */ Fts5IndexIter *pIter; /* Term/rowid iterator object */ @@ -218150,7 +222763,6 @@ struct Fts5VocabCursor { char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */ /* These are used by 'col' tables only */ - Fts5Config *pConfig; /* Fts5 table configuration */ int iCol; i64 *aCnt; i64 *aDoc; @@ -218413,8 +223025,7 @@ static int fts5VocabOpenMethod( sqlite3_vtab_cursor **ppCsr ){ Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab; - Fts5Index *pIndex = 0; - Fts5Config *pConfig = 0; + Fts5Table *pFts5 = 0; Fts5VocabCursor *pCsr = 0; int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; @@ -218433,31 +223044,34 @@ static int fts5VocabOpenMethod( if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ i64 iId = sqlite3_column_int64(pStmt, 0); - pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig); + pFts5 = sqlite3Fts5TableFromCsrid(pTab->pGlobal, iId); } - if( rc==SQLITE_OK && pIndex==0 ){ - rc = sqlite3_finalize(pStmt); - pStmt = 0; - if( rc==SQLITE_OK ){ - pVTab->zErrMsg = sqlite3_mprintf( - "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl - ); - rc = SQLITE_ERROR; + if( rc==SQLITE_OK ){ + if( pFts5==0 ){ + rc = sqlite3_finalize(pStmt); + pStmt = 0; + if( rc==SQLITE_OK ){ + pVTab->zErrMsg = sqlite3_mprintf( + "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl + ); + rc = SQLITE_ERROR; + } + }else{ + rc = sqlite3Fts5FlushToDisk(pFts5); } } if( rc==SQLITE_OK ){ - int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor); + int nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor); pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte); } if( pCsr ){ - pCsr->pIndex = pIndex; + pCsr->pFts5 = pFts5; pCsr->pStmt = pStmt; - pCsr->pConfig = pConfig; pCsr->aCnt = (i64*)&pCsr[1]; - pCsr->aDoc = &pCsr->aCnt[pConfig->nCol]; + pCsr->aDoc = &pCsr->aCnt[pFts5->pConfig->nCol]; }else{ sqlite3_finalize(pStmt); } @@ -218473,6 +223087,7 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){ sqlite3_free(pCsr->zLeTerm); pCsr->nLeTerm = -1; pCsr->zLeTerm = 0; + pCsr->bEof = 0; } /* @@ -218511,12 +223126,14 @@ static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){ } static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){ - int eDetail = pCsr->pConfig->eDetail; + int eDetail = pCsr->pFts5->pConfig->eDetail; int rc = SQLITE_OK; Fts5IndexIter *pIter = pCsr->pIter; i64 *pp = &pCsr->iInstPos; int *po = &pCsr->iInstOff; + assert( sqlite3Fts5IterEof(pIter)==0 ); + assert( pCsr->bEof==0 ); while( eDetail==FTS5_DETAIL_NONE || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp) ){ @@ -218526,7 +223143,7 @@ static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){ rc = sqlite3Fts5IterNextScan(pCsr->pIter); if( rc==SQLITE_OK ){ rc = fts5VocabInstanceNewTerm(pCsr); - if( eDetail==FTS5_DETAIL_NONE ) break; + if( pCsr->bEof || eDetail==FTS5_DETAIL_NONE ) break; } if( rc ){ pCsr->bEof = 1; @@ -218544,7 +223161,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; int rc = SQLITE_OK; - int nCol = pCsr->pConfig->nCol; + int nCol = pCsr->pFts5->pConfig->nCol; pCsr->rowid++; @@ -218566,6 +223183,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ int nTerm; zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); + assert( nTerm>=0 ); if( pCsr->nLeTerm>=0 ){ int nCmp = MIN(nTerm, pCsr->nLeTerm); int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp); @@ -218582,7 +223200,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW ); while( rc==SQLITE_OK ){ - int eDetail = pCsr->pConfig->eDetail; + int eDetail = pCsr->pFts5->pConfig->eDetail; const u8 *pPos; int nPos; /* Position list */ i64 iPos = 0; /* 64-bit position read from poslist */ int iOff = 0; /* Current offset within position list */ @@ -218605,7 +223223,6 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ int iCol = -1; while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ int ii = FTS5_POS2COLUMN(iPos); - pCsr->aCnt[ii]++; if( iCol!=ii ){ if( ii>=nCol ){ rc = FTS5_CORRUPT; @@ -218614,6 +223231,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ pCsr->aDoc[ii]++; iCol = ii; } + pCsr->aCnt[ii]++; } }else if( eDetail==FTS5_DETAIL_COLUMNS ){ while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){ @@ -218642,7 +223260,9 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ if( rc==SQLITE_OK ){ zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); - if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){ + if( nTerm!=pCsr->term.n + || (nTerm>0 && memcmp(zTerm, pCsr->term.p, nTerm)) + ){ break; } if( sqlite3Fts5IterEof(pCsr->pIter) ) break; @@ -218652,8 +223272,10 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ } if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ - while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++; - assert( pCsr->iColpConfig->nCol ); + for(/* noop */; pCsr->iColaDoc[pCsr->iCol]==0; pCsr->iCol++); + if( pCsr->iCol==nCol ){ + rc = FTS5_CORRUPT; + } } return rc; } @@ -218700,6 +223322,7 @@ static int fts5VocabFilterMethod( } if( pLe ){ const char *zCopy = (const char *)sqlite3_value_text(pLe); + if( zCopy==0 ) zCopy = ""; pCsr->nLeTerm = sqlite3_value_bytes(pLe); pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1); if( pCsr->zLeTerm==0 ){ @@ -218711,14 +223334,15 @@ static int fts5VocabFilterMethod( } if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); + Fts5Index *pIndex = pCsr->pFts5->pIndex; + rc = sqlite3Fts5IndexQuery(pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); } if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){ rc = fts5VocabInstanceNewTerm(pCsr); } - if( rc==SQLITE_OK - && !pCsr->bEof - && (eType!=FTS5_VOCAB_INSTANCE || pCsr->pConfig->eDetail!=FTS5_DETAIL_NONE) + if( rc==SQLITE_OK && !pCsr->bEof + && (eType!=FTS5_VOCAB_INSTANCE + || pCsr->pFts5->pConfig->eDetail!=FTS5_DETAIL_NONE) ){ rc = fts5VocabNextMethod(pCursor); } @@ -218741,7 +223365,7 @@ static int fts5VocabColumnMethod( int iCol /* Index of column to read value from */ ){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; - int eDetail = pCsr->pConfig->eDetail; + int eDetail = pCsr->pFts5->pConfig->eDetail; int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType; i64 iVal = 0; @@ -218753,7 +223377,7 @@ static int fts5VocabColumnMethod( assert( iCol==1 || iCol==2 || iCol==3 ); if( iCol==1 ){ if( eDetail!=FTS5_DETAIL_NONE ){ - const char *z = pCsr->pConfig->azCol[pCsr->iCol]; + const char *z = pCsr->pFts5->pConfig->azCol[pCsr->iCol]; sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); } }else if( iCol==2 ){ @@ -218781,8 +223405,8 @@ static int fts5VocabColumnMethod( }else if( eDetail==FTS5_DETAIL_COLUMNS ){ ii = (int)pCsr->iInstPos; } - if( ii>=0 && iipConfig->nCol ){ - const char *z = pCsr->pConfig->azCol[ii]; + if( ii>=0 && iipFts5->pConfig->nCol ){ + const char *z = pCsr->pFts5->pConfig->azCol[ii]; sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); } break; @@ -218841,6 +223465,7 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, + /* xShadowName */ 0 }; void *p = (void*)pGlobal; @@ -218848,8 +223473,6 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ } - - #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */ @@ -219123,6 +223746,7 @@ static sqlite3_module stmtModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0, /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -219155,9 +223779,9 @@ SQLITE_API int sqlite3_stmt_init( #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ /************** End of stmt.c ************************************************/ -#if __LINE__!=219157 +#if __LINE__!=223781 #undef SQLITE_SOURCE_ID -#define SQLITE_SOURCE_ID "2018-09-25 19:08:10 fb90e7189ae6d62e77ba3a308ca5d683f90bbe633cf681865365b8e92792alt2" +#define SQLITE_SOURCE_ID "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88alt2" #endif /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h index 05d11a8a6fa56..a85240a167c3c 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h @@ -124,9 +124,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.25.2" -#define SQLITE_VERSION_NUMBER 3025002 -#define SQLITE_SOURCE_ID "2018-09-25 19:08:10 fb90e7189ae6d62e77ba3a308ca5d683f90bbe633cf681865365b8e92792d1c7" +#define SQLITE_VERSION "3.29.0" +#define SQLITE_VERSION_NUMBER 3029000 +#define SQLITE_SOURCE_ID "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88bfa6" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -190,6 +190,9 @@ SQLITE_API int sqlite3_libversion_number(void); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_API int sqlite3_compileoption_used(const char *zOptName); SQLITE_API const char *sqlite3_compileoption_get(int N); +#else +# define sqlite3_compileoption_used(X) 0 +# define sqlite3_compileoption_get(X) ((void*)0) #endif /* @@ -824,6 +827,15 @@ struct sqlite3_io_methods { ** file space based on this hint in order to help writes to the database ** file run faster. ** +**
  • [[SQLITE_FCNTL_SIZE_LIMIT]] +** The [SQLITE_FCNTL_SIZE_LIMIT] opcode is used by in-memory VFS that +** implements [sqlite3_deserialize()] to set an upper bound on the size +** of the in-memory database. The argument is a pointer to a [sqlite3_int64]. +** If the integer pointed to is negative, then it is filled in with the +** current limit. Otherwise the limit is set to the larger of the value +** of the integer pointed to and the current database size. The integer +** pointed to is set to the new limit. +** **
  • [[SQLITE_FCNTL_CHUNK_SIZE]] ** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS ** extends and truncates the database file in chunks of a size specified @@ -1132,6 +1144,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 #define SQLITE_FCNTL_LOCK_TIMEOUT 34 #define SQLITE_FCNTL_DATA_VERSION 35 +#define SQLITE_FCNTL_SIZE_LIMIT 36 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -1284,8 +1297,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] -** to test whether a file is at least readable. The file can be a -** directory. +** to test whether a file is at least readable. The SQLITE_ACCESS_READ +** flag is never actually used and is not implemented in the built-in +** VFSes of SQLite. The file is named by the second argument and can be a +** directory. The xAccess method returns [SQLITE_OK] on success or some +** non-zero error code if there is an I/O error or if the name of +** the file given in the second argument is illegal. If SQLITE_OK +** is returned, then non-zero or zero is written into *pResOut to indicate +** whether or not the file is accessible. ** ** ^SQLite will always allocate at least mxPathname+1 bytes for the ** output buffer xFullPathname. The exact size of the output buffer @@ -1973,6 +1992,17 @@ struct sqlite3_mem_methods { ** negative value for this option restores the default behaviour. ** This option is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. +** +** [[SQLITE_CONFIG_MEMDB_MAXSIZE]] +**
    SQLITE_CONFIG_MEMDB_MAXSIZE +**
    The SQLITE_CONFIG_MEMDB_MAXSIZE option accepts a single parameter +** [sqlite3_int64] parameter which is the default maximum size for an in-memory +** database created using [sqlite3_deserialize()]. This default maximum +** size can be adjusted up or down for individual databases using the +** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this +** configuration setting is never used, then the default maximum is determined +** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that +** compile-time option is not set, then the default maximum is 1073741824. **
  • */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -2003,6 +2033,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ +#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ /* ** CAPI3REF: Database Connection Configuration Options @@ -2018,6 +2049,7 @@ struct sqlite3_mem_methods { ** is invoked. ** **
    +** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    **
    ^This option takes three additional arguments that determine the ** [lookaside memory allocator] configuration for the [database connection]. @@ -2040,6 +2072,7 @@ struct sqlite3_mem_methods { ** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^
    ** +** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **
    SQLITE_DBCONFIG_ENABLE_FKEY
    **
    ^This option is used to enable or disable the enforcement of ** [foreign key constraints]. There should be two additional arguments. @@ -2050,6 +2083,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the FK enforcement setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_TRIGGER]] **
    SQLITE_DBCONFIG_ENABLE_TRIGGER
    **
    ^This option is used to enable or disable [CREATE TRIGGER | triggers]. ** There should be two additional arguments. @@ -2060,9 +2094,10 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the trigger setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] **
    SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
    -**
    ^This option is used to enable or disable the two-argument -** version of the [fts3_tokenizer()] function which is part of the +**
    ^This option is used to enable or disable the +** [fts3_tokenizer()] function which is part of the ** [FTS3] full-text search engine extension. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable fts3_tokenizer() or @@ -2073,6 +2108,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the new setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]] **
    SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
    **
    ^This option is used to enable or disable the [sqlite3_load_extension()] ** interface independently of the [load_extension()] SQL function. @@ -2090,7 +2126,7 @@ struct sqlite3_mem_methods { ** be a NULL pointer, in which case the new setting is not reported back. **
    ** -**
    SQLITE_DBCONFIG_MAINDBNAME
    +** [[SQLITE_DBCONFIG_MAINDBNAME]]
    SQLITE_DBCONFIG_MAINDBNAME
    **
    ^This option is used to change the name of the "main" database ** schema. ^The sole argument is a pointer to a constant UTF8 string ** which will become the new schema name in place of "main". ^SQLite @@ -2099,6 +2135,7 @@ struct sqlite3_mem_methods { ** until after the database connection closes. **
    ** +** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] **
    SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
    **
    Usually, when a database in wal mode is closed or detached from a ** database handle, SQLite checks if this will mean that there are now no @@ -2112,7 +2149,7 @@ struct sqlite3_mem_methods { ** have been disabled - 0 if they are not disabled, 1 if they are. **
    ** -**
    SQLITE_DBCONFIG_ENABLE_QPSG
    +** [[SQLITE_DBCONFIG_ENABLE_QPSG]]
    SQLITE_DBCONFIG_ENABLE_QPSG
    **
    ^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates ** the [query planner stability guarantee] (QPSG). When the QPSG is active, ** a single SQL query statement will always use the same algorithm regardless @@ -2128,7 +2165,7 @@ struct sqlite3_mem_methods { ** following this call. **
    ** -**
    SQLITE_DBCONFIG_TRIGGER_EQP
    +** [[SQLITE_DBCONFIG_TRIGGER_EQP]]
    SQLITE_DBCONFIG_TRIGGER_EQP
    **
    By default, the output of EXPLAIN QUERY PLAN commands does not ** include output for any operations performed by trigger programs. This ** option is used to set or clear (the default) a flag that governs this @@ -2140,7 +2177,7 @@ struct sqlite3_mem_methods { ** it is not disabled, 1 if it is. **
    ** -**
    SQLITE_DBCONFIG_RESET_DATABASE
    +** [[SQLITE_DBCONFIG_RESET_DATABASE]]
    SQLITE_DBCONFIG_RESET_DATABASE
    **
    Set the SQLITE_DBCONFIG_RESET_DATABASE flag and then run ** [VACUUM] in order to reset a database back to an empty database ** with no schema and no content. The following process works even for @@ -2159,6 +2196,58 @@ struct sqlite3_mem_methods { ** Because resetting a database is destructive and irreversible, the ** process requires the use of this obscure API and multiple steps to help ** ensure that it does not happen by accident. +** +** [[SQLITE_DBCONFIG_DEFENSIVE]]
    SQLITE_DBCONFIG_DEFENSIVE
    +**
    The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the +** "defensive" flag for a database connection. When the defensive +** flag is enabled, language features that allow ordinary SQL to +** deliberately corrupt the database file are disabled. The disabled +** features include but are not limited to the following: +**
      +**
    • The [PRAGMA writable_schema=ON] statement. +**
    • The [PRAGMA journal_mode=OFF] statement. +**
    • Writes to the [sqlite_dbpage] virtual table. +**
    • Direct writes to [shadow tables]. +**
    +**
    +** +** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]]
    SQLITE_DBCONFIG_WRITABLE_SCHEMA
    +**
    The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the +** "writable_schema" flag. This has the same effect and is logically equivalent +** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF]. +** The first argument to this setting is an integer which is 0 to disable +** the writable_schema, positive to enable writable_schema, or negative to +** leave the setting unchanged. The second parameter is a pointer to an +** integer into which is written 0 or 1 to indicate whether the writable_schema +** is enabled or disabled following this call. +**
    +** +** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]] +**
    SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
    +**
    The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates +** the legacy behavior of the [ALTER TABLE RENAME] command such it +** behaves as it did prior to [version 3.24.0] (2018-06-04). See the +** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for +** additional information. This feature can also be turned on and off +** using the [PRAGMA legacy_alter_table] statement. +**
    +** +** [[SQLITE_DBCONFIG_DQS_DML]] +**
    SQLITE_DBCONFIG_DQS_DML +**
    The SQLITE_DBCONFIG_DQS_DML option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DML statement +** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. +**
    +** +** [[SQLITE_DBCONFIG_DQS_DDL]] +**
    SQLITE_DBCONFIG_DQS_DDL +**
    The SQLITE_DBCONFIG_DQS option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DDL statements, +** such as CREATE TABLE and CREATE INDEX. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. **
    **
    */ @@ -2172,7 +2261,12 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ #define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ #define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1009 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ +#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ +#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1014 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -2329,7 +2423,7 @@ SQLITE_API int sqlite3_changes(sqlite3*); ** not. ^Changes to a view that are intercepted by INSTEAD OF triggers ** are not counted. ** -** This the [sqlite3_total_changes(D)] interface only reports the number +** The [sqlite3_total_changes(D)] interface only reports the number ** of rows that changed due to SQL statement run against database ** connection D. Any changes by other database connections are ignored. ** To detect changes against a database file from other database @@ -2973,9 +3067,9 @@ SQLITE_API int sqlite3_set_authorizer( ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite -** might provide greater resolution on the profiler callback. The -** sqlite3_profile() function is considered experimental and is -** subject to change in future versions of SQLite. +** might provide greater resolution on the profiler callback. Invoking +** either [sqlite3_trace()] or [sqlite3_trace_v2()] will cancel the +** profile callback. */ SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); @@ -3389,6 +3483,8 @@ SQLITE_API int sqlite3_open_v2( ** is not a database file pathname pointer that SQLite passed into the xOpen ** VFS method, then the behavior of this routine is undefined and probably ** undesirable. +** +** See the [URI filename] documentation for additional information. */ SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); @@ -3610,9 +3706,24 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** on this hint by avoiding the use of [lookaside memory] so as not to ** deplete the limited store of lookaside memory. Future versions of ** SQLite may act on this hint differently. +** +** [[SQLITE_PREPARE_NORMALIZE]]
    SQLITE_PREPARE_NORMALIZE
    +**
    The SQLITE_PREPARE_NORMALIZE flag is a no-op. This flag used +** to be required for any prepared statement that wanted to use the +** [sqlite3_normalized_sql()] interface. However, the +** [sqlite3_normalized_sql()] interface is now available to all +** prepared statements, regardless of whether or not they use this +** flag. +** +** [[SQLITE_PREPARE_NO_VTAB]]
    SQLITE_PREPARE_NO_VTAB
    +**
    The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler +** to return an error (error code SQLITE_ERROR) if the statement uses +** any virtual tables. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 +#define SQLITE_PREPARE_NORMALIZE 0x02 +#define SQLITE_PREPARE_NO_VTAB 0x04 /* ** CAPI3REF: Compiling An SQL Statement @@ -3770,6 +3881,11 @@ SQLITE_API int sqlite3_prepare16_v3( ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 ** string containing the SQL text of prepared statement P with ** [bound parameters] expanded. +** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8 +** string containing the normalized SQL text of prepared statement P. The +** semantics used to normalize a SQL statement are unspecified and subject +** to change. At a minimum, literal values will be replaced with suitable +** placeholders. ** ** ^(For example, if a prepared statement is created using the SQL ** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 @@ -3785,14 +3901,16 @@ SQLITE_API int sqlite3_prepare16_v3( ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time ** option causes sqlite3_expanded_sql() to always return NULL. ** -** ^The string returned by sqlite3_sql(P) is managed by SQLite and is -** automatically freed when the prepared statement is finalized. +** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) +** are managed by SQLite and are automatically freed when the prepared +** statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, ** is obtained from [sqlite3_malloc()] and must be free by the application ** by passing it to [sqlite3_free()]. */ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); +SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database @@ -3830,6 +3948,18 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); */ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); +/* +** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement +** METHOD: sqlite3_stmt +** +** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the +** prepared statement S is an EXPLAIN statement, or 2 if the +** statement S is an EXPLAIN QUERY PLAN. +** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is +** an ordinary statement or a NULL pointer. +*/ +SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); + /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt @@ -3969,7 +4099,9 @@ typedef struct sqlite3_context sqlite3_context; ** ^The fifth argument to the BLOB and string binding interfaces ** is a destructor used to dispose of the BLOB or ** string after SQLite has finished with it. ^The destructor is called -** to dispose of the BLOB or string even if the call to bind API fails. +** to dispose of the BLOB or string even if the call to the bind API fails, +** except the destructor is not called if the third parameter is a NULL +** pointer or the fourth parameter is negative. ** ^If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. @@ -4886,6 +5018,8 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** sqlite3_value_nochange   ** →  True if the column is unchanged in an UPDATE ** against a virtual table. +** sqlite3_value_frombind   +** →  True if value originated from a [bound parameter] ** ** ** Details: @@ -4947,6 +5081,11 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** than within an [xUpdate] method call for an UPDATE statement, then ** the return value is arbitrary and meaningless. ** +** ^The sqlite3_value_frombind(X) interface returns non-zero if the +** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] +** interfaces. ^If X comes from an SQL literal value, or a table column, +** and expression, then sqlite3_value_frombind(X) returns zero. +** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to @@ -4992,6 +5131,7 @@ SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); +SQLITE_API int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values @@ -5727,7 +5867,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); ** associated with database N of connection D. ^The main database file ** has the name "main". If there is no attached database N on the database ** connection D, or if database N is a temporary or in-memory database, then -** a NULL pointer is returned. +** this function will return either a NULL pointer or an empty string. ** ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename @@ -6282,6 +6422,9 @@ struct sqlite3_module { int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); + /* The methods above are in versions 1 and 2 of the sqlite_module object. + ** Those below are for version 3 and greater. */ + int (*xShadowName)(const char*); }; /* @@ -7204,6 +7347,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ +#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 @@ -7214,7 +7358,8 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_SORTER_MMAP 24 #define SQLITE_TESTCTRL_IMPOSTER 25 #define SQLITE_TESTCTRL_PARSER_COVERAGE 26 -#define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_RESULT_INTREAL 27 +#define SQLITE_TESTCTRL_LAST 27 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -8616,6 +8761,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** can use to customize and optimize their behavior. ** **
    +** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]] **
    SQLITE_VTAB_CONSTRAINT_SUPPORT **
    Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, @@ -9385,7 +9531,7 @@ struct sqlite3_rtree_query_info { sqlite3_int64 iRowid; /* Rowid for current entry */ sqlite3_rtree_dbl rParentScore; /* Score of parent node */ int eParentWithin; /* Visibility of parent node */ - int eWithin; /* OUT: Visiblity */ + int eWithin; /* OUT: Visibility */ sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ /* The following fields are only available in 3.8.11 and later */ sqlite3_value **apSqlParam; /* Original SQL values of parameters */ @@ -9881,12 +10027,38 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); ** consecutively. There is no chance that the iterator will visit a change ** the applies to table X, then one for table Y, and then later on visit ** another change for table X. +** +** The behavior of sqlite3changeset_start_v2() and its streaming equivalent +** may be modified by passing a combination of +** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter. +** +** Note that the sqlite3changeset_start_v2() API is still experimental +** and therefore subject to change. */ SQLITE_API int sqlite3changeset_start( sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset /* Pointer to blob containing changeset */ ); +SQLITE_API int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset, /* Pointer to blob containing changeset */ + int flags /* SESSION_CHANGESETSTART_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3changeset_start_v2 +** +** The following flags may passed via the 4th parameter to +** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: +** +**
    SQLITE_CHANGESETAPPLY_INVERT
    +** Invert the changeset while iterating through it. This is equivalent to +** inverting a changeset using sqlite3changeset_invert() before applying it. +** It is an error to specify this flag with a patchset. +*/ +#define SQLITE_CHANGESETSTART_INVERT 0x0002 /* @@ -9930,7 +10102,7 @@ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); ** sqlite3changeset_next() is called on the iterator or until the ** conflict-handler function returns. If pnCol is not NULL, then *pnCol is ** set to the number of columns in the table affected by the change. If -** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change +** pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change ** is an indirect change, or false (0) otherwise. See the documentation for ** [sqlite3session_indirect()] for a description of direct and indirect ** changes. Finally, if pOp is not NULL, then *pOp is set to one of @@ -10541,7 +10713,7 @@ SQLITE_API int sqlite3changeset_apply_v2( ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, /* OUT: Rebase data */ - int flags /* Combination of SESSION_APPLY_* flags */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ ); /* @@ -10559,8 +10731,14 @@ SQLITE_API int sqlite3changeset_apply_v2( ** causes the sessions module to omit this savepoint. In this case, if the ** caller has an open transaction or savepoint when apply_v2() is called, ** it may revert the partially applied changeset by rolling it back. +** +**
    SQLITE_CHANGESETAPPLY_INVERT
    +** Invert the changeset before applying it. This is equivalent to inverting +** a changeset using sqlite3changeset_invert() before applying it. It is +** an error to specify this flag with a patchset. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 +#define SQLITE_CHANGESETAPPLY_INVERT 0x0002 /* ** CAPI3REF: Constants Passed To The Conflict Handler @@ -10791,7 +10969,7 @@ SQLITE_API int sqlite3rebaser_configure( ** in size. This function allocates and populates a buffer with a copy ** of the changeset rebased rebased according to the configuration of the ** rebaser object passed as the first argument. If successful, (*ppOut) -** is set to point to the new buffer containing the rebased changset and +** is set to point to the new buffer containing the rebased changeset and ** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the ** responsibility of the caller to eventually free the new buffer using ** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut) @@ -10954,6 +11132,12 @@ SQLITE_API int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); +SQLITE_API int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +); SQLITE_API int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), @@ -10980,6 +11164,45 @@ SQLITE_API int sqlite3rebaser_rebase_strm( void *pOut ); +/* +** CAPI3REF: Configure global parameters +** +** The sqlite3session_config() interface is used to make global configuration +** changes to the sessions module in order to tune it to the specific needs +** of the application. +** +** The sqlite3session_config() interface is not threadsafe. If it is invoked +** while any other thread is inside any other sessions method then the +** results are undefined. Furthermore, if it is invoked after any sessions +** related objects have been created, the results are also undefined. +** +** The first argument to the sqlite3session_config() function must be one +** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The +** interpretation of the (void*) value passed as the second parameter and +** the effect of calling this function depends on the value of the first +** parameter. +** +**
    +**
    SQLITE_SESSION_CONFIG_STRMSIZE
    +** By default, the sessions module streaming interfaces attempt to input +** and output data in approximately 1 KiB chunks. This operand may be used +** to set and query the value of this configuration setting. The pointer +** passed as the second argument must point to a value of type (int). +** If this value is greater than 0, it is used as the new streaming data +** chunk size for both input and output. Before returning, the (int) value +** pointed to by pArg is set to the final value of the streaming interface +** chunk size. +**
    +** +** This function returns SQLITE_OK if successful, or an SQLite error code +** otherwise. +*/ +SQLITE_API int sqlite3session_config(int op, void *pArg); + +/* +** CAPI3REF: Values for sqlite3session_config(). +*/ +#define SQLITE_SESSION_CONFIG_STRMSIZE 1 /* ** Make sure we can call this stuff from C++. @@ -11113,12 +11336,8 @@ struct Fts5PhraseIter { ** ** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. The exception is if the table was created -** with the offsets=0 option specified. In this case *piOff is always -** set to -1. -** -** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) -** if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. @@ -11159,7 +11378,7 @@ struct Fts5PhraseIter { ** Save the pointer passed as the second argument as the extension functions ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of -** of the same MATCH query using the xGetAuxdata() API. +** the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for ** each FTS query (MATCH expression). If the extension function is invoked @@ -11174,7 +11393,7 @@ struct Fts5PhraseIter { ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** -** If an error (e.g. an OOM condition) occurs within this function, an +** If an error (e.g. an OOM condition) occurs within this function, ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. @@ -11407,11 +11626,11 @@ struct Fts5ExtensionApi { ** the tokenizer substitutes "first" for "1st" and the query works ** as expected. ** -**
  • By adding multiple synonyms for a single term to the FTS index. -** In this case, when tokenizing query text, the tokenizer may -** provide multiple synonyms for a single term within the document. -** FTS5 then queries the index for each synonym individually. For -** example, faced with the query: +**
  • By querying the index for all synonyms of each query term +** separately. In this case, when tokenizing query text, the +** tokenizer may provide multiple synonyms for a single term +** within the document. FTS5 then queries the index for each +** synonym individually. For example, faced with the query: ** ** ** ... MATCH 'first place' @@ -11435,7 +11654,7 @@ struct Fts5ExtensionApi { ** "place". ** ** This way, even if the tokenizer does not provide synonyms -** when tokenizing query text (it should not - to do would be +** when tokenizing query text (it should not - to do so would be ** inefficient), it doesn't matter if the user queries for ** 'first + place' or '1st + place', as there are entries in the ** FTS index corresponding to both forms of the first token. diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3.go b/vendor/github.com/mattn/go-sqlite3/sqlite3.go index 942b0b5bcb592..9e9e91a1f53d6 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3.go +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3.go @@ -683,7 +683,7 @@ func (c *SQLiteConn) RegisterAggregator(name string, impl interface{}, pure bool ai.stepArgConverters = append(ai.stepArgConverters, conv) } if step.IsVariadic() { - conv, err := callbackArg(t.In(start + stepNArgs).Elem()) + conv, err := callbackArg(step.In(start + stepNArgs).Elem()) if err != nil { return err } @@ -740,6 +740,8 @@ func (c *SQLiteConn) RegisterAggregator(name string, impl interface{}, pure bool // AutoCommit return which currently auto commit or not. func (c *SQLiteConn) AutoCommit() bool { + c.mu.Lock() + defer c.mu.Unlock() return int(C.sqlite3_get_autocommit(c.db)) != 0 } @@ -1340,6 +1342,9 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { mutex|C.SQLITE_OPEN_READWRITE|C.SQLITE_OPEN_CREATE, nil) if rv != 0 { + if db != nil { + C.sqlite3_close_v2(db) + } return nil, Error{Code: ErrNo(rv)} } if db == nil { @@ -1376,7 +1381,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { // - Activate User Authentication // Check if the user wants to activate User Authentication. // If so then first create a temporary AuthConn to the database - // This is possible because we are already succesfully authenticated. + // This is possible because we are already successfully authenticated. // // - Check if `sqlite_user`` table exists // YES => Add the provided user from DSN as Admin User and @@ -1387,7 +1392,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { // Create connection to SQLite conn := &SQLiteConn{db: db, loc: loc, txlock: txlock} - // Password Cipher has to be registerd before authentication + // Password Cipher has to be registered before authentication if len(authCrypt) > 0 { switch strings.ToUpper(authCrypt) { case "SHA1": @@ -1674,7 +1679,7 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er defer C.free(unsafe.Pointer(pquery)) var s *C.sqlite3_stmt var tail *C.char - rv := C._sqlite3_prepare_v2_internal(c.db, pquery, -1, &s, &tail) + rv := C._sqlite3_prepare_v2_internal(c.db, pquery, C.int(-1), &s, &tail) if rv != C.SQLITE_OK { return nil, c.lastError() } @@ -1718,7 +1723,7 @@ func (c *SQLiteConn) GetFilename(schemaName string) string { // GetLimit returns the current value of a run-time limit. // See: sqlite3_limit, http://www.sqlite.org/c3ref/limit.html func (c *SQLiteConn) GetLimit(id int) int { - return int(C._sqlite3_limit(c.db, C.int(id), -1)) + return int(C._sqlite3_limit(c.db, C.int(id), C.int(-1))) } // SetLimit changes the value of a run-time limits. @@ -2024,16 +2029,11 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error { case C.SQLITE_BLOB: p := C.sqlite3_column_blob(rc.s.s, C.int(i)) if p == nil { - dest[i] = nil + dest[i] = []byte{} continue } - n := int(C.sqlite3_column_bytes(rc.s.s, C.int(i))) - switch dest[i].(type) { - default: - slice := make([]byte, n) - copy(slice[:], (*[1 << 30]byte)(p)[0:n]) - dest[i] = slice - } + n := C.sqlite3_column_bytes(rc.s.s, C.int(i)) + dest[i] = C.GoBytes(p, n) case C.SQLITE_NULL: dest[i] = nil case C.SQLITE_TEXT: @@ -2062,9 +2062,8 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error { } dest[i] = t default: - dest[i] = []byte(s) + dest[i] = s } - } } return nil diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_func_crypt.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_func_crypt.go index d397c8cfe6682..afd93333d737d 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3_func_crypt.go +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_func_crypt.go @@ -13,7 +13,7 @@ import ( // This file provides several different implementations for the // default embedded sqlite_crypt function. -// This function is uses a ceasar-cypher by default +// This function is uses a caesar-cypher by default // and is used within the UserAuthentication module to encode // the password. // @@ -40,7 +40,7 @@ import ( // password X, sqlite_crypt(X,NULL) is run. A new random salt is selected // when the second argument is NULL. // -// The built-in version of of sqlite_crypt() uses a simple Ceasar-cypher +// The built-in version of of sqlite_crypt() uses a simple Caesar-cypher // which prevents passwords from being revealed by searching the raw database // for ASCII text, but is otherwise trivally broken. For better password // security, the database should be encrypted using the SQLite Encryption diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go index 43e6418808d00..82b7fea09f453 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go @@ -10,7 +10,6 @@ package sqlite3 import ( "database/sql/driver" - "errors" "context" ) @@ -18,7 +17,8 @@ import ( // Ping implement Pinger. func (c *SQLiteConn) Ping(ctx context.Context) error { if c.db == nil { - return errors.New("Connection was closed") + // must be ErrBadConn for sql to close the database + return driver.ErrBadConn } return nil } diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3ext.h b/vendor/github.com/mattn/go-sqlite3/sqlite3ext.h index 50e6866ac4566..dd515d711ba1b 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3ext.h +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3ext.h @@ -311,12 +311,18 @@ struct sqlite3_api_routines { int (*str_errcode)(sqlite3_str*); int (*str_length)(sqlite3_str*); char *(*str_value)(sqlite3_str*); + /* Version 3.25.0 and later */ int (*create_window_function)(sqlite3*,const char*,int,int,void*, void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInv)(sqlite3_context*,int,sqlite3_value**), void(*xDestroy)(void*)); + /* Version 3.26.0 and later */ + const char *(*normalized_sql)(sqlite3_stmt*); + /* Version 3.28.0 and later */ + int (*stmt_isexplain)(sqlite3_stmt*); + int (*value_frombind)(sqlite3_value*); }; /* @@ -604,6 +610,11 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_str_value sqlite3_api->str_value /* Version 3.25.0 and later */ #define sqlite3_create_window_function sqlite3_api->create_window_function +/* Version 3.26.0 and later */ +#define sqlite3_normalized_sql sqlite3_api->normalized_sql +/* Version 3.28.0 and later */ +#define sqlite3_stmt_isexplain sqlite3_api->isexplain +#define sqlite3_value_frombind sqlite3_api->frombind #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db.go b/vendor/github.com/syndtr/goleveldb/leveldb/db.go index b27c38d37e678..90fedf7bd7d71 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db.go @@ -872,6 +872,10 @@ func (db *DB) Has(key []byte, ro *opt.ReadOptions) (ret bool, err error) { // DB. And a nil Range.Limit is treated as a key after all keys in // the DB. // +// WARNING: Any slice returned by interator (e.g. slice returned by calling +// Iterator.Key() or Iterator.Key() methods), its content should not be modified +// unless noted otherwise. +// // The iterator must be released after use, by calling Release method. // // Also read Iterator documentation of the leveldb/iterator package. diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db_snapshot.go b/vendor/github.com/syndtr/goleveldb/leveldb/db_snapshot.go index 2c69d2e531d53..c2ad70c8476c1 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db_snapshot.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db_snapshot.go @@ -142,6 +142,10 @@ func (snap *Snapshot) Has(key []byte, ro *opt.ReadOptions) (ret bool, err error) // DB. And a nil Range.Limit is treated as a key after all keys in // the DB. // +// WARNING: Any slice returned by interator (e.g. slice returned by calling +// Iterator.Key() or Iterator.Value() methods), its content should not be +// modified unless noted otherwise. +// // The iterator must be released after use, by calling Release method. // Releasing the snapshot doesn't mean releasing the iterator too, the // iterator would be still valid until released. diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db_transaction.go b/vendor/github.com/syndtr/goleveldb/leveldb/db_transaction.go index b8f7e7d21dfa6..1a00001882af5 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db_transaction.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db_transaction.go @@ -69,6 +69,10 @@ func (tr *Transaction) Has(key []byte, ro *opt.ReadOptions) (bool, error) { // DB. And a nil Range.Limit is treated as a key after all keys in // the DB. // +// WARNING: Any slice returned by interator (e.g. slice returned by calling +// Iterator.Key() or Iterator.Key() methods), its content should not be modified +// unless noted otherwise. +// // The iterator must be released after use, by calling Release method. // // Also read Iterator documentation of the leveldb/iterator package. diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go b/vendor/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go index b661c08a93e22..824e47f5f4029 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/memdb/memdb.go @@ -397,6 +397,10 @@ func (p *DB) Find(key []byte) (rkey, value []byte, err error) { // DB. And a nil Range.Limit is treated as a key after all keys in // the DB. // +// WARNING: Any slice returned by interator (e.g. slice returned by calling +// Iterator.Key() or Iterator.Key() methods), its content should not be modified +// unless noted otherwise. +// // The iterator must be released after use, by calling Release method. // // Also read Iterator documentation of the leveldb/iterator package. diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/table/reader.go b/vendor/github.com/syndtr/goleveldb/leveldb/table/reader.go index 16cfbaa0068a7..496feb6fb4588 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/table/reader.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/table/reader.go @@ -787,6 +787,10 @@ func (r *Reader) getDataIterErr(dataBH blockHandle, slice *util.Range, verifyChe // table. And a nil Range.Limit is treated as a key after all keys in // the table. // +// WARNING: Any slice returned by interator (e.g. slice returned by calling +// Iterator.Key() or Iterator.Key() methods), its content should not be modified +// unless noted otherwise. +// // The returned iterator is not safe for concurrent use and should be released // after use. // diff --git a/vendor/google.golang.org/appengine/internal/api.go b/vendor/google.golang.org/appengine/internal/api.go index bbc1cb9c34551..a6ec19e14cfc4 100644 --- a/vendor/google.golang.org/appengine/internal/api.go +++ b/vendor/google.golang.org/appengine/internal/api.go @@ -44,6 +44,7 @@ var ( curNamespaceHeader = http.CanonicalHeaderKey("X-AppEngine-Current-Namespace") userIPHeader = http.CanonicalHeaderKey("X-AppEngine-User-IP") remoteAddrHeader = http.CanonicalHeaderKey("X-AppEngine-Remote-Addr") + devRequestIdHeader = http.CanonicalHeaderKey("X-Appengine-Dev-Request-Id") // Outgoing headers. apiEndpointHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Endpoint") @@ -494,6 +495,9 @@ func Call(ctx netcontext.Context, service, method string, in, out proto.Message) if ticket == "" { ticket = DefaultTicket() } + if dri := c.req.Header.Get(devRequestIdHeader); IsDevAppServer() && dri != "" { + ticket = dri + } req := &remotepb.Request{ ServiceName: &service, Method: &method, diff --git a/vendor/gopkg.in/bufio.v1/.travis.yml b/vendor/gopkg.in/bufio.v1/.travis.yml deleted file mode 100644 index ccca6bb4a61b6..0000000000000 --- a/vendor/gopkg.in/bufio.v1/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: go - -go: - - 1.0 - - 1.1 - - 1.2 - - tip - -install: - - go get launchpad.net/gocheck - - go get gopkg.in/bufio.v1 diff --git a/vendor/gopkg.in/bufio.v1/LICENSE b/vendor/gopkg.in/bufio.v1/LICENSE deleted file mode 100644 index 07a316cbf47f0..0000000000000 --- a/vendor/gopkg.in/bufio.v1/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2013 The bufio Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/gopkg.in/bufio.v1/Makefile b/vendor/gopkg.in/bufio.v1/Makefile deleted file mode 100644 index 038ed47e941eb..0000000000000 --- a/vendor/gopkg.in/bufio.v1/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -all: - go test gopkg.in/bufio.v1 diff --git a/vendor/gopkg.in/bufio.v1/README.md b/vendor/gopkg.in/bufio.v1/README.md deleted file mode 100644 index bfb85ee544f17..0000000000000 --- a/vendor/gopkg.in/bufio.v1/README.md +++ /dev/null @@ -1,4 +0,0 @@ -bufio -===== - -This is a fork of the http://golang.org/pkg/bufio/ package. It adds `ReadN` method that allows reading next `n` bytes from the internal buffer without allocating intermediate buffer. This method works just like the [Buffer.Next](http://golang.org/pkg/bytes/#Buffer.Next) method, but has slightly different signature. diff --git a/vendor/gopkg.in/bufio.v1/buffer.go b/vendor/gopkg.in/bufio.v1/buffer.go deleted file mode 100644 index 8b915605b64b6..0000000000000 --- a/vendor/gopkg.in/bufio.v1/buffer.go +++ /dev/null @@ -1,413 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bufio - -// Simple byte buffer for marshaling data. - -import ( - "bytes" - "errors" - "io" - "unicode/utf8" -) - -// A Buffer is a variable-sized buffer of bytes with Read and Write methods. -// The zero value for Buffer is an empty buffer ready to use. -type Buffer struct { - buf []byte // contents are the bytes buf[off : len(buf)] - off int // read at &buf[off], write at &buf[len(buf)] - runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune - bootstrap [64]byte // memory to hold first slice; helps small buffers (Printf) avoid allocation. - lastRead readOp // last read operation, so that Unread* can work correctly. -} - -// The readOp constants describe the last action performed on -// the buffer, so that UnreadRune and UnreadByte can -// check for invalid usage. -type readOp int - -const ( - opInvalid readOp = iota // Non-read operation. - opReadRune // Read rune. - opRead // Any other read operation. -) - -// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer. -var ErrTooLarge = errors.New("bytes.Buffer: too large") - -// Bytes returns a slice of the contents of the unread portion of the buffer; -// len(b.Bytes()) == b.Len(). If the caller changes the contents of the -// returned slice, the contents of the buffer will change provided there -// are no intervening method calls on the Buffer. -func (b *Buffer) Bytes() []byte { return b.buf[b.off:] } - -// String returns the contents of the unread portion of the buffer -// as a string. If the Buffer is a nil pointer, it returns "". -func (b *Buffer) String() string { - if b == nil { - // Special case, useful in debugging. - return "" - } - return string(b.buf[b.off:]) -} - -// Len returns the number of bytes of the unread portion of the buffer; -// b.Len() == len(b.Bytes()). -func (b *Buffer) Len() int { return len(b.buf) - b.off } - -// Truncate discards all but the first n unread bytes from the buffer. -// It panics if n is negative or greater than the length of the buffer. -func (b *Buffer) Truncate(n int) { - b.lastRead = opInvalid - switch { - case n < 0 || n > b.Len(): - panic("bytes.Buffer: truncation out of range") - case n == 0: - // Reuse buffer space. - b.off = 0 - } - b.buf = b.buf[0 : b.off+n] -} - -// Reset resets the buffer so it has no content. -// b.Reset() is the same as b.Truncate(0). -func (b *Buffer) Reset() { b.Truncate(0) } - -// grow grows the buffer to guarantee space for n more bytes. -// It returns the index where bytes should be written. -// If the buffer can't grow it will panic with ErrTooLarge. -func (b *Buffer) grow(n int) int { - m := b.Len() - // If buffer is empty, reset to recover space. - if m == 0 && b.off != 0 { - b.Truncate(0) - } - if len(b.buf)+n > cap(b.buf) { - var buf []byte - if b.buf == nil && n <= len(b.bootstrap) { - buf = b.bootstrap[0:] - } else if m+n <= cap(b.buf)/2 { - // We can slide things down instead of allocating a new - // slice. We only need m+n <= cap(b.buf) to slide, but - // we instead let capacity get twice as large so we - // don't spend all our time copying. - copy(b.buf[:], b.buf[b.off:]) - buf = b.buf[:m] - } else { - // not enough space anywhere - buf = makeSlice(2*cap(b.buf) + n) - copy(buf, b.buf[b.off:]) - } - b.buf = buf - b.off = 0 - } - b.buf = b.buf[0 : b.off+m+n] - return b.off + m -} - -// Grow grows the buffer's capacity, if necessary, to guarantee space for -// another n bytes. After Grow(n), at least n bytes can be written to the -// buffer without another allocation. -// If n is negative, Grow will panic. -// If the buffer can't grow it will panic with ErrTooLarge. -func (b *Buffer) Grow(n int) { - if n < 0 { - panic("bytes.Buffer.Grow: negative count") - } - m := b.grow(n) - b.buf = b.buf[0:m] -} - -// Write appends the contents of p to the buffer, growing the buffer as -// needed. The return value n is the length of p; err is always nil. If the -// buffer becomes too large, Write will panic with ErrTooLarge. -func (b *Buffer) Write(p []byte) (n int, err error) { - b.lastRead = opInvalid - m := b.grow(len(p)) - return copy(b.buf[m:], p), nil -} - -// WriteString appends the contents of s to the buffer, growing the buffer as -// needed. The return value n is the length of s; err is always nil. If the -// buffer becomes too large, WriteString will panic with ErrTooLarge. -func (b *Buffer) WriteString(s string) (n int, err error) { - b.lastRead = opInvalid - m := b.grow(len(s)) - return copy(b.buf[m:], s), nil -} - -// MinRead is the minimum slice size passed to a Read call by -// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond -// what is required to hold the contents of r, ReadFrom will not grow the -// underlying buffer. -const MinRead = 512 - -// ReadFrom reads data from r until EOF and appends it to the buffer, growing -// the buffer as needed. The return value n is the number of bytes read. Any -// error except io.EOF encountered during the read is also returned. If the -// buffer becomes too large, ReadFrom will panic with ErrTooLarge. -func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) { - b.lastRead = opInvalid - // If buffer is empty, reset to recover space. - if b.off >= len(b.buf) { - b.Truncate(0) - } - for { - if free := cap(b.buf) - len(b.buf); free < MinRead { - // not enough space at end - newBuf := b.buf - if b.off+free < MinRead { - // not enough space using beginning of buffer; - // double buffer capacity - newBuf = makeSlice(2*cap(b.buf) + MinRead) - } - copy(newBuf, b.buf[b.off:]) - b.buf = newBuf[:len(b.buf)-b.off] - b.off = 0 - } - m, e := r.Read(b.buf[len(b.buf):cap(b.buf)]) - b.buf = b.buf[0 : len(b.buf)+m] - n += int64(m) - if e == io.EOF { - break - } - if e != nil { - return n, e - } - } - return n, nil // err is EOF, so return nil explicitly -} - -// makeSlice allocates a slice of size n. If the allocation fails, it panics -// with ErrTooLarge. -func makeSlice(n int) []byte { - // If the make fails, give a known error. - defer func() { - if recover() != nil { - panic(ErrTooLarge) - } - }() - return make([]byte, n) -} - -// WriteTo writes data to w until the buffer is drained or an error occurs. -// The return value n is the number of bytes written; it always fits into an -// int, but it is int64 to match the io.WriterTo interface. Any error -// encountered during the write is also returned. -func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) { - b.lastRead = opInvalid - if b.off < len(b.buf) { - nBytes := b.Len() - m, e := w.Write(b.buf[b.off:]) - if m > nBytes { - panic("bytes.Buffer.WriteTo: invalid Write count") - } - b.off += m - n = int64(m) - if e != nil { - return n, e - } - // all bytes should have been written, by definition of - // Write method in io.Writer - if m != nBytes { - return n, io.ErrShortWrite - } - } - // Buffer is now empty; reset. - b.Truncate(0) - return -} - -// WriteByte appends the byte c to the buffer, growing the buffer as needed. -// The returned error is always nil, but is included to match bufio.Writer's -// WriteByte. If the buffer becomes too large, WriteByte will panic with -// ErrTooLarge. -func (b *Buffer) WriteByte(c byte) error { - b.lastRead = opInvalid - m := b.grow(1) - b.buf[m] = c - return nil -} - -// WriteRune appends the UTF-8 encoding of Unicode code point r to the -// buffer, returning its length and an error, which is always nil but is -// included to match bufio.Writer's WriteRune. The buffer is grown as needed; -// if it becomes too large, WriteRune will panic with ErrTooLarge. -func (b *Buffer) WriteRune(r rune) (n int, err error) { - if r < utf8.RuneSelf { - b.WriteByte(byte(r)) - return 1, nil - } - n = utf8.EncodeRune(b.runeBytes[0:], r) - b.Write(b.runeBytes[0:n]) - return n, nil -} - -// Read reads the next len(p) bytes from the buffer or until the buffer -// is drained. The return value n is the number of bytes read. If the -// buffer has no data to return, err is io.EOF (unless len(p) is zero); -// otherwise it is nil. -func (b *Buffer) Read(p []byte) (n int, err error) { - b.lastRead = opInvalid - if b.off >= len(b.buf) { - // Buffer is empty, reset to recover space. - b.Truncate(0) - if len(p) == 0 { - return - } - return 0, io.EOF - } - n = copy(p, b.buf[b.off:]) - b.off += n - if n > 0 { - b.lastRead = opRead - } - return -} - -// Next returns a slice containing the next n bytes from the buffer, -// advancing the buffer as if the bytes had been returned by Read. -// If there are fewer than n bytes in the buffer, Next returns the entire buffer. -// The slice is only valid until the next call to a read or write method. -func (b *Buffer) Next(n int) []byte { - b.lastRead = opInvalid - m := b.Len() - if n > m { - n = m - } - data := b.buf[b.off : b.off+n] - b.off += n - if n > 0 { - b.lastRead = opRead - } - return data -} - -// ReadByte reads and returns the next byte from the buffer. -// If no byte is available, it returns error io.EOF. -func (b *Buffer) ReadByte() (c byte, err error) { - b.lastRead = opInvalid - if b.off >= len(b.buf) { - // Buffer is empty, reset to recover space. - b.Truncate(0) - return 0, io.EOF - } - c = b.buf[b.off] - b.off++ - b.lastRead = opRead - return c, nil -} - -// ReadRune reads and returns the next UTF-8-encoded -// Unicode code point from the buffer. -// If no bytes are available, the error returned is io.EOF. -// If the bytes are an erroneous UTF-8 encoding, it -// consumes one byte and returns U+FFFD, 1. -func (b *Buffer) ReadRune() (r rune, size int, err error) { - b.lastRead = opInvalid - if b.off >= len(b.buf) { - // Buffer is empty, reset to recover space. - b.Truncate(0) - return 0, 0, io.EOF - } - b.lastRead = opReadRune - c := b.buf[b.off] - if c < utf8.RuneSelf { - b.off++ - return rune(c), 1, nil - } - r, n := utf8.DecodeRune(b.buf[b.off:]) - b.off += n - return r, n, nil -} - -// UnreadRune unreads the last rune returned by ReadRune. -// If the most recent read or write operation on the buffer was -// not a ReadRune, UnreadRune returns an error. (In this regard -// it is stricter than UnreadByte, which will unread the last byte -// from any read operation.) -func (b *Buffer) UnreadRune() error { - if b.lastRead != opReadRune { - return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune") - } - b.lastRead = opInvalid - if b.off > 0 { - _, n := utf8.DecodeLastRune(b.buf[0:b.off]) - b.off -= n - } - return nil -} - -// UnreadByte unreads the last byte returned by the most recent -// read operation. If write has happened since the last read, UnreadByte -// returns an error. -func (b *Buffer) UnreadByte() error { - if b.lastRead != opReadRune && b.lastRead != opRead { - return errors.New("bytes.Buffer: UnreadByte: previous operation was not a read") - } - b.lastRead = opInvalid - if b.off > 0 { - b.off-- - } - return nil -} - -// ReadBytes reads until the first occurrence of delim in the input, -// returning a slice containing the data up to and including the delimiter. -// If ReadBytes encounters an error before finding a delimiter, -// it returns the data read before the error and the error itself (often io.EOF). -// ReadBytes returns err != nil if and only if the returned data does not end in -// delim. -func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) { - slice, err := b.readSlice(delim) - // return a copy of slice. The buffer's backing array may - // be overwritten by later calls. - line = append(line, slice...) - return -} - -// readSlice is like ReadBytes but returns a reference to internal buffer data. -func (b *Buffer) readSlice(delim byte) (line []byte, err error) { - i := bytes.IndexByte(b.buf[b.off:], delim) - end := b.off + i + 1 - if i < 0 { - end = len(b.buf) - err = io.EOF - } - line = b.buf[b.off:end] - b.off = end - b.lastRead = opRead - return line, err -} - -// ReadString reads until the first occurrence of delim in the input, -// returning a string containing the data up to and including the delimiter. -// If ReadString encounters an error before finding a delimiter, -// it returns the data read before the error and the error itself (often io.EOF). -// ReadString returns err != nil if and only if the returned data does not end -// in delim. -func (b *Buffer) ReadString(delim byte) (line string, err error) { - slice, err := b.readSlice(delim) - return string(slice), err -} - -// NewBuffer creates and initializes a new Buffer using buf as its initial -// contents. It is intended to prepare a Buffer to read existing data. It -// can also be used to size the internal buffer for writing. To do that, -// buf should have the desired capacity but a length of zero. -// -// In most cases, new(Buffer) (or just declaring a Buffer variable) is -// sufficient to initialize a Buffer. -func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} } - -// NewBufferString creates and initializes a new Buffer using string s as its -// initial contents. It is intended to prepare a buffer to read an existing -// string. -// -// In most cases, new(Buffer) (or just declaring a Buffer variable) is -// sufficient to initialize a Buffer. -func NewBufferString(s string) *Buffer { - return &Buffer{buf: []byte(s)} -} diff --git a/vendor/gopkg.in/bufio.v1/bufio.go b/vendor/gopkg.in/bufio.v1/bufio.go deleted file mode 100644 index 8f5cdc084d462..0000000000000 --- a/vendor/gopkg.in/bufio.v1/bufio.go +++ /dev/null @@ -1,728 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer -// object, creating another object (Reader or Writer) that also implements -// the interface but provides buffering and some help for textual I/O. -package bufio - -import ( - "bytes" - "errors" - "io" - "unicode/utf8" -) - -const ( - defaultBufSize = 4096 -) - -var ( - ErrInvalidUnreadByte = errors.New("bufio: invalid use of UnreadByte") - ErrInvalidUnreadRune = errors.New("bufio: invalid use of UnreadRune") - ErrBufferFull = errors.New("bufio: buffer full") - ErrNegativeCount = errors.New("bufio: negative count") -) - -// Buffered input. - -// Reader implements buffering for an io.Reader object. -type Reader struct { - buf []byte - rd io.Reader - r, w int - err error - lastByte int - lastRuneSize int -} - -const minReadBufferSize = 16 -const maxConsecutiveEmptyReads = 100 - -// NewReaderSize returns a new Reader whose buffer has at least the specified -// size. If the argument io.Reader is already a Reader with large enough -// size, it returns the underlying Reader. -func NewReaderSize(rd io.Reader, size int) *Reader { - // Is it already a Reader? - b, ok := rd.(*Reader) - if ok && len(b.buf) >= size { - return b - } - if size < minReadBufferSize { - size = minReadBufferSize - } - r := new(Reader) - r.reset(make([]byte, size), rd) - return r -} - -// NewReader returns a new Reader whose buffer has the default size. -func NewReader(rd io.Reader) *Reader { - return NewReaderSize(rd, defaultBufSize) -} - -// Reset discards any buffered data, resets all state, and switches -// the buffered reader to read from r. -func (b *Reader) Reset(r io.Reader) { - b.reset(b.buf, r) -} - -func (b *Reader) reset(buf []byte, r io.Reader) { - *b = Reader{ - buf: buf, - rd: r, - lastByte: -1, - lastRuneSize: -1, - } -} - -var errNegativeRead = errors.New("bufio: reader returned negative count from Read") - -// fill reads a new chunk into the buffer. -func (b *Reader) fill() { - // Slide existing data to beginning. - if b.r > 0 { - copy(b.buf, b.buf[b.r:b.w]) - b.w -= b.r - b.r = 0 - } - - if b.w >= len(b.buf) { - panic("bufio: tried to fill full buffer") - } - - // Read new data: try a limited number of times. - for i := maxConsecutiveEmptyReads; i > 0; i-- { - n, err := b.rd.Read(b.buf[b.w:]) - if n < 0 { - panic(errNegativeRead) - } - b.w += n - if err != nil { - b.err = err - return - } - if n > 0 { - return - } - } - b.err = io.ErrNoProgress -} - -func (b *Reader) readErr() error { - err := b.err - b.err = nil - return err -} - -// Peek returns the next n bytes without advancing the reader. The bytes stop -// being valid at the next read call. If Peek returns fewer than n bytes, it -// also returns an error explaining why the read is short. The error is -// ErrBufferFull if n is larger than b's buffer size. -func (b *Reader) Peek(n int) ([]byte, error) { - if n < 0 { - return nil, ErrNegativeCount - } - if n > len(b.buf) { - return nil, ErrBufferFull - } - // 0 <= n <= len(b.buf) - for b.w-b.r < n && b.err == nil { - b.fill() // b.w-b.r < len(b.buf) => buffer is not full - } - m := b.w - b.r - if m > n { - m = n - } - var err error - if m < n { - err = b.readErr() - if err == nil { - err = ErrBufferFull - } - } - return b.buf[b.r : b.r+m], err -} - -// Read reads data into p. -// It returns the number of bytes read into p. -// It calls Read at most once on the underlying Reader, -// hence n may be less than len(p). -// At EOF, the count will be zero and err will be io.EOF. -func (b *Reader) Read(p []byte) (n int, err error) { - n = len(p) - if n == 0 { - return 0, b.readErr() - } - if b.r == b.w { - if b.err != nil { - return 0, b.readErr() - } - if len(p) >= len(b.buf) { - // Large read, empty buffer. - // Read directly into p to avoid copy. - n, b.err = b.rd.Read(p) - if n < 0 { - panic(errNegativeRead) - } - if n > 0 { - b.lastByte = int(p[n-1]) - b.lastRuneSize = -1 - } - return n, b.readErr() - } - b.fill() // buffer is empty - if b.w == b.r { - return 0, b.readErr() - } - } - - if n > b.w-b.r { - n = b.w - b.r - } - copy(p[0:n], b.buf[b.r:]) - b.r += n - b.lastByte = int(b.buf[b.r-1]) - b.lastRuneSize = -1 - return n, nil -} - -// ReadByte reads and returns a single byte. -// If no byte is available, returns an error. -func (b *Reader) ReadByte() (c byte, err error) { - b.lastRuneSize = -1 - for b.r == b.w { - if b.err != nil { - return 0, b.readErr() - } - b.fill() // buffer is empty - } - c = b.buf[b.r] - b.r++ - b.lastByte = int(c) - return c, nil -} - -// UnreadByte unreads the last byte. Only the most recently read byte can be unread. -func (b *Reader) UnreadByte() error { - if b.lastByte < 0 || b.r == 0 && b.w > 0 { - return ErrInvalidUnreadByte - } - // b.r > 0 || b.w == 0 - if b.r > 0 { - b.r-- - } else { - // b.r == 0 && b.w == 0 - b.w = 1 - } - b.buf[b.r] = byte(b.lastByte) - b.lastByte = -1 - b.lastRuneSize = -1 - return nil -} - -// ReadRune reads a single UTF-8 encoded Unicode character and returns the -// rune and its size in bytes. If the encoded rune is invalid, it consumes one byte -// and returns unicode.ReplacementChar (U+FFFD) with a size of 1. -func (b *Reader) ReadRune() (r rune, size int, err error) { - for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil && b.w-b.r < len(b.buf) { - b.fill() // b.w-b.r < len(buf) => buffer is not full - } - b.lastRuneSize = -1 - if b.r == b.w { - return 0, 0, b.readErr() - } - r, size = rune(b.buf[b.r]), 1 - if r >= 0x80 { - r, size = utf8.DecodeRune(b.buf[b.r:b.w]) - } - b.r += size - b.lastByte = int(b.buf[b.r-1]) - b.lastRuneSize = size - return r, size, nil -} - -// UnreadRune unreads the last rune. If the most recent read operation on -// the buffer was not a ReadRune, UnreadRune returns an error. (In this -// regard it is stricter than UnreadByte, which will unread the last byte -// from any read operation.) -func (b *Reader) UnreadRune() error { - if b.lastRuneSize < 0 || b.r < b.lastRuneSize { - return ErrInvalidUnreadRune - } - b.r -= b.lastRuneSize - b.lastByte = -1 - b.lastRuneSize = -1 - return nil -} - -// Buffered returns the number of bytes that can be read from the current buffer. -func (b *Reader) Buffered() int { return b.w - b.r } - -// ReadSlice reads until the first occurrence of delim in the input, -// returning a slice pointing at the bytes in the buffer. -// The bytes stop being valid at the next read. -// If ReadSlice encounters an error before finding a delimiter, -// it returns all the data in the buffer and the error itself (often io.EOF). -// ReadSlice fails with error ErrBufferFull if the buffer fills without a delim. -// Because the data returned from ReadSlice will be overwritten -// by the next I/O operation, most clients should use -// ReadBytes or ReadString instead. -// ReadSlice returns err != nil if and only if line does not end in delim. -func (b *Reader) ReadSlice(delim byte) (line []byte, err error) { - for { - // Search buffer. - if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 { - line = b.buf[b.r : b.r+i+1] - b.r += i + 1 - break - } - - // Pending error? - if b.err != nil { - line = b.buf[b.r:b.w] - b.r = b.w - err = b.readErr() - break - } - - // Buffer full? - if n := b.Buffered(); n >= len(b.buf) { - b.r = b.w - line = b.buf - err = ErrBufferFull - break - } - - b.fill() // buffer is not full - } - - // Handle last byte, if any. - if i := len(line) - 1; i >= 0 { - b.lastByte = int(line[i]) - } - - return -} - -// ReadN tries to read exactly n bytes. -// The bytes stop being valid at the next read call. -// If ReadN encounters an error before reading n bytes, -// it returns all the data in the buffer and the error itself (often io.EOF). -// ReadN fails with error ErrBufferFull if the buffer fills -// without reading N bytes. -// Because the data returned from ReadN will be overwritten -// by the next I/O operation, most clients should use -// ReadBytes or ReadString instead. -func (b *Reader) ReadN(n int) ([]byte, error) { - for b.Buffered() < n { - if b.err != nil { - buf := b.buf[b.r:b.w] - b.r = b.w - return buf, b.readErr() - } - - // Buffer is full? - if b.Buffered() >= len(b.buf) { - b.r = b.w - return b.buf, ErrBufferFull - } - - b.fill() - } - buf := b.buf[b.r : b.r+n] - b.r += n - return buf, nil -} - -// ReadLine is a low-level line-reading primitive. Most callers should use -// ReadBytes('\n') or ReadString('\n') instead or use a Scanner. -// -// ReadLine tries to return a single line, not including the end-of-line bytes. -// If the line was too long for the buffer then isPrefix is set and the -// beginning of the line is returned. The rest of the line will be returned -// from future calls. isPrefix will be false when returning the last fragment -// of the line. The returned buffer is only valid until the next call to -// ReadLine. ReadLine either returns a non-nil line or it returns an error, -// never both. -// -// The text returned from ReadLine does not include the line end ("\r\n" or "\n"). -// No indication or error is given if the input ends without a final line end. -// Calling UnreadByte after ReadLine will always unread the last byte read -// (possibly a character belonging to the line end) even if that byte is not -// part of the line returned by ReadLine. -func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) { - line, err = b.ReadSlice('\n') - if err == ErrBufferFull { - // Handle the case where "\r\n" straddles the buffer. - if len(line) > 0 && line[len(line)-1] == '\r' { - // Put the '\r' back on buf and drop it from line. - // Let the next call to ReadLine check for "\r\n". - if b.r == 0 { - // should be unreachable - panic("bufio: tried to rewind past start of buffer") - } - b.r-- - line = line[:len(line)-1] - } - return line, true, nil - } - - if len(line) == 0 { - if err != nil { - line = nil - } - return - } - err = nil - - if line[len(line)-1] == '\n' { - drop := 1 - if len(line) > 1 && line[len(line)-2] == '\r' { - drop = 2 - } - line = line[:len(line)-drop] - } - return -} - -// ReadBytes reads until the first occurrence of delim in the input, -// returning a slice containing the data up to and including the delimiter. -// If ReadBytes encounters an error before finding a delimiter, -// it returns the data read before the error and the error itself (often io.EOF). -// ReadBytes returns err != nil if and only if the returned data does not end in -// delim. -// For simple uses, a Scanner may be more convenient. -func (b *Reader) ReadBytes(delim byte) (line []byte, err error) { - // Use ReadSlice to look for array, - // accumulating full buffers. - var frag []byte - var full [][]byte - err = nil - - for { - var e error - frag, e = b.ReadSlice(delim) - if e == nil { // got final fragment - break - } - if e != ErrBufferFull { // unexpected error - err = e - break - } - - // Make a copy of the buffer. - buf := make([]byte, len(frag)) - copy(buf, frag) - full = append(full, buf) - } - - // Allocate new buffer to hold the full pieces and the fragment. - n := 0 - for i := range full { - n += len(full[i]) - } - n += len(frag) - - // Copy full pieces and fragment in. - buf := make([]byte, n) - n = 0 - for i := range full { - n += copy(buf[n:], full[i]) - } - copy(buf[n:], frag) - return buf, err -} - -// ReadString reads until the first occurrence of delim in the input, -// returning a string containing the data up to and including the delimiter. -// If ReadString encounters an error before finding a delimiter, -// it returns the data read before the error and the error itself (often io.EOF). -// ReadString returns err != nil if and only if the returned data does not end in -// delim. -// For simple uses, a Scanner may be more convenient. -func (b *Reader) ReadString(delim byte) (line string, err error) { - bytes, err := b.ReadBytes(delim) - line = string(bytes) - return line, err -} - -// WriteTo implements io.WriterTo. -func (b *Reader) WriteTo(w io.Writer) (n int64, err error) { - n, err = b.writeBuf(w) - if err != nil { - return - } - - if r, ok := b.rd.(io.WriterTo); ok { - m, err := r.WriteTo(w) - n += m - return n, err - } - - if w, ok := w.(io.ReaderFrom); ok { - m, err := w.ReadFrom(b.rd) - n += m - return n, err - } - - if b.w-b.r < len(b.buf) { - b.fill() // buffer not full - } - - for b.r < b.w { - // b.r < b.w => buffer is not empty - m, err := b.writeBuf(w) - n += m - if err != nil { - return n, err - } - b.fill() // buffer is empty - } - - if b.err == io.EOF { - b.err = nil - } - - return n, b.readErr() -} - -// writeBuf writes the Reader's buffer to the writer. -func (b *Reader) writeBuf(w io.Writer) (int64, error) { - n, err := w.Write(b.buf[b.r:b.w]) - if n < b.r-b.w { - panic(errors.New("bufio: writer did not write all data")) - } - b.r += n - return int64(n), err -} - -// buffered output - -// Writer implements buffering for an io.Writer object. -// If an error occurs writing to a Writer, no more data will be -// accepted and all subsequent writes will return the error. -// After all data has been written, the client should call the -// Flush method to guarantee all data has been forwarded to -// the underlying io.Writer. -type Writer struct { - err error - buf []byte - n int - wr io.Writer -} - -// NewWriterSize returns a new Writer whose buffer has at least the specified -// size. If the argument io.Writer is already a Writer with large enough -// size, it returns the underlying Writer. -func NewWriterSize(w io.Writer, size int) *Writer { - // Is it already a Writer? - b, ok := w.(*Writer) - if ok && len(b.buf) >= size { - return b - } - if size <= 0 { - size = defaultBufSize - } - return &Writer{ - buf: make([]byte, size), - wr: w, - } -} - -// NewWriter returns a new Writer whose buffer has the default size. -func NewWriter(w io.Writer) *Writer { - return NewWriterSize(w, defaultBufSize) -} - -// Reset discards any unflushed buffered data, clears any error, and -// resets b to write its output to w. -func (b *Writer) Reset(w io.Writer) { - b.err = nil - b.n = 0 - b.wr = w -} - -// Flush writes any buffered data to the underlying io.Writer. -func (b *Writer) Flush() error { - err := b.flush() - return err -} - -func (b *Writer) flush() error { - if b.err != nil { - return b.err - } - if b.n == 0 { - return nil - } - n, err := b.wr.Write(b.buf[0:b.n]) - if n < b.n && err == nil { - err = io.ErrShortWrite - } - if err != nil { - if n > 0 && n < b.n { - copy(b.buf[0:b.n-n], b.buf[n:b.n]) - } - b.n -= n - b.err = err - return err - } - b.n = 0 - return nil -} - -// Available returns how many bytes are unused in the buffer. -func (b *Writer) Available() int { return len(b.buf) - b.n } - -// Buffered returns the number of bytes that have been written into the current buffer. -func (b *Writer) Buffered() int { return b.n } - -// Write writes the contents of p into the buffer. -// It returns the number of bytes written. -// If nn < len(p), it also returns an error explaining -// why the write is short. -func (b *Writer) Write(p []byte) (nn int, err error) { - for len(p) > b.Available() && b.err == nil { - var n int - if b.Buffered() == 0 { - // Large write, empty buffer. - // Write directly from p to avoid copy. - n, b.err = b.wr.Write(p) - } else { - n = copy(b.buf[b.n:], p) - b.n += n - b.flush() - } - nn += n - p = p[n:] - } - if b.err != nil { - return nn, b.err - } - n := copy(b.buf[b.n:], p) - b.n += n - nn += n - return nn, nil -} - -// WriteByte writes a single byte. -func (b *Writer) WriteByte(c byte) error { - if b.err != nil { - return b.err - } - if b.Available() <= 0 && b.flush() != nil { - return b.err - } - b.buf[b.n] = c - b.n++ - return nil -} - -// WriteRune writes a single Unicode code point, returning -// the number of bytes written and any error. -func (b *Writer) WriteRune(r rune) (size int, err error) { - if r < utf8.RuneSelf { - err = b.WriteByte(byte(r)) - if err != nil { - return 0, err - } - return 1, nil - } - if b.err != nil { - return 0, b.err - } - n := b.Available() - if n < utf8.UTFMax { - if b.flush(); b.err != nil { - return 0, b.err - } - n = b.Available() - if n < utf8.UTFMax { - // Can only happen if buffer is silly small. - return b.WriteString(string(r)) - } - } - size = utf8.EncodeRune(b.buf[b.n:], r) - b.n += size - return size, nil -} - -// WriteString writes a string. -// It returns the number of bytes written. -// If the count is less than len(s), it also returns an error explaining -// why the write is short. -func (b *Writer) WriteString(s string) (int, error) { - nn := 0 - for len(s) > b.Available() && b.err == nil { - n := copy(b.buf[b.n:], s) - b.n += n - nn += n - s = s[n:] - b.flush() - } - if b.err != nil { - return nn, b.err - } - n := copy(b.buf[b.n:], s) - b.n += n - nn += n - return nn, nil -} - -// ReadFrom implements io.ReaderFrom. -func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) { - if b.Buffered() == 0 { - if w, ok := b.wr.(io.ReaderFrom); ok { - return w.ReadFrom(r) - } - } - var m int - for { - if b.Available() == 0 { - if err1 := b.flush(); err1 != nil { - return n, err1 - } - } - nr := 0 - for nr < maxConsecutiveEmptyReads { - m, err = r.Read(b.buf[b.n:]) - if m != 0 || err != nil { - break - } - nr++ - } - if nr == maxConsecutiveEmptyReads { - return n, io.ErrNoProgress - } - b.n += m - n += int64(m) - if err != nil { - break - } - } - if err == io.EOF { - // If we filled the buffer exactly, flush pre-emptively. - if b.Available() == 0 { - err = b.flush() - } else { - err = nil - } - } - return n, err -} - -// buffered input and output - -// ReadWriter stores pointers to a Reader and a Writer. -// It implements io.ReadWriter. -type ReadWriter struct { - *Reader - *Writer -} - -// NewReadWriter allocates a new ReadWriter that dispatches to r and w. -func NewReadWriter(r *Reader, w *Writer) *ReadWriter { - return &ReadWriter{r, w} -} diff --git a/vendor/gopkg.in/ini.v1/.travis.yml b/vendor/gopkg.in/ini.v1/.travis.yml index c8ea49ccc623d..17d3dc5a9fb8a 100644 --- a/vendor/gopkg.in/ini.v1/.travis.yml +++ b/vendor/gopkg.in/ini.v1/.travis.yml @@ -7,6 +7,7 @@ go: - 1.9.x - 1.10.x - 1.11.x + - 1.12.x script: - go get golang.org/x/tools/cmd/cover diff --git a/vendor/gopkg.in/ini.v1/error.go b/vendor/gopkg.in/ini.v1/error.go index 80afe7431584a..d88347c54bf62 100644 --- a/vendor/gopkg.in/ini.v1/error.go +++ b/vendor/gopkg.in/ini.v1/error.go @@ -18,10 +18,12 @@ import ( "fmt" ) +// ErrDelimiterNotFound indicates the error type of no delimiter is found which there should be one. type ErrDelimiterNotFound struct { Line string } +// IsErrDelimiterNotFound returns true if the given error is an instance of ErrDelimiterNotFound. func IsErrDelimiterNotFound(err error) bool { _, ok := err.(ErrDelimiterNotFound) return ok diff --git a/vendor/gopkg.in/ini.v1/file.go b/vendor/gopkg.in/ini.v1/file.go index 0ed0eafd02983..b38aadd1f8dd7 100644 --- a/vendor/gopkg.in/ini.v1/file.go +++ b/vendor/gopkg.in/ini.v1/file.go @@ -68,7 +68,7 @@ func Empty() *File { func (f *File) NewSection(name string) (*Section, error) { if len(name) == 0 { return nil, errors.New("error creating new section: empty section name") - } else if f.options.Insensitive && name != DEFAULT_SECTION { + } else if f.options.Insensitive && name != DefaultSection { name = strings.ToLower(name) } @@ -111,7 +111,7 @@ func (f *File) NewSections(names ...string) (err error) { // GetSection returns section by given name. func (f *File) GetSection(name string) (*Section, error) { if len(name) == 0 { - name = DEFAULT_SECTION + name = DefaultSection } if f.options.Insensitive { name = strings.ToLower(name) @@ -141,7 +141,7 @@ func (f *File) Section(name string) *Section { return sec } -// Section returns list of Section. +// Sections returns a list of Section stored in the current instance. func (f *File) Sections() []*Section { if f.BlockMode { f.lock.RLock() @@ -175,7 +175,7 @@ func (f *File) DeleteSection(name string) { } if len(name) == 0 { - name = DEFAULT_SECTION + name = DefaultSection } for i, s := range f.sectionList { @@ -306,7 +306,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { for _, kname := range sec.keyList { key := sec.Key(kname) if len(key.Comment) > 0 { - if len(indent) > 0 && sname != DEFAULT_SECTION { + if len(indent) > 0 && sname != DefaultSection { buf.WriteString(indent) } @@ -325,7 +325,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { } } - if len(indent) > 0 && sname != DEFAULT_SECTION { + if len(indent) > 0 && sname != DefaultSection { buf.WriteString(indent) } diff --git a/vendor/gopkg.in/ini.v1/ini.go b/vendor/gopkg.in/ini.v1/ini.go index f827a1ef99f1b..03cd57ff96bfe 100644 --- a/vendor/gopkg.in/ini.v1/ini.go +++ b/vendor/gopkg.in/ini.v1/ini.go @@ -28,44 +28,46 @@ import ( ) const ( - // Name for default section. You can use this constant or the string literal. + // DefaultSection is the name of default section. You can use this constant or the string literal. // In most of cases, an empty string is all you need to access the section. - DEFAULT_SECTION = "DEFAULT" + DefaultSection = "DEFAULT" + // Deprecated: Use "DefaultSection" instead. + DEFAULT_SECTION = DefaultSection // Maximum allowed depth when recursively substituing variable names. - _DEPTH_VALUES = 99 - _VERSION = "1.42.0" + depthValues = 99 + version = "1.44.0" ) // Version returns current package version literal. func Version() string { - return _VERSION + return version } var ( - // Delimiter to determine or compose a new line. - // This variable will be changed to "\r\n" automatically on Windows - // at package init time. + // LineBreak is the delimiter to determine or compose a new line. + // This variable will be changed to "\r\n" automatically on Windows at package init time. LineBreak = "\n" - // Place custom spaces when PrettyFormat and PrettyEqual are both disabled - DefaultFormatLeft = "" + // DefaultFormatLeft places custom spaces on the left when PrettyFormat and PrettyEqual are both disabled. + DefaultFormatLeft = "" + // DefaultFormatRight places custom spaces on the right when PrettyFormat and PrettyEqual are both disabled. DefaultFormatRight = "" // Variable regexp pattern: %(variable)s varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`) - // Indicate whether to align "=" sign with spaces to produce pretty output + // PrettyFormat indicates whether to align "=" sign with spaces to produce pretty output // or reduce all possible spaces for compact format. PrettyFormat = true - // Place spaces around "=" sign even when PrettyFormat is false + // PrettyEqual places spaces around "=" sign even when PrettyFormat is false. PrettyEqual = false - // Explicitly write DEFAULT section header + // DefaultHeader explicitly writes default section header. DefaultHeader = false - // Indicate whether to put a line between sections + // PrettySection indicates whether to put a line between sections. PrettySection = true ) @@ -129,6 +131,7 @@ func parseDataSource(source interface{}) (dataSource, error) { } } +// LoadOptions contains all customized options used for load data source(s). type LoadOptions struct { // Loose indicates whether the parser should ignore nonexistent files or return error. Loose bool @@ -174,6 +177,7 @@ type LoadOptions struct { PreserveSurroundedQuote bool } +// LoadSources allows caller to apply customized options for loading from data source(s). func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { sources := make([]dataSource, len(others)+1) sources[0], err = parseDataSource(source) diff --git a/vendor/gopkg.in/ini.v1/key.go b/vendor/gopkg.in/ini.v1/key.go index 0fee0dc7e407d..38860ff4bd261 100644 --- a/vendor/gopkg.in/ini.v1/key.go +++ b/vendor/gopkg.in/ini.v1/key.go @@ -77,6 +77,7 @@ func (k *Key) addNestedValue(val string) error { return nil } +// AddNestedValue adds a nested value to the key. func (k *Key) AddNestedValue(val string) error { if !k.s.f.options.AllowNestedValues { return errors.New("nested value is not allowed") @@ -126,7 +127,7 @@ func (k *Key) transformValue(val string) string { if !strings.Contains(val, "%") { return val } - for i := 0; i < _DEPTH_VALUES; i++ { + for i := 0; i < depthValues; i++ { vr := varPattern.FindString(val) if len(vr) == 0 { break @@ -186,8 +187,8 @@ func (k *Key) Float64() (float64, error) { // Int returns int type value. func (k *Key) Int() (int, error) { - v, err := strconv.ParseInt(k.String(), 0, 64) - return int(v), err + v, err := strconv.ParseInt(k.String(), 0, 64) + return int(v), err } // Int64 returns int64 type value. @@ -491,7 +492,7 @@ func (k *Key) Strings(delim string) []string { buf.WriteRune(runes[idx]) } } - idx += 1 + idx++ if idx == len(runes) { break } @@ -669,7 +670,7 @@ func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, vals := make([]int, 0, len(strs)) for _, str := range strs { valInt64, err := strconv.ParseInt(str, 0, 64) - val := int(valInt64) + val := int(valInt64) if err != nil && returnOnInvalid { return nil, err } diff --git a/vendor/gopkg.in/ini.v1/parser.go b/vendor/gopkg.in/ini.v1/parser.go index f20073d1b4cd0..7c22a25c1a5ce 100644 --- a/vendor/gopkg.in/ini.v1/parser.go +++ b/vendor/gopkg.in/ini.v1/parser.go @@ -27,25 +27,29 @@ import ( var pythonMultiline = regexp.MustCompile("^(\\s+)([^\n]+)") -type tokenType int - -const ( - _TOKEN_INVALID tokenType = iota - _TOKEN_COMMENT - _TOKEN_SECTION - _TOKEN_KEY -) +type parserOptions struct { + IgnoreContinuation bool + IgnoreInlineComment bool + AllowPythonMultilineValues bool + SpaceBeforeInlineComment bool + UnescapeValueDoubleQuotes bool + UnescapeValueCommentSymbols bool + PreserveSurroundedQuote bool +} type parser struct { buf *bufio.Reader + options parserOptions + isEOF bool count int comment *bytes.Buffer } -func newParser(r io.Reader) *parser { +func newParser(r io.Reader, opts parserOptions) *parser { return &parser{ buf: bufio.NewReader(r), + options: opts, count: 1, comment: &bytes.Buffer{}, } @@ -196,12 +200,13 @@ func hasSurroundedQuote(in string, quote byte) bool { strings.IndexByte(in[1:], quote) == len(in)-2 } -func (p *parser) readValue(in []byte, - parserBufferSize int, - ignoreContinuation, ignoreInlineComment, unescapeValueDoubleQuotes, unescapeValueCommentSymbols, allowPythonMultilines, spaceBeforeInlineComment, preserveSurroundedQuote bool) (string, error) { +func (p *parser) readValue(in []byte, bufferSize int) (string, error) { line := strings.TrimLeftFunc(string(in), unicode.IsSpace) if len(line) == 0 { + if p.options.AllowPythonMultilineValues && len(in) > 0 && in[len(in)-1] == '\n' { + return p.readPythonMultilines(line, bufferSize) + } return "", nil } @@ -210,7 +215,7 @@ func (p *parser) readValue(in []byte, valQuote = `"""` } else if line[0] == '`' { valQuote = "`" - } else if unescapeValueDoubleQuotes && line[0] == '"' { + } else if p.options.UnescapeValueDoubleQuotes && line[0] == '"' { valQuote = `"` } @@ -222,7 +227,7 @@ func (p *parser) readValue(in []byte, return p.readMultilines(line, line[startIdx:], valQuote) } - if unescapeValueDoubleQuotes && valQuote == `"` { + if p.options.UnescapeValueDoubleQuotes && valQuote == `"` { return strings.Replace(line[startIdx:pos+startIdx], `\"`, `"`, -1), nil } return line[startIdx : pos+startIdx], nil @@ -234,14 +239,14 @@ func (p *parser) readValue(in []byte, trimmedLastChar := line[len(line)-1] // Check continuation lines when desired - if !ignoreContinuation && trimmedLastChar == '\\' { + if !p.options.IgnoreContinuation && trimmedLastChar == '\\' { return p.readContinuationLines(line[:len(line)-1]) } // Check if ignore inline comment - if !ignoreInlineComment { + if !p.options.IgnoreInlineComment { var i int - if spaceBeforeInlineComment { + if p.options.SpaceBeforeInlineComment { i = strings.Index(line, " #") if i == -1 { i = strings.Index(line, " ;") @@ -260,65 +265,75 @@ func (p *parser) readValue(in []byte, // Trim single and double quotes if (hasSurroundedQuote(line, '\'') || - hasSurroundedQuote(line, '"')) && !preserveSurroundedQuote { + hasSurroundedQuote(line, '"')) && !p.options.PreserveSurroundedQuote { line = line[1 : len(line)-1] - } else if len(valQuote) == 0 && unescapeValueCommentSymbols { + } else if len(valQuote) == 0 && p.options.UnescapeValueCommentSymbols { if strings.Contains(line, `\;`) { line = strings.Replace(line, `\;`, ";", -1) } if strings.Contains(line, `\#`) { line = strings.Replace(line, `\#`, "#", -1) } - } else if allowPythonMultilines && lastChar == '\n' { - parserBufferPeekResult, _ := p.buf.Peek(parserBufferSize) - peekBuffer := bytes.NewBuffer(parserBufferPeekResult) + } else if p.options.AllowPythonMultilineValues && lastChar == '\n' { + return p.readPythonMultilines(line, bufferSize) + } - val := line + return line, nil +} - for { - peekData, peekErr := peekBuffer.ReadBytes('\n') - if peekErr != nil { - if peekErr == io.EOF { - return val, nil - } - return "", peekErr - } +func (p *parser) readPythonMultilines(line string, bufferSize int) (string, error) { + parserBufferPeekResult, _ := p.buf.Peek(bufferSize) + peekBuffer := bytes.NewBuffer(parserBufferPeekResult) - peekMatches := pythonMultiline.FindStringSubmatch(string(peekData)) - if len(peekMatches) != 3 { - return val, nil + for { + peekData, peekErr := peekBuffer.ReadBytes('\n') + if peekErr != nil { + if peekErr == io.EOF { + return line, nil } + return "", peekErr + } - // NOTE: Return if not a python-ini multi-line value. - currentIdentSize := len(peekMatches[1]) - if currentIdentSize <= 0 { - return val, nil - } + peekMatches := pythonMultiline.FindStringSubmatch(string(peekData)) + if len(peekMatches) != 3 { + return line, nil + } - // NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer. - _, err := p.readUntil('\n') - if err != nil { - return "", err - } + // NOTE: Return if not a python-ini multi-line value. + currentIdentSize := len(peekMatches[1]) + if currentIdentSize <= 0 { + return line, nil + } - val += fmt.Sprintf("\n%s", peekMatches[2]) + // NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer. + _, err := p.readUntil('\n') + if err != nil { + return "", err } - } - return line, nil + line += fmt.Sprintf("\n%s", peekMatches[2]) + } } // parse parses data through an io.Reader. func (f *File) parse(reader io.Reader) (err error) { - p := newParser(reader) + p := newParser(reader, parserOptions{ + IgnoreContinuation: f.options.IgnoreContinuation, + IgnoreInlineComment: f.options.IgnoreInlineComment, + AllowPythonMultilineValues: f.options.AllowPythonMultilineValues, + SpaceBeforeInlineComment: f.options.SpaceBeforeInlineComment, + UnescapeValueDoubleQuotes: f.options.UnescapeValueDoubleQuotes, + UnescapeValueCommentSymbols: f.options.UnescapeValueCommentSymbols, + PreserveSurroundedQuote: f.options.PreserveSurroundedQuote, + }) if err = p.BOM(); err != nil { return fmt.Errorf("BOM: %v", err) } // Ignore error because default section name is never empty string. - name := DEFAULT_SECTION + name := DefaultSection if f.options.Insensitive { - name = strings.ToLower(DEFAULT_SECTION) + name = strings.ToLower(DefaultSection) } section, _ := f.NewSection(name) @@ -426,15 +441,7 @@ func (f *File) parse(reader io.Reader) (err error) { if IsErrDelimiterNotFound(err) { switch { case f.options.AllowBooleanKeys: - kname, err := p.readValue(line, - parserBufferSize, - f.options.IgnoreContinuation, - f.options.IgnoreInlineComment, - f.options.UnescapeValueDoubleQuotes, - f.options.UnescapeValueCommentSymbols, - f.options.AllowPythonMultilineValues, - f.options.SpaceBeforeInlineComment, - f.options.PreserveSurroundedQuote) + kname, err := p.readValue(line, parserBufferSize) if err != nil { return err } @@ -461,15 +468,7 @@ func (f *File) parse(reader io.Reader) (err error) { p.count++ } - value, err := p.readValue(line[offset:], - parserBufferSize, - f.options.IgnoreContinuation, - f.options.IgnoreInlineComment, - f.options.UnescapeValueDoubleQuotes, - f.options.UnescapeValueCommentSymbols, - f.options.AllowPythonMultilineValues, - f.options.SpaceBeforeInlineComment, - f.options.PreserveSurroundedQuote) + value, err := p.readValue(line[offset:], parserBufferSize) if err != nil { return err } diff --git a/vendor/gopkg.in/ini.v1/section.go b/vendor/gopkg.in/ini.v1/section.go index bc32c620d6ede..0bd3e1301574e 100644 --- a/vendor/gopkg.in/ini.v1/section.go +++ b/vendor/gopkg.in/ini.v1/section.go @@ -106,7 +106,6 @@ func (s *Section) NewBooleanKey(name string) (*Key, error) { // GetKey returns key in section by given name. func (s *Section) GetKey(name string) (*Key, error) { - // FIXME: change to section level lock? if s.f.BlockMode { s.f.lock.RLock() } @@ -129,9 +128,8 @@ func (s *Section) GetKey(name string) (*Key, error) { continue } return sec.GetKey(name) - } else { - break } + break } return nil, fmt.Errorf("error when getting key of section '%s': key '%s' not exists", s.name, name) } @@ -144,8 +142,7 @@ func (s *Section) HasKey(name string) bool { return key != nil } -// Haskey is a backwards-compatible name for HasKey. -// TODO: delete me in v2 +// Deprecated: Use "HasKey" instead. func (s *Section) Haskey(name string) bool { return s.HasKey(name) } diff --git a/vendor/gopkg.in/ini.v1/struct.go b/vendor/gopkg.in/ini.v1/struct.go index a9dfed078ab6f..4cdcb6b41b93c 100644 --- a/vendor/gopkg.in/ini.v1/struct.go +++ b/vendor/gopkg.in/ini.v1/struct.go @@ -149,7 +149,7 @@ func wrapStrictError(err error, isStrict bool) error { // setWithProperType sets proper value to field based on its type, // but it does not return error for failing parsing, -// because we want to use default value that is already assigned to strcut. +// because we want to use default value that is already assigned to struct. func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { switch t.Kind() { case reflect.String: @@ -244,14 +244,21 @@ func (s *Section) mapTo(val reflect.Value, isStrict bool) error { continue } - isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous isStruct := tpField.Type.Kind() == reflect.Struct + isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct + isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous if isAnonymous { field.Set(reflect.New(tpField.Type.Elem())) } - if isAnonymous || isStruct { + if isAnonymous || isStruct || isStructPtr { if sec, err := s.f.GetSection(fieldName); err == nil { + // Only set the field to non-nil struct value if we have + // a section for it. Otherwise, we end up with a non-nil + // struct ptr even though there is no data. + if isStructPtr && field.IsNil() { + field.Set(reflect.New(tpField.Type.Elem())) + } if err = sec.mapTo(field, isStrict); err != nil { return fmt.Errorf("error mapping field(%s): %v", fieldName, err) } @@ -283,7 +290,7 @@ func (s *Section) MapTo(v interface{}) error { return s.mapTo(val, false) } -// MapTo maps section to given struct in strict mode, +// StrictMapTo maps section to given struct in strict mode, // which returns all possible error including value parsing error. func (s *Section) StrictMapTo(v interface{}) error { typ := reflect.TypeOf(v) @@ -303,13 +310,13 @@ func (f *File) MapTo(v interface{}) error { return f.Section("").MapTo(v) } -// MapTo maps file to given struct in strict mode, +// StrictMapTo maps file to given struct in strict mode, // which returns all possible error including value parsing error. func (f *File) StrictMapTo(v interface{}) error { return f.Section("").StrictMapTo(v) } -// MapTo maps data sources to given struct with name mapper. +// MapToWithMapper maps data sources to given struct with name mapper. func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { cfg, err := Load(source, others...) if err != nil { @@ -342,14 +349,43 @@ func StrictMapTo(v, source interface{}, others ...interface{}) error { } // reflectSliceWithProperType does the opposite thing as setSliceWithProperType. -func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) error { +func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error { slice := field.Slice(0, field.Len()) if field.Len() == 0 { return nil } + sliceOf := field.Type().Elem().Kind() + + if allowShadow { + var keyWithShadows *Key + for i := 0; i < field.Len(); i++ { + var val string + switch sliceOf { + case reflect.String: + val = slice.Index(i).String() + case reflect.Int, reflect.Int64: + val = fmt.Sprint(slice.Index(i).Int()) + case reflect.Uint, reflect.Uint64: + val = fmt.Sprint(slice.Index(i).Uint()) + case reflect.Float64: + val = fmt.Sprint(slice.Index(i).Float()) + case reflectTime: + val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339) + default: + return fmt.Errorf("unsupported type '[]%s'", sliceOf) + } + + if i == 0 { + keyWithShadows = newKey(key.s, key.name, val) + } else { + keyWithShadows.AddShadow(val) + } + } + key = keyWithShadows + return nil + } var buf bytes.Buffer - sliceOf := field.Type().Elem().Kind() for i := 0; i < field.Len(); i++ { switch sliceOf { case reflect.String: @@ -367,12 +403,12 @@ func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) err } buf.WriteString(delim) } - key.SetValue(buf.String()[:buf.Len()-1]) + key.SetValue(buf.String()[:buf.Len()-len(delim)]) return nil } // reflectWithProperType does the opposite thing as setWithProperType. -func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error { +func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error { switch t.Kind() { case reflect.String: key.SetValue(field.String()) @@ -387,7 +423,7 @@ func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim case reflectTime: key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339))) case reflect.Slice: - return reflectSliceWithProperType(key, field, delim) + return reflectSliceWithProperType(key, field, delim, allowShadow) default: return fmt.Errorf("unsupported type '%s'", t) } @@ -432,12 +468,12 @@ func (s *Section) reflectFrom(val reflect.Value) error { continue } - opts := strings.SplitN(tag, ",", 2) - if len(opts) == 2 && opts[1] == "omitempty" && isEmptyValue(field) { + rawName, omitEmpty, allowShadow := parseTagOptions(tag) + if omitEmpty && isEmptyValue(field) { continue } - fieldName := s.parseFieldName(tpField.Name, opts[0]) + fieldName := s.parseFieldName(tpField.Name, rawName) if len(fieldName) == 0 || !field.CanSet() { continue } @@ -473,7 +509,7 @@ func (s *Section) reflectFrom(val reflect.Value) error { key.Comment = tpField.Tag.Get("comment") } - if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { + if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim")), allowShadow); err != nil { return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) } @@ -500,7 +536,7 @@ func (f *File) ReflectFrom(v interface{}) error { return f.Section("").ReflectFrom(v) } -// ReflectFrom reflects data sources from given struct with name mapper. +// ReflectFromWithMapper reflects data sources from given struct with name mapper. func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error { cfg.NameMapper = mapper return cfg.ReflectFrom(v) diff --git a/vendor/gopkg.in/redis.v2/.travis.yml b/vendor/gopkg.in/redis.v2/.travis.yml deleted file mode 100644 index c3cf4b8a6e386..0000000000000 --- a/vendor/gopkg.in/redis.v2/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: go - -services: -- redis-server - -go: - - 1.1 - - 1.2 - - 1.3 - - tip - -install: - - go get gopkg.in/bufio.v1 - - go get gopkg.in/check.v1 - - mkdir -p $HOME/gopath/src/gopkg.in - - ln -s `pwd` $HOME/gopath/src/gopkg.in/redis.v2 - -before_script: - - redis-server testdata/sentinel.conf --sentinel & diff --git a/vendor/gopkg.in/redis.v2/LICENSE b/vendor/gopkg.in/redis.v2/LICENSE deleted file mode 100644 index 6855a95feb9ed..0000000000000 --- a/vendor/gopkg.in/redis.v2/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2012 The Redis Go Client Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/gopkg.in/redis.v2/Makefile b/vendor/gopkg.in/redis.v2/Makefile deleted file mode 100644 index b250d9bfa96ae..0000000000000 --- a/vendor/gopkg.in/redis.v2/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -all: - go test gopkg.in/redis.v2 -cpu=1,2,4 - go test gopkg.in/redis.v2 -short -race diff --git a/vendor/gopkg.in/redis.v2/README.md b/vendor/gopkg.in/redis.v2/README.md deleted file mode 100644 index ddf875f9a19ce..0000000000000 --- a/vendor/gopkg.in/redis.v2/README.md +++ /dev/null @@ -1,46 +0,0 @@ -Redis client for Golang [![Build Status](https://travis-ci.org/go-redis/redis.png?branch=master)](https://travis-ci.org/go-redis/redis) -======================= - -Supports: - -- Redis 2.8 commands except QUIT, MONITOR, SLOWLOG and SYNC. -- Pub/sub. -- Transactions. -- Pipelining. -- Connection pool. -- TLS connections. -- Thread safety. -- Timeouts. -- Redis Sentinel. - -API docs: http://godoc.org/gopkg.in/redis.v2. -Examples: http://godoc.org/gopkg.in/redis.v2#pkg-examples. - -Installation ------------- - -Install: - - go get gopkg.in/redis.v2 - -Look and feel -------------- - -Some corner cases: - - SORT list LIMIT 0 2 ASC - vals, err := client.Sort("list", redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result() - - ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2 - vals, err := client.ZRangeByScoreWithScores("zset", redis.ZRangeByScore{ - Min: "-inf", - Max: "+inf", - Offset: 0, - Count: 2, - }).Result() - - ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM - vals, err := client.ZInterStore("out", redis.ZStore{Weights: []int64{2, 3}}, "zset1", "zset2").Result() - - EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello" - vals, err := client.Eval("return {KEYS[1],ARGV[1]}", []string{"key"}, []string{"hello"}).Result() diff --git a/vendor/gopkg.in/redis.v2/command.go b/vendor/gopkg.in/redis.v2/command.go deleted file mode 100644 index d7c76cf92a943..0000000000000 --- a/vendor/gopkg.in/redis.v2/command.go +++ /dev/null @@ -1,597 +0,0 @@ -package redis - -import ( - "fmt" - "strconv" - "strings" - "time" - - "gopkg.in/bufio.v1" -) - -var ( - _ Cmder = (*Cmd)(nil) - _ Cmder = (*SliceCmd)(nil) - _ Cmder = (*StatusCmd)(nil) - _ Cmder = (*IntCmd)(nil) - _ Cmder = (*DurationCmd)(nil) - _ Cmder = (*BoolCmd)(nil) - _ Cmder = (*StringCmd)(nil) - _ Cmder = (*FloatCmd)(nil) - _ Cmder = (*StringSliceCmd)(nil) - _ Cmder = (*BoolSliceCmd)(nil) - _ Cmder = (*StringStringMapCmd)(nil) - _ Cmder = (*ZSliceCmd)(nil) - _ Cmder = (*ScanCmd)(nil) -) - -type Cmder interface { - args() []string - parseReply(*bufio.Reader) error - setErr(error) - - writeTimeout() *time.Duration - readTimeout() *time.Duration - - Err() error - String() string -} - -func setCmdsErr(cmds []Cmder, e error) { - for _, cmd := range cmds { - cmd.setErr(e) - } -} - -func cmdString(cmd Cmder, val interface{}) string { - s := strings.Join(cmd.args(), " ") - if err := cmd.Err(); err != nil { - return s + ": " + err.Error() - } - if val != nil { - return s + ": " + fmt.Sprint(val) - } - return s - -} - -//------------------------------------------------------------------------------ - -type baseCmd struct { - _args []string - - err error - - _writeTimeout, _readTimeout *time.Duration -} - -func newBaseCmd(args ...string) *baseCmd { - return &baseCmd{ - _args: args, - } -} - -func (cmd *baseCmd) Err() error { - if cmd.err != nil { - return cmd.err - } - return nil -} - -func (cmd *baseCmd) args() []string { - return cmd._args -} - -func (cmd *baseCmd) readTimeout() *time.Duration { - return cmd._readTimeout -} - -func (cmd *baseCmd) setReadTimeout(d time.Duration) { - cmd._readTimeout = &d -} - -func (cmd *baseCmd) writeTimeout() *time.Duration { - return cmd._writeTimeout -} - -func (cmd *baseCmd) setWriteTimeout(d time.Duration) { - cmd._writeTimeout = &d -} - -func (cmd *baseCmd) setErr(e error) { - cmd.err = e -} - -//------------------------------------------------------------------------------ - -type Cmd struct { - *baseCmd - - val interface{} -} - -func NewCmd(args ...string) *Cmd { - return &Cmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *Cmd) Val() interface{} { - return cmd.val -} - -func (cmd *Cmd) Result() (interface{}, error) { - return cmd.val, cmd.err -} - -func (cmd *Cmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *Cmd) parseReply(rd *bufio.Reader) error { - cmd.val, cmd.err = parseReply(rd, parseSlice) - return cmd.err -} - -//------------------------------------------------------------------------------ - -type SliceCmd struct { - *baseCmd - - val []interface{} -} - -func NewSliceCmd(args ...string) *SliceCmd { - return &SliceCmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *SliceCmd) Val() []interface{} { - return cmd.val -} - -func (cmd *SliceCmd) Result() ([]interface{}, error) { - return cmd.val, cmd.err -} - -func (cmd *SliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *SliceCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, parseSlice) - if err != nil { - cmd.err = err - return err - } - cmd.val = v.([]interface{}) - return nil -} - -//------------------------------------------------------------------------------ - -type StatusCmd struct { - *baseCmd - - val string -} - -func NewStatusCmd(args ...string) *StatusCmd { - return &StatusCmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *StatusCmd) Val() string { - return cmd.val -} - -func (cmd *StatusCmd) Result() (string, error) { - return cmd.val, cmd.err -} - -func (cmd *StatusCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *StatusCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, nil) - if err != nil { - cmd.err = err - return err - } - cmd.val = v.(string) - return nil -} - -//------------------------------------------------------------------------------ - -type IntCmd struct { - *baseCmd - - val int64 -} - -func NewIntCmd(args ...string) *IntCmd { - return &IntCmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *IntCmd) Val() int64 { - return cmd.val -} - -func (cmd *IntCmd) Result() (int64, error) { - return cmd.val, cmd.err -} - -func (cmd *IntCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *IntCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, nil) - if err != nil { - cmd.err = err - return err - } - cmd.val = v.(int64) - return nil -} - -//------------------------------------------------------------------------------ - -type DurationCmd struct { - *baseCmd - - val time.Duration - precision time.Duration -} - -func NewDurationCmd(precision time.Duration, args ...string) *DurationCmd { - return &DurationCmd{ - baseCmd: newBaseCmd(args...), - precision: precision, - } -} - -func (cmd *DurationCmd) Val() time.Duration { - return cmd.val -} - -func (cmd *DurationCmd) Result() (time.Duration, error) { - return cmd.val, cmd.err -} - -func (cmd *DurationCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *DurationCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, nil) - if err != nil { - cmd.err = err - return err - } - cmd.val = time.Duration(v.(int64)) * cmd.precision - return nil -} - -//------------------------------------------------------------------------------ - -type BoolCmd struct { - *baseCmd - - val bool -} - -func NewBoolCmd(args ...string) *BoolCmd { - return &BoolCmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *BoolCmd) Val() bool { - return cmd.val -} - -func (cmd *BoolCmd) Result() (bool, error) { - return cmd.val, cmd.err -} - -func (cmd *BoolCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *BoolCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, nil) - if err != nil { - cmd.err = err - return err - } - cmd.val = v.(int64) == 1 - return nil -} - -//------------------------------------------------------------------------------ - -type StringCmd struct { - *baseCmd - - val string -} - -func NewStringCmd(args ...string) *StringCmd { - return &StringCmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *StringCmd) Val() string { - return cmd.val -} - -func (cmd *StringCmd) Result() (string, error) { - return cmd.val, cmd.err -} - -func (cmd *StringCmd) Int64() (int64, error) { - if cmd.err != nil { - return 0, cmd.err - } - return strconv.ParseInt(cmd.val, 10, 64) -} - -func (cmd *StringCmd) Uint64() (uint64, error) { - if cmd.err != nil { - return 0, cmd.err - } - return strconv.ParseUint(cmd.val, 10, 64) -} - -func (cmd *StringCmd) Float64() (float64, error) { - if cmd.err != nil { - return 0, cmd.err - } - return strconv.ParseFloat(cmd.val, 64) -} - -func (cmd *StringCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *StringCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, nil) - if err != nil { - cmd.err = err - return err - } - cmd.val = v.(string) - return nil -} - -//------------------------------------------------------------------------------ - -type FloatCmd struct { - *baseCmd - - val float64 -} - -func NewFloatCmd(args ...string) *FloatCmd { - return &FloatCmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *FloatCmd) Val() float64 { - return cmd.val -} - -func (cmd *FloatCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *FloatCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, nil) - if err != nil { - cmd.err = err - return err - } - cmd.val, cmd.err = strconv.ParseFloat(v.(string), 64) - return cmd.err -} - -//------------------------------------------------------------------------------ - -type StringSliceCmd struct { - *baseCmd - - val []string -} - -func NewStringSliceCmd(args ...string) *StringSliceCmd { - return &StringSliceCmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *StringSliceCmd) Val() []string { - return cmd.val -} - -func (cmd *StringSliceCmd) Result() ([]string, error) { - return cmd.Val(), cmd.Err() -} - -func (cmd *StringSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *StringSliceCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, parseStringSlice) - if err != nil { - cmd.err = err - return err - } - cmd.val = v.([]string) - return nil -} - -//------------------------------------------------------------------------------ - -type BoolSliceCmd struct { - *baseCmd - - val []bool -} - -func NewBoolSliceCmd(args ...string) *BoolSliceCmd { - return &BoolSliceCmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *BoolSliceCmd) Val() []bool { - return cmd.val -} - -func (cmd *BoolSliceCmd) Result() ([]bool, error) { - return cmd.val, cmd.err -} - -func (cmd *BoolSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *BoolSliceCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, parseBoolSlice) - if err != nil { - cmd.err = err - return err - } - cmd.val = v.([]bool) - return nil -} - -//------------------------------------------------------------------------------ - -type StringStringMapCmd struct { - *baseCmd - - val map[string]string -} - -func NewStringStringMapCmd(args ...string) *StringStringMapCmd { - return &StringStringMapCmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *StringStringMapCmd) Val() map[string]string { - return cmd.val -} - -func (cmd *StringStringMapCmd) Result() (map[string]string, error) { - return cmd.val, cmd.err -} - -func (cmd *StringStringMapCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *StringStringMapCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, parseStringStringMap) - if err != nil { - cmd.err = err - return err - } - cmd.val = v.(map[string]string) - return nil -} - -//------------------------------------------------------------------------------ - -type ZSliceCmd struct { - *baseCmd - - val []Z -} - -func NewZSliceCmd(args ...string) *ZSliceCmd { - return &ZSliceCmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *ZSliceCmd) Val() []Z { - return cmd.val -} - -func (cmd *ZSliceCmd) Result() ([]Z, error) { - return cmd.val, cmd.err -} - -func (cmd *ZSliceCmd) String() string { - return cmdString(cmd, cmd.val) -} - -func (cmd *ZSliceCmd) parseReply(rd *bufio.Reader) error { - v, err := parseReply(rd, parseZSlice) - if err != nil { - cmd.err = err - return err - } - cmd.val = v.([]Z) - return nil -} - -//------------------------------------------------------------------------------ - -type ScanCmd struct { - *baseCmd - - cursor int64 - keys []string -} - -func NewScanCmd(args ...string) *ScanCmd { - return &ScanCmd{ - baseCmd: newBaseCmd(args...), - } -} - -func (cmd *ScanCmd) Val() (int64, []string) { - return cmd.cursor, cmd.keys -} - -func (cmd *ScanCmd) Result() (int64, []string, error) { - return cmd.cursor, cmd.keys, cmd.err -} - -func (cmd *ScanCmd) String() string { - return cmdString(cmd, cmd.keys) -} - -func (cmd *ScanCmd) parseReply(rd *bufio.Reader) error { - vi, err := parseReply(rd, parseSlice) - if err != nil { - cmd.err = err - return cmd.err - } - v := vi.([]interface{}) - - cmd.cursor, cmd.err = strconv.ParseInt(v[0].(string), 10, 64) - if cmd.err != nil { - return cmd.err - } - - keys := v[1].([]interface{}) - for _, keyi := range keys { - cmd.keys = append(cmd.keys, keyi.(string)) - } - - return nil -} diff --git a/vendor/gopkg.in/redis.v2/commands.go b/vendor/gopkg.in/redis.v2/commands.go deleted file mode 100644 index 6068bab17e125..0000000000000 --- a/vendor/gopkg.in/redis.v2/commands.go +++ /dev/null @@ -1,1246 +0,0 @@ -package redis - -import ( - "io" - "strconv" - "time" -) - -func formatFloat(f float64) string { - return strconv.FormatFloat(f, 'f', -1, 64) -} - -func readTimeout(sec int64) time.Duration { - if sec == 0 { - return 0 - } - return time.Duration(sec+1) * time.Second -} - -//------------------------------------------------------------------------------ - -func (c *Client) Auth(password string) *StatusCmd { - cmd := NewStatusCmd("AUTH", password) - c.Process(cmd) - return cmd -} - -func (c *Client) Echo(message string) *StringCmd { - cmd := NewStringCmd("ECHO", message) - c.Process(cmd) - return cmd -} - -func (c *Client) Ping() *StatusCmd { - cmd := NewStatusCmd("PING") - c.Process(cmd) - return cmd -} - -func (c *Client) Quit() *StatusCmd { - panic("not implemented") -} - -func (c *Client) Select(index int64) *StatusCmd { - cmd := NewStatusCmd("SELECT", strconv.FormatInt(index, 10)) - c.Process(cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c *Client) Del(keys ...string) *IntCmd { - args := append([]string{"DEL"}, keys...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) Dump(key string) *StringCmd { - cmd := NewStringCmd("DUMP", key) - c.Process(cmd) - return cmd -} - -func (c *Client) Exists(key string) *BoolCmd { - cmd := NewBoolCmd("EXISTS", key) - c.Process(cmd) - return cmd -} - -func (c *Client) Expire(key string, dur time.Duration) *BoolCmd { - cmd := NewBoolCmd("EXPIRE", key, strconv.FormatInt(int64(dur/time.Second), 10)) - c.Process(cmd) - return cmd -} - -func (c *Client) ExpireAt(key string, tm time.Time) *BoolCmd { - cmd := NewBoolCmd("EXPIREAT", key, strconv.FormatInt(tm.Unix(), 10)) - c.Process(cmd) - return cmd -} - -func (c *Client) Keys(pattern string) *StringSliceCmd { - cmd := NewStringSliceCmd("KEYS", pattern) - c.Process(cmd) - return cmd -} - -func (c *Client) Migrate(host, port, key string, db, timeout int64) *StatusCmd { - cmd := NewStatusCmd( - "MIGRATE", - host, - port, - key, - strconv.FormatInt(db, 10), - strconv.FormatInt(timeout, 10), - ) - cmd.setReadTimeout(readTimeout(timeout)) - c.Process(cmd) - return cmd -} - -func (c *Client) Move(key string, db int64) *BoolCmd { - cmd := NewBoolCmd("MOVE", key, strconv.FormatInt(db, 10)) - c.Process(cmd) - return cmd -} - -func (c *Client) ObjectRefCount(keys ...string) *IntCmd { - args := append([]string{"OBJECT", "REFCOUNT"}, keys...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ObjectEncoding(keys ...string) *StringCmd { - args := append([]string{"OBJECT", "ENCODING"}, keys...) - cmd := NewStringCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ObjectIdleTime(keys ...string) *DurationCmd { - args := append([]string{"OBJECT", "IDLETIME"}, keys...) - cmd := NewDurationCmd(time.Second, args...) - c.Process(cmd) - return cmd -} - -func (c *Client) Persist(key string) *BoolCmd { - cmd := NewBoolCmd("PERSIST", key) - c.Process(cmd) - return cmd -} - -func (c *Client) PExpire(key string, dur time.Duration) *BoolCmd { - cmd := NewBoolCmd("PEXPIRE", key, strconv.FormatInt(int64(dur/time.Millisecond), 10)) - c.Process(cmd) - return cmd -} - -func (c *Client) PExpireAt(key string, tm time.Time) *BoolCmd { - cmd := NewBoolCmd( - "PEXPIREAT", - key, - strconv.FormatInt(tm.UnixNano()/int64(time.Millisecond), 10), - ) - c.Process(cmd) - return cmd -} - -func (c *Client) PTTL(key string) *DurationCmd { - cmd := NewDurationCmd(time.Millisecond, "PTTL", key) - c.Process(cmd) - return cmd -} - -func (c *Client) RandomKey() *StringCmd { - cmd := NewStringCmd("RANDOMKEY") - c.Process(cmd) - return cmd -} - -func (c *Client) Rename(key, newkey string) *StatusCmd { - cmd := NewStatusCmd("RENAME", key, newkey) - c.Process(cmd) - return cmd -} - -func (c *Client) RenameNX(key, newkey string) *BoolCmd { - cmd := NewBoolCmd("RENAMENX", key, newkey) - c.Process(cmd) - return cmd -} - -func (c *Client) Restore(key string, ttl int64, value string) *StatusCmd { - cmd := NewStatusCmd( - "RESTORE", - key, - strconv.FormatInt(ttl, 10), - value, - ) - c.Process(cmd) - return cmd -} - -type Sort struct { - By string - Offset, Count float64 - Get []string - Order string - IsAlpha bool - Store string -} - -func (c *Client) Sort(key string, sort Sort) *StringSliceCmd { - args := []string{"SORT", key} - if sort.By != "" { - args = append(args, "BY", sort.By) - } - if sort.Offset != 0 || sort.Count != 0 { - args = append(args, "LIMIT", formatFloat(sort.Offset), formatFloat(sort.Count)) - } - for _, get := range sort.Get { - args = append(args, "GET", get) - } - if sort.Order != "" { - args = append(args, sort.Order) - } - if sort.IsAlpha { - args = append(args, "ALPHA") - } - if sort.Store != "" { - args = append(args, "STORE", sort.Store) - } - cmd := NewStringSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) TTL(key string) *DurationCmd { - cmd := NewDurationCmd(time.Second, "TTL", key) - c.Process(cmd) - return cmd -} - -func (c *Client) Type(key string) *StatusCmd { - cmd := NewStatusCmd("TYPE", key) - c.Process(cmd) - return cmd -} - -func (c *Client) Scan(cursor int64, match string, count int64) *ScanCmd { - args := []string{"SCAN", strconv.FormatInt(cursor, 10)} - if match != "" { - args = append(args, "MATCH", match) - } - if count > 0 { - args = append(args, "COUNT", strconv.FormatInt(count, 10)) - } - cmd := NewScanCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) SScan(key string, cursor int64, match string, count int64) *ScanCmd { - args := []string{"SSCAN", key, strconv.FormatInt(cursor, 10)} - if match != "" { - args = append(args, "MATCH", match) - } - if count > 0 { - args = append(args, "COUNT", strconv.FormatInt(count, 10)) - } - cmd := NewScanCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) HScan(key string, cursor int64, match string, count int64) *ScanCmd { - args := []string{"HSCAN", key, strconv.FormatInt(cursor, 10)} - if match != "" { - args = append(args, "MATCH", match) - } - if count > 0 { - args = append(args, "COUNT", strconv.FormatInt(count, 10)) - } - cmd := NewScanCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ZScan(key string, cursor int64, match string, count int64) *ScanCmd { - args := []string{"ZSCAN", key, strconv.FormatInt(cursor, 10)} - if match != "" { - args = append(args, "MATCH", match) - } - if count > 0 { - args = append(args, "COUNT", strconv.FormatInt(count, 10)) - } - cmd := NewScanCmd(args...) - c.Process(cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c *Client) Append(key, value string) *IntCmd { - cmd := NewIntCmd("APPEND", key, value) - c.Process(cmd) - return cmd -} - -type BitCount struct { - Start, End int64 -} - -func (c *Client) BitCount(key string, bitCount *BitCount) *IntCmd { - args := []string{"BITCOUNT", key} - if bitCount != nil { - args = append( - args, - strconv.FormatInt(bitCount.Start, 10), - strconv.FormatInt(bitCount.End, 10), - ) - } - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) bitOp(op, destKey string, keys ...string) *IntCmd { - args := []string{"BITOP", op, destKey} - args = append(args, keys...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) BitOpAnd(destKey string, keys ...string) *IntCmd { - return c.bitOp("AND", destKey, keys...) -} - -func (c *Client) BitOpOr(destKey string, keys ...string) *IntCmd { - return c.bitOp("OR", destKey, keys...) -} - -func (c *Client) BitOpXor(destKey string, keys ...string) *IntCmd { - return c.bitOp("XOR", destKey, keys...) -} - -func (c *Client) BitOpNot(destKey string, key string) *IntCmd { - return c.bitOp("NOT", destKey, key) -} - -func (c *Client) Decr(key string) *IntCmd { - cmd := NewIntCmd("DECR", key) - c.Process(cmd) - return cmd -} - -func (c *Client) DecrBy(key string, decrement int64) *IntCmd { - cmd := NewIntCmd("DECRBY", key, strconv.FormatInt(decrement, 10)) - c.Process(cmd) - return cmd -} - -func (c *Client) Get(key string) *StringCmd { - cmd := NewStringCmd("GET", key) - c.Process(cmd) - return cmd -} - -func (c *Client) GetBit(key string, offset int64) *IntCmd { - cmd := NewIntCmd("GETBIT", key, strconv.FormatInt(offset, 10)) - c.Process(cmd) - return cmd -} - -func (c *Client) GetRange(key string, start, end int64) *StringCmd { - cmd := NewStringCmd( - "GETRANGE", - key, - strconv.FormatInt(start, 10), - strconv.FormatInt(end, 10), - ) - c.Process(cmd) - return cmd -} - -func (c *Client) GetSet(key, value string) *StringCmd { - cmd := NewStringCmd("GETSET", key, value) - c.Process(cmd) - return cmd -} - -func (c *Client) Incr(key string) *IntCmd { - cmd := NewIntCmd("INCR", key) - c.Process(cmd) - return cmd -} - -func (c *Client) IncrBy(key string, value int64) *IntCmd { - cmd := NewIntCmd("INCRBY", key, strconv.FormatInt(value, 10)) - c.Process(cmd) - return cmd -} - -func (c *Client) IncrByFloat(key string, value float64) *FloatCmd { - cmd := NewFloatCmd("INCRBYFLOAT", key, formatFloat(value)) - c.Process(cmd) - return cmd -} - -func (c *Client) MGet(keys ...string) *SliceCmd { - args := append([]string{"MGET"}, keys...) - cmd := NewSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) MSet(pairs ...string) *StatusCmd { - args := append([]string{"MSET"}, pairs...) - cmd := NewStatusCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) MSetNX(pairs ...string) *BoolCmd { - args := append([]string{"MSETNX"}, pairs...) - cmd := NewBoolCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) PSetEx(key string, dur time.Duration, value string) *StatusCmd { - cmd := NewStatusCmd( - "PSETEX", - key, - strconv.FormatInt(int64(dur/time.Millisecond), 10), - value, - ) - c.Process(cmd) - return cmd -} - -func (c *Client) Set(key, value string) *StatusCmd { - cmd := NewStatusCmd("SET", key, value) - c.Process(cmd) - return cmd -} - -func (c *Client) SetBit(key string, offset int64, value int) *IntCmd { - cmd := NewIntCmd( - "SETBIT", - key, - strconv.FormatInt(offset, 10), - strconv.FormatInt(int64(value), 10), - ) - c.Process(cmd) - return cmd -} - -func (c *Client) SetEx(key string, dur time.Duration, value string) *StatusCmd { - cmd := NewStatusCmd("SETEX", key, strconv.FormatInt(int64(dur/time.Second), 10), value) - c.Process(cmd) - return cmd -} - -func (c *Client) SetNX(key, value string) *BoolCmd { - cmd := NewBoolCmd("SETNX", key, value) - c.Process(cmd) - return cmd -} - -func (c *Client) SetRange(key string, offset int64, value string) *IntCmd { - cmd := NewIntCmd("SETRANGE", key, strconv.FormatInt(offset, 10), value) - c.Process(cmd) - return cmd -} - -func (c *Client) StrLen(key string) *IntCmd { - cmd := NewIntCmd("STRLEN", key) - c.Process(cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c *Client) HDel(key string, fields ...string) *IntCmd { - args := append([]string{"HDEL", key}, fields...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) HExists(key, field string) *BoolCmd { - cmd := NewBoolCmd("HEXISTS", key, field) - c.Process(cmd) - return cmd -} - -func (c *Client) HGet(key, field string) *StringCmd { - cmd := NewStringCmd("HGET", key, field) - c.Process(cmd) - return cmd -} - -func (c *Client) HGetAll(key string) *StringSliceCmd { - cmd := NewStringSliceCmd("HGETALL", key) - c.Process(cmd) - return cmd -} - -func (c *Client) HGetAllMap(key string) *StringStringMapCmd { - cmd := NewStringStringMapCmd("HGETALL", key) - c.Process(cmd) - return cmd -} - -func (c *Client) HIncrBy(key, field string, incr int64) *IntCmd { - cmd := NewIntCmd("HINCRBY", key, field, strconv.FormatInt(incr, 10)) - c.Process(cmd) - return cmd -} - -func (c *Client) HIncrByFloat(key, field string, incr float64) *FloatCmd { - cmd := NewFloatCmd("HINCRBYFLOAT", key, field, formatFloat(incr)) - c.Process(cmd) - return cmd -} - -func (c *Client) HKeys(key string) *StringSliceCmd { - cmd := NewStringSliceCmd("HKEYS", key) - c.Process(cmd) - return cmd -} - -func (c *Client) HLen(key string) *IntCmd { - cmd := NewIntCmd("HLEN", key) - c.Process(cmd) - return cmd -} - -func (c *Client) HMGet(key string, fields ...string) *SliceCmd { - args := append([]string{"HMGET", key}, fields...) - cmd := NewSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) HMSet(key, field, value string, pairs ...string) *StatusCmd { - args := append([]string{"HMSET", key, field, value}, pairs...) - cmd := NewStatusCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) HSet(key, field, value string) *BoolCmd { - cmd := NewBoolCmd("HSET", key, field, value) - c.Process(cmd) - return cmd -} - -func (c *Client) HSetNX(key, field, value string) *BoolCmd { - cmd := NewBoolCmd("HSETNX", key, field, value) - c.Process(cmd) - return cmd -} - -func (c *Client) HVals(key string) *StringSliceCmd { - cmd := NewStringSliceCmd("HVALS", key) - c.Process(cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c *Client) BLPop(timeout int64, keys ...string) *StringSliceCmd { - args := append([]string{"BLPOP"}, keys...) - args = append(args, strconv.FormatInt(timeout, 10)) - cmd := NewStringSliceCmd(args...) - cmd.setReadTimeout(readTimeout(timeout)) - c.Process(cmd) - return cmd -} - -func (c *Client) BRPop(timeout int64, keys ...string) *StringSliceCmd { - args := append([]string{"BRPOP"}, keys...) - args = append(args, strconv.FormatInt(timeout, 10)) - cmd := NewStringSliceCmd(args...) - cmd.setReadTimeout(readTimeout(timeout)) - c.Process(cmd) - return cmd -} - -func (c *Client) BRPopLPush(source, destination string, timeout int64) *StringCmd { - cmd := NewStringCmd( - "BRPOPLPUSH", - source, - destination, - strconv.FormatInt(timeout, 10), - ) - cmd.setReadTimeout(readTimeout(timeout)) - c.Process(cmd) - return cmd -} - -func (c *Client) LIndex(key string, index int64) *StringCmd { - cmd := NewStringCmd("LINDEX", key, strconv.FormatInt(index, 10)) - c.Process(cmd) - return cmd -} - -func (c *Client) LInsert(key, op, pivot, value string) *IntCmd { - cmd := NewIntCmd("LINSERT", key, op, pivot, value) - c.Process(cmd) - return cmd -} - -func (c *Client) LLen(key string) *IntCmd { - cmd := NewIntCmd("LLEN", key) - c.Process(cmd) - return cmd -} - -func (c *Client) LPop(key string) *StringCmd { - cmd := NewStringCmd("LPOP", key) - c.Process(cmd) - return cmd -} - -func (c *Client) LPush(key string, values ...string) *IntCmd { - args := append([]string{"LPUSH", key}, values...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) LPushX(key, value string) *IntCmd { - cmd := NewIntCmd("LPUSHX", key, value) - c.Process(cmd) - return cmd -} - -func (c *Client) LRange(key string, start, stop int64) *StringSliceCmd { - cmd := NewStringSliceCmd( - "LRANGE", - key, - strconv.FormatInt(start, 10), - strconv.FormatInt(stop, 10), - ) - c.Process(cmd) - return cmd -} - -func (c *Client) LRem(key string, count int64, value string) *IntCmd { - cmd := NewIntCmd("LREM", key, strconv.FormatInt(count, 10), value) - c.Process(cmd) - return cmd -} - -func (c *Client) LSet(key string, index int64, value string) *StatusCmd { - cmd := NewStatusCmd("LSET", key, strconv.FormatInt(index, 10), value) - c.Process(cmd) - return cmd -} - -func (c *Client) LTrim(key string, start, stop int64) *StatusCmd { - cmd := NewStatusCmd( - "LTRIM", - key, - strconv.FormatInt(start, 10), - strconv.FormatInt(stop, 10), - ) - c.Process(cmd) - return cmd -} - -func (c *Client) RPop(key string) *StringCmd { - cmd := NewStringCmd("RPOP", key) - c.Process(cmd) - return cmd -} - -func (c *Client) RPopLPush(source, destination string) *StringCmd { - cmd := NewStringCmd("RPOPLPUSH", source, destination) - c.Process(cmd) - return cmd -} - -func (c *Client) RPush(key string, values ...string) *IntCmd { - args := append([]string{"RPUSH", key}, values...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) RPushX(key string, value string) *IntCmd { - cmd := NewIntCmd("RPUSHX", key, value) - c.Process(cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c *Client) SAdd(key string, members ...string) *IntCmd { - args := append([]string{"SADD", key}, members...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) SCard(key string) *IntCmd { - cmd := NewIntCmd("SCARD", key) - c.Process(cmd) - return cmd -} - -func (c *Client) SDiff(keys ...string) *StringSliceCmd { - args := append([]string{"SDIFF"}, keys...) - cmd := NewStringSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) SDiffStore(destination string, keys ...string) *IntCmd { - args := append([]string{"SDIFFSTORE", destination}, keys...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) SInter(keys ...string) *StringSliceCmd { - args := append([]string{"SINTER"}, keys...) - cmd := NewStringSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) SInterStore(destination string, keys ...string) *IntCmd { - args := append([]string{"SINTERSTORE", destination}, keys...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) SIsMember(key, member string) *BoolCmd { - cmd := NewBoolCmd("SISMEMBER", key, member) - c.Process(cmd) - return cmd -} - -func (c *Client) SMembers(key string) *StringSliceCmd { - cmd := NewStringSliceCmd("SMEMBERS", key) - c.Process(cmd) - return cmd -} - -func (c *Client) SMove(source, destination, member string) *BoolCmd { - cmd := NewBoolCmd("SMOVE", source, destination, member) - c.Process(cmd) - return cmd -} - -func (c *Client) SPop(key string) *StringCmd { - cmd := NewStringCmd("SPOP", key) - c.Process(cmd) - return cmd -} - -func (c *Client) SRandMember(key string) *StringCmd { - cmd := NewStringCmd("SRANDMEMBER", key) - c.Process(cmd) - return cmd -} - -func (c *Client) SRem(key string, members ...string) *IntCmd { - args := append([]string{"SREM", key}, members...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) SUnion(keys ...string) *StringSliceCmd { - args := append([]string{"SUNION"}, keys...) - cmd := NewStringSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) SUnionStore(destination string, keys ...string) *IntCmd { - args := append([]string{"SUNIONSTORE", destination}, keys...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -type Z struct { - Score float64 - Member string -} - -type ZStore struct { - Weights []int64 - Aggregate string -} - -func (c *Client) ZAdd(key string, members ...Z) *IntCmd { - args := []string{"ZADD", key} - for _, m := range members { - args = append(args, formatFloat(m.Score), m.Member) - } - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ZCard(key string) *IntCmd { - cmd := NewIntCmd("ZCARD", key) - c.Process(cmd) - return cmd -} - -func (c *Client) ZCount(key, min, max string) *IntCmd { - cmd := NewIntCmd("ZCOUNT", key, min, max) - c.Process(cmd) - return cmd -} - -func (c *Client) ZIncrBy(key string, increment float64, member string) *FloatCmd { - cmd := NewFloatCmd("ZINCRBY", key, formatFloat(increment), member) - c.Process(cmd) - return cmd -} - -func (c *Client) ZInterStore( - destination string, - store ZStore, - keys ...string, -) *IntCmd { - args := []string{"ZINTERSTORE", destination, strconv.FormatInt(int64(len(keys)), 10)} - args = append(args, keys...) - if len(store.Weights) > 0 { - args = append(args, "WEIGHTS") - for _, weight := range store.Weights { - args = append(args, strconv.FormatInt(weight, 10)) - } - } - if store.Aggregate != "" { - args = append(args, "AGGREGATE", store.Aggregate) - } - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) zRange(key string, start, stop int64, withScores bool) *StringSliceCmd { - args := []string{ - "ZRANGE", - key, - strconv.FormatInt(start, 10), - strconv.FormatInt(stop, 10), - } - if withScores { - args = append(args, "WITHSCORES") - } - cmd := NewStringSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ZRange(key string, start, stop int64) *StringSliceCmd { - return c.zRange(key, start, stop, false) -} - -func (c *Client) ZRangeWithScores(key string, start, stop int64) *ZSliceCmd { - args := []string{ - "ZRANGE", - key, - strconv.FormatInt(start, 10), - strconv.FormatInt(stop, 10), - "WITHSCORES", - } - cmd := NewZSliceCmd(args...) - c.Process(cmd) - return cmd -} - -type ZRangeByScore struct { - Min, Max string - - Offset, Count int64 -} - -func (c *Client) zRangeByScore(key string, opt ZRangeByScore, withScores bool) *StringSliceCmd { - args := []string{"ZRANGEBYSCORE", key, opt.Min, opt.Max} - if withScores { - args = append(args, "WITHSCORES") - } - if opt.Offset != 0 || opt.Count != 0 { - args = append( - args, - "LIMIT", - strconv.FormatInt(opt.Offset, 10), - strconv.FormatInt(opt.Count, 10), - ) - } - cmd := NewStringSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ZRangeByScore(key string, opt ZRangeByScore) *StringSliceCmd { - return c.zRangeByScore(key, opt, false) -} - -func (c *Client) ZRangeByScoreWithScores(key string, opt ZRangeByScore) *ZSliceCmd { - args := []string{"ZRANGEBYSCORE", key, opt.Min, opt.Max, "WITHSCORES"} - if opt.Offset != 0 || opt.Count != 0 { - args = append( - args, - "LIMIT", - strconv.FormatInt(opt.Offset, 10), - strconv.FormatInt(opt.Count, 10), - ) - } - cmd := NewZSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ZRank(key, member string) *IntCmd { - cmd := NewIntCmd("ZRANK", key, member) - c.Process(cmd) - return cmd -} - -func (c *Client) ZRem(key string, members ...string) *IntCmd { - args := append([]string{"ZREM", key}, members...) - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ZRemRangeByRank(key string, start, stop int64) *IntCmd { - cmd := NewIntCmd( - "ZREMRANGEBYRANK", - key, - strconv.FormatInt(start, 10), - strconv.FormatInt(stop, 10), - ) - c.Process(cmd) - return cmd -} - -func (c *Client) ZRemRangeByScore(key, min, max string) *IntCmd { - cmd := NewIntCmd("ZREMRANGEBYSCORE", key, min, max) - c.Process(cmd) - return cmd -} - -func (c *Client) zRevRange(key, start, stop string, withScores bool) *StringSliceCmd { - args := []string{"ZREVRANGE", key, start, stop} - if withScores { - args = append(args, "WITHSCORES") - } - cmd := NewStringSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ZRevRange(key, start, stop string) *StringSliceCmd { - return c.zRevRange(key, start, stop, false) -} - -func (c *Client) ZRevRangeWithScores(key, start, stop string) *ZSliceCmd { - args := []string{"ZREVRANGE", key, start, stop, "WITHSCORES"} - cmd := NewZSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) zRevRangeByScore(key string, opt ZRangeByScore, withScores bool) *StringSliceCmd { - args := []string{"ZREVRANGEBYSCORE", key, opt.Max, opt.Min} - if withScores { - args = append(args, "WITHSCORES") - } - if opt.Offset != 0 || opt.Count != 0 { - args = append( - args, - "LIMIT", - strconv.FormatInt(opt.Offset, 10), - strconv.FormatInt(opt.Count, 10), - ) - } - cmd := NewStringSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ZRevRangeByScore(key string, opt ZRangeByScore) *StringSliceCmd { - return c.zRevRangeByScore(key, opt, false) -} - -func (c *Client) ZRevRangeByScoreWithScores(key string, opt ZRangeByScore) *ZSliceCmd { - args := []string{"ZREVRANGEBYSCORE", key, opt.Max, opt.Min, "WITHSCORES"} - if opt.Offset != 0 || opt.Count != 0 { - args = append( - args, - "LIMIT", - strconv.FormatInt(opt.Offset, 10), - strconv.FormatInt(opt.Count, 10), - ) - } - cmd := NewZSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ZRevRank(key, member string) *IntCmd { - cmd := NewIntCmd("ZREVRANK", key, member) - c.Process(cmd) - return cmd -} - -func (c *Client) ZScore(key, member string) *FloatCmd { - cmd := NewFloatCmd("ZSCORE", key, member) - c.Process(cmd) - return cmd -} - -func (c *Client) ZUnionStore( - destination string, - store ZStore, - keys ...string, -) *IntCmd { - args := []string{"ZUNIONSTORE", destination, strconv.FormatInt(int64(len(keys)), 10)} - args = append(args, keys...) - if len(store.Weights) > 0 { - args = append(args, "WEIGHTS") - for _, weight := range store.Weights { - args = append(args, strconv.FormatInt(weight, 10)) - } - } - if store.Aggregate != "" { - args = append(args, "AGGREGATE", store.Aggregate) - } - cmd := NewIntCmd(args...) - c.Process(cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c *Client) BgRewriteAOF() *StatusCmd { - cmd := NewStatusCmd("BGREWRITEAOF") - c.Process(cmd) - return cmd -} - -func (c *Client) BgSave() *StatusCmd { - cmd := NewStatusCmd("BGSAVE") - c.Process(cmd) - return cmd -} - -func (c *Client) ClientKill(ipPort string) *StatusCmd { - cmd := NewStatusCmd("CLIENT", "KILL", ipPort) - c.Process(cmd) - return cmd -} - -func (c *Client) ClientList() *StringCmd { - cmd := NewStringCmd("CLIENT", "LIST") - c.Process(cmd) - return cmd -} - -func (c *Client) ConfigGet(parameter string) *SliceCmd { - cmd := NewSliceCmd("CONFIG", "GET", parameter) - c.Process(cmd) - return cmd -} - -func (c *Client) ConfigResetStat() *StatusCmd { - cmd := NewStatusCmd("CONFIG", "RESETSTAT") - c.Process(cmd) - return cmd -} - -func (c *Client) ConfigSet(parameter, value string) *StatusCmd { - cmd := NewStatusCmd("CONFIG", "SET", parameter, value) - c.Process(cmd) - return cmd -} - -func (c *Client) DbSize() *IntCmd { - cmd := NewIntCmd("DBSIZE") - c.Process(cmd) - return cmd -} - -func (c *Client) FlushAll() *StatusCmd { - cmd := NewStatusCmd("FLUSHALL") - c.Process(cmd) - return cmd -} - -func (c *Client) FlushDb() *StatusCmd { - cmd := NewStatusCmd("FLUSHDB") - c.Process(cmd) - return cmd -} - -func (c *Client) Info() *StringCmd { - cmd := NewStringCmd("INFO") - c.Process(cmd) - return cmd -} - -func (c *Client) LastSave() *IntCmd { - cmd := NewIntCmd("LASTSAVE") - c.Process(cmd) - return cmd -} - -func (c *Client) Save() *StatusCmd { - cmd := NewStatusCmd("SAVE") - c.Process(cmd) - return cmd -} - -func (c *Client) shutdown(modifier string) *StatusCmd { - var args []string - if modifier == "" { - args = []string{"SHUTDOWN"} - } else { - args = []string{"SHUTDOWN", modifier} - } - cmd := NewStatusCmd(args...) - c.Process(cmd) - if err := cmd.Err(); err != nil { - if err == io.EOF { - // Server quit as expected. - cmd.err = nil - } - } else { - // Server did not quit. String reply contains the reason. - cmd.err = errorf(cmd.val) - cmd.val = "" - } - return cmd -} - -func (c *Client) Shutdown() *StatusCmd { - return c.shutdown("") -} - -func (c *Client) ShutdownSave() *StatusCmd { - return c.shutdown("SAVE") -} - -func (c *Client) ShutdownNoSave() *StatusCmd { - return c.shutdown("NOSAVE") -} - -func (c *Client) SlaveOf(host, port string) *StatusCmd { - cmd := NewStatusCmd("SLAVEOF", host, port) - c.Process(cmd) - return cmd -} - -func (c *Client) SlowLog() { - panic("not implemented") -} - -func (c *Client) Sync() { - panic("not implemented") -} - -func (c *Client) Time() *StringSliceCmd { - cmd := NewStringSliceCmd("TIME") - c.Process(cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c *Client) Eval(script string, keys []string, args []string) *Cmd { - cmdArgs := []string{"EVAL", script, strconv.FormatInt(int64(len(keys)), 10)} - cmdArgs = append(cmdArgs, keys...) - cmdArgs = append(cmdArgs, args...) - cmd := NewCmd(cmdArgs...) - c.Process(cmd) - return cmd -} - -func (c *Client) EvalSha(sha1 string, keys []string, args []string) *Cmd { - cmdArgs := []string{"EVALSHA", sha1, strconv.FormatInt(int64(len(keys)), 10)} - cmdArgs = append(cmdArgs, keys...) - cmdArgs = append(cmdArgs, args...) - cmd := NewCmd(cmdArgs...) - c.Process(cmd) - return cmd -} - -func (c *Client) ScriptExists(scripts ...string) *BoolSliceCmd { - args := append([]string{"SCRIPT", "EXISTS"}, scripts...) - cmd := NewBoolSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) ScriptFlush() *StatusCmd { - cmd := NewStatusCmd("SCRIPT", "FLUSH") - c.Process(cmd) - return cmd -} - -func (c *Client) ScriptKill() *StatusCmd { - cmd := NewStatusCmd("SCRIPT", "KILL") - c.Process(cmd) - return cmd -} - -func (c *Client) ScriptLoad(script string) *StringCmd { - cmd := NewStringCmd("SCRIPT", "LOAD", script) - c.Process(cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c *Client) DebugObject(key string) *StringCmd { - cmd := NewStringCmd("DEBUG", "OBJECT", key) - c.Process(cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c *Client) PubSubChannels(pattern string) *StringSliceCmd { - args := []string{"PUBSUB", "CHANNELS"} - if pattern != "*" { - args = append(args, pattern) - } - cmd := NewStringSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) PubSubNumSub(channels ...string) *SliceCmd { - args := []string{"PUBSUB", "NUMSUB"} - args = append(args, channels...) - cmd := NewSliceCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Client) PubSubNumPat() *IntCmd { - cmd := NewIntCmd("PUBSUB", "NUMPAT") - c.Process(cmd) - return cmd -} diff --git a/vendor/gopkg.in/redis.v2/doc.go b/vendor/gopkg.in/redis.v2/doc.go deleted file mode 100644 index 55262533a63dc..0000000000000 --- a/vendor/gopkg.in/redis.v2/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -/* -Package redis implements a Redis client. -*/ -package redis diff --git a/vendor/gopkg.in/redis.v2/error.go b/vendor/gopkg.in/redis.v2/error.go deleted file mode 100644 index 667fffdc6829b..0000000000000 --- a/vendor/gopkg.in/redis.v2/error.go +++ /dev/null @@ -1,23 +0,0 @@ -package redis - -import ( - "fmt" -) - -// Redis nil reply. -var Nil = errorf("redis: nil") - -// Redis transaction failed. -var TxFailedErr = errorf("redis: transaction failed") - -type redisError struct { - s string -} - -func errorf(s string, args ...interface{}) redisError { - return redisError{s: fmt.Sprintf(s, args...)} -} - -func (err redisError) Error() string { - return err.s -} diff --git a/vendor/gopkg.in/redis.v2/multi.go b/vendor/gopkg.in/redis.v2/multi.go deleted file mode 100644 index bff38dfaaa441..0000000000000 --- a/vendor/gopkg.in/redis.v2/multi.go +++ /dev/null @@ -1,138 +0,0 @@ -package redis - -import ( - "errors" - "fmt" -) - -var errDiscard = errors.New("redis: Discard can be used only inside Exec") - -// Not thread-safe. -type Multi struct { - *Client -} - -func (c *Client) Multi() *Multi { - return &Multi{ - Client: &Client{ - baseClient: &baseClient{ - opt: c.opt, - connPool: newSingleConnPool(c.connPool, true), - }, - }, - } -} - -func (c *Multi) Close() error { - if err := c.Unwatch().Err(); err != nil { - return err - } - return c.Client.Close() -} - -func (c *Multi) Watch(keys ...string) *StatusCmd { - args := append([]string{"WATCH"}, keys...) - cmd := NewStatusCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Multi) Unwatch(keys ...string) *StatusCmd { - args := append([]string{"UNWATCH"}, keys...) - cmd := NewStatusCmd(args...) - c.Process(cmd) - return cmd -} - -func (c *Multi) Discard() error { - if c.cmds == nil { - return errDiscard - } - c.cmds = c.cmds[:1] - return nil -} - -// Exec always returns list of commands. If transaction fails -// TxFailedErr is returned. Otherwise Exec returns error of the first -// failed command or nil. -func (c *Multi) Exec(f func() error) ([]Cmder, error) { - c.cmds = []Cmder{NewStatusCmd("MULTI")} - if err := f(); err != nil { - return nil, err - } - c.cmds = append(c.cmds, NewSliceCmd("EXEC")) - - cmds := c.cmds - c.cmds = nil - - if len(cmds) == 2 { - return []Cmder{}, nil - } - - cn, err := c.conn() - if err != nil { - setCmdsErr(cmds[1:len(cmds)-1], err) - return cmds[1 : len(cmds)-1], err - } - - err = c.execCmds(cn, cmds) - if err != nil { - c.freeConn(cn, err) - return cmds[1 : len(cmds)-1], err - } - - c.putConn(cn) - return cmds[1 : len(cmds)-1], nil -} - -func (c *Multi) execCmds(cn *conn, cmds []Cmder) error { - err := c.writeCmd(cn, cmds...) - if err != nil { - setCmdsErr(cmds[1:len(cmds)-1], err) - return err - } - - statusCmd := NewStatusCmd() - - // Omit last command (EXEC). - cmdsLen := len(cmds) - 1 - - // Parse queued replies. - for i := 0; i < cmdsLen; i++ { - if err := statusCmd.parseReply(cn.rd); err != nil { - setCmdsErr(cmds[1:len(cmds)-1], err) - return err - } - } - - // Parse number of replies. - line, err := readLine(cn.rd) - if err != nil { - setCmdsErr(cmds[1:len(cmds)-1], err) - return err - } - if line[0] != '*' { - err := fmt.Errorf("redis: expected '*', but got line %q", line) - setCmdsErr(cmds[1:len(cmds)-1], err) - return err - } - if len(line) == 3 && line[1] == '-' && line[2] == '1' { - setCmdsErr(cmds[1:len(cmds)-1], TxFailedErr) - return TxFailedErr - } - - var firstCmdErr error - - // Parse replies. - // Loop starts from 1 to omit MULTI cmd. - for i := 1; i < cmdsLen; i++ { - cmd := cmds[i] - if err := cmd.parseReply(cn.rd); err != nil { - if firstCmdErr == nil { - firstCmdErr = err - } - } - } - - return firstCmdErr -} diff --git a/vendor/gopkg.in/redis.v2/parser.go b/vendor/gopkg.in/redis.v2/parser.go deleted file mode 100644 index b4c380c764459..0000000000000 --- a/vendor/gopkg.in/redis.v2/parser.go +++ /dev/null @@ -1,262 +0,0 @@ -package redis - -import ( - "errors" - "fmt" - "strconv" - - "gopkg.in/bufio.v1" -) - -type multiBulkParser func(rd *bufio.Reader, n int64) (interface{}, error) - -var ( - errReaderTooSmall = errors.New("redis: reader is too small") -) - -//------------------------------------------------------------------------------ - -func appendArgs(buf []byte, args []string) []byte { - buf = append(buf, '*') - buf = strconv.AppendUint(buf, uint64(len(args)), 10) - buf = append(buf, '\r', '\n') - for _, arg := range args { - buf = append(buf, '$') - buf = strconv.AppendUint(buf, uint64(len(arg)), 10) - buf = append(buf, '\r', '\n') - buf = append(buf, arg...) - buf = append(buf, '\r', '\n') - } - return buf -} - -//------------------------------------------------------------------------------ - -func readLine(rd *bufio.Reader) ([]byte, error) { - line, isPrefix, err := rd.ReadLine() - if err != nil { - return line, err - } - if isPrefix { - return line, errReaderTooSmall - } - return line, nil -} - -func readN(rd *bufio.Reader, n int) ([]byte, error) { - b, err := rd.ReadN(n) - if err == bufio.ErrBufferFull { - tmp := make([]byte, n) - r := copy(tmp, b) - b = tmp - - for { - nn, err := rd.Read(b[r:]) - r += nn - if r >= n { - // Ignore error if we read enough. - break - } - if err != nil { - return nil, err - } - } - } else if err != nil { - return nil, err - } - return b, nil -} - -//------------------------------------------------------------------------------ - -func parseReq(rd *bufio.Reader) ([]string, error) { - line, err := readLine(rd) - if err != nil { - return nil, err - } - - if line[0] != '*' { - return []string{string(line)}, nil - } - numReplies, err := strconv.ParseInt(string(line[1:]), 10, 64) - if err != nil { - return nil, err - } - - args := make([]string, 0, numReplies) - for i := int64(0); i < numReplies; i++ { - line, err = readLine(rd) - if err != nil { - return nil, err - } - if line[0] != '$' { - return nil, fmt.Errorf("redis: expected '$', but got %q", line) - } - - argLen, err := strconv.ParseInt(string(line[1:]), 10, 32) - if err != nil { - return nil, err - } - - arg, err := readN(rd, int(argLen)+2) - if err != nil { - return nil, err - } - args = append(args, string(arg[:argLen])) - } - return args, nil -} - -//------------------------------------------------------------------------------ - -func parseReply(rd *bufio.Reader, p multiBulkParser) (interface{}, error) { - line, err := readLine(rd) - if err != nil { - return nil, err - } - - switch line[0] { - case '-': - return nil, errorf(string(line[1:])) - case '+': - return string(line[1:]), nil - case ':': - v, err := strconv.ParseInt(string(line[1:]), 10, 64) - if err != nil { - return nil, err - } - return v, nil - case '$': - if len(line) == 3 && line[1] == '-' && line[2] == '1' { - return nil, Nil - } - - replyLen, err := strconv.Atoi(string(line[1:])) - if err != nil { - return nil, err - } - - b, err := readN(rd, replyLen+2) - if err != nil { - return nil, err - } - return string(b[:replyLen]), nil - case '*': - if len(line) == 3 && line[1] == '-' && line[2] == '1' { - return nil, Nil - } - - repliesNum, err := strconv.ParseInt(string(line[1:]), 10, 64) - if err != nil { - return nil, err - } - - return p(rd, repliesNum) - } - return nil, fmt.Errorf("redis: can't parse %q", line) -} - -func parseSlice(rd *bufio.Reader, n int64) (interface{}, error) { - vals := make([]interface{}, 0, n) - for i := int64(0); i < n; i++ { - v, err := parseReply(rd, parseSlice) - if err == Nil { - vals = append(vals, nil) - } else if err != nil { - return nil, err - } else { - vals = append(vals, v) - } - } - return vals, nil -} - -func parseStringSlice(rd *bufio.Reader, n int64) (interface{}, error) { - vals := make([]string, 0, n) - for i := int64(0); i < n; i++ { - viface, err := parseReply(rd, nil) - if err != nil { - return nil, err - } - v, ok := viface.(string) - if !ok { - return nil, fmt.Errorf("got %T, expected string", viface) - } - vals = append(vals, v) - } - return vals, nil -} - -func parseBoolSlice(rd *bufio.Reader, n int64) (interface{}, error) { - vals := make([]bool, 0, n) - for i := int64(0); i < n; i++ { - viface, err := parseReply(rd, nil) - if err != nil { - return nil, err - } - v, ok := viface.(int64) - if !ok { - return nil, fmt.Errorf("got %T, expected int64", viface) - } - vals = append(vals, v == 1) - } - return vals, nil -} - -func parseStringStringMap(rd *bufio.Reader, n int64) (interface{}, error) { - m := make(map[string]string, n/2) - for i := int64(0); i < n; i += 2 { - keyiface, err := parseReply(rd, nil) - if err != nil { - return nil, err - } - key, ok := keyiface.(string) - if !ok { - return nil, fmt.Errorf("got %T, expected string", keyiface) - } - - valueiface, err := parseReply(rd, nil) - if err != nil { - return nil, err - } - value, ok := valueiface.(string) - if !ok { - return nil, fmt.Errorf("got %T, expected string", valueiface) - } - - m[key] = value - } - return m, nil -} - -func parseZSlice(rd *bufio.Reader, n int64) (interface{}, error) { - zz := make([]Z, n/2) - for i := int64(0); i < n; i += 2 { - z := &zz[i/2] - - memberiface, err := parseReply(rd, nil) - if err != nil { - return nil, err - } - member, ok := memberiface.(string) - if !ok { - return nil, fmt.Errorf("got %T, expected string", memberiface) - } - z.Member = member - - scoreiface, err := parseReply(rd, nil) - if err != nil { - return nil, err - } - scorestr, ok := scoreiface.(string) - if !ok { - return nil, fmt.Errorf("got %T, expected string", scoreiface) - } - score, err := strconv.ParseFloat(scorestr, 64) - if err != nil { - return nil, err - } - z.Score = score - } - return zz, nil -} diff --git a/vendor/gopkg.in/redis.v2/pipeline.go b/vendor/gopkg.in/redis.v2/pipeline.go deleted file mode 100644 index 540d6c51d9bcb..0000000000000 --- a/vendor/gopkg.in/redis.v2/pipeline.go +++ /dev/null @@ -1,91 +0,0 @@ -package redis - -// Not thread-safe. -type Pipeline struct { - *Client - - closed bool -} - -func (c *Client) Pipeline() *Pipeline { - return &Pipeline{ - Client: &Client{ - baseClient: &baseClient{ - opt: c.opt, - connPool: c.connPool, - - cmds: make([]Cmder, 0), - }, - }, - } -} - -func (c *Client) Pipelined(f func(*Pipeline) error) ([]Cmder, error) { - pc := c.Pipeline() - if err := f(pc); err != nil { - return nil, err - } - cmds, err := pc.Exec() - pc.Close() - return cmds, err -} - -func (c *Pipeline) Close() error { - c.closed = true - return nil -} - -func (c *Pipeline) Discard() error { - if c.closed { - return errClosed - } - c.cmds = c.cmds[:0] - return nil -} - -// Exec always returns list of commands and error of the first failed -// command if any. -func (c *Pipeline) Exec() ([]Cmder, error) { - if c.closed { - return nil, errClosed - } - - cmds := c.cmds - c.cmds = make([]Cmder, 0) - - if len(cmds) == 0 { - return []Cmder{}, nil - } - - cn, err := c.conn() - if err != nil { - setCmdsErr(cmds, err) - return cmds, err - } - - if err := c.execCmds(cn, cmds); err != nil { - c.freeConn(cn, err) - return cmds, err - } - - c.putConn(cn) - return cmds, nil -} - -func (c *Pipeline) execCmds(cn *conn, cmds []Cmder) error { - if err := c.writeCmd(cn, cmds...); err != nil { - setCmdsErr(cmds, err) - return err - } - - var firstCmdErr error - for _, cmd := range cmds { - if err := cmd.parseReply(cn.rd); err != nil { - if firstCmdErr == nil { - firstCmdErr = err - } - } - } - - return firstCmdErr -} diff --git a/vendor/gopkg.in/redis.v2/pool.go b/vendor/gopkg.in/redis.v2/pool.go deleted file mode 100644 index bca4d1963351a..0000000000000 --- a/vendor/gopkg.in/redis.v2/pool.go +++ /dev/null @@ -1,405 +0,0 @@ -package redis - -import ( - "container/list" - "errors" - "log" - "net" - "sync" - "time" - - "gopkg.in/bufio.v1" -) - -var ( - errClosed = errors.New("redis: client is closed") - errRateLimited = errors.New("redis: you open connections too fast") -) - -var ( - zeroTime = time.Time{} -) - -type pool interface { - Get() (*conn, bool, error) - Put(*conn) error - Remove(*conn) error - Len() int - Size() int - Close() error - Filter(func(*conn) bool) -} - -//------------------------------------------------------------------------------ - -type conn struct { - netcn net.Conn - rd *bufio.Reader - buf []byte - - inUse bool - usedAt time.Time - - readTimeout time.Duration - writeTimeout time.Duration - - elem *list.Element -} - -func newConnFunc(dial func() (net.Conn, error)) func() (*conn, error) { - return func() (*conn, error) { - netcn, err := dial() - if err != nil { - return nil, err - } - cn := &conn{ - netcn: netcn, - buf: make([]byte, 0, 64), - } - cn.rd = bufio.NewReader(cn) - return cn, nil - } -} - -func (cn *conn) Read(b []byte) (int, error) { - if cn.readTimeout != 0 { - cn.netcn.SetReadDeadline(time.Now().Add(cn.readTimeout)) - } else { - cn.netcn.SetReadDeadline(zeroTime) - } - return cn.netcn.Read(b) -} - -func (cn *conn) Write(b []byte) (int, error) { - if cn.writeTimeout != 0 { - cn.netcn.SetWriteDeadline(time.Now().Add(cn.writeTimeout)) - } else { - cn.netcn.SetWriteDeadline(zeroTime) - } - return cn.netcn.Write(b) -} - -func (cn *conn) RemoteAddr() net.Addr { - return cn.netcn.RemoteAddr() -} - -func (cn *conn) Close() error { - return cn.netcn.Close() -} - -//------------------------------------------------------------------------------ - -type connPool struct { - dial func() (*conn, error) - rl *rateLimiter - - opt *options - - cond *sync.Cond - conns *list.List - - idleNum int - closed bool -} - -func newConnPool(dial func() (*conn, error), opt *options) *connPool { - return &connPool{ - dial: dial, - rl: newRateLimiter(time.Second, 2*opt.PoolSize), - - opt: opt, - - cond: sync.NewCond(&sync.Mutex{}), - conns: list.New(), - } -} - -func (p *connPool) new() (*conn, error) { - if !p.rl.Check() { - return nil, errRateLimited - } - return p.dial() -} - -func (p *connPool) Get() (*conn, bool, error) { - p.cond.L.Lock() - - if p.closed { - p.cond.L.Unlock() - return nil, false, errClosed - } - - if p.opt.IdleTimeout > 0 { - for el := p.conns.Front(); el != nil; el = el.Next() { - cn := el.Value.(*conn) - if cn.inUse { - break - } - if time.Since(cn.usedAt) > p.opt.IdleTimeout { - if err := p.remove(cn); err != nil { - log.Printf("remove failed: %s", err) - } - } - } - } - - for p.conns.Len() >= p.opt.PoolSize && p.idleNum == 0 { - p.cond.Wait() - } - - if p.idleNum > 0 { - elem := p.conns.Front() - cn := elem.Value.(*conn) - if cn.inUse { - panic("pool: precondition failed") - } - cn.inUse = true - p.conns.MoveToBack(elem) - p.idleNum-- - - p.cond.L.Unlock() - return cn, false, nil - } - - if p.conns.Len() < p.opt.PoolSize { - cn, err := p.new() - if err != nil { - p.cond.L.Unlock() - return nil, false, err - } - - cn.inUse = true - cn.elem = p.conns.PushBack(cn) - - p.cond.L.Unlock() - return cn, true, nil - } - - panic("not reached") -} - -func (p *connPool) Put(cn *conn) error { - if cn.rd.Buffered() != 0 { - b, _ := cn.rd.ReadN(cn.rd.Buffered()) - log.Printf("redis: connection has unread data: %q", b) - return p.Remove(cn) - } - - if p.opt.IdleTimeout > 0 { - cn.usedAt = time.Now() - } - - p.cond.L.Lock() - if p.closed { - p.cond.L.Unlock() - return errClosed - } - cn.inUse = false - p.conns.MoveToFront(cn.elem) - p.idleNum++ - p.cond.Signal() - p.cond.L.Unlock() - - return nil -} - -func (p *connPool) Remove(cn *conn) error { - p.cond.L.Lock() - if p.closed { - // Noop, connection is already closed. - p.cond.L.Unlock() - return nil - } - err := p.remove(cn) - p.cond.Signal() - p.cond.L.Unlock() - return err -} - -func (p *connPool) remove(cn *conn) error { - p.conns.Remove(cn.elem) - cn.elem = nil - if !cn.inUse { - p.idleNum-- - } - return cn.Close() -} - -// Len returns number of idle connections. -func (p *connPool) Len() int { - defer p.cond.L.Unlock() - p.cond.L.Lock() - return p.idleNum -} - -// Size returns number of connections in the pool. -func (p *connPool) Size() int { - defer p.cond.L.Unlock() - p.cond.L.Lock() - return p.conns.Len() -} - -func (p *connPool) Filter(f func(*conn) bool) { - p.cond.L.Lock() - for el, next := p.conns.Front(), p.conns.Front(); el != nil; el = next { - next = el.Next() - cn := el.Value.(*conn) - if !f(cn) { - p.remove(cn) - } - } - p.cond.L.Unlock() -} - -func (p *connPool) Close() error { - defer p.cond.L.Unlock() - p.cond.L.Lock() - if p.closed { - return nil - } - p.closed = true - p.rl.Close() - var retErr error - for { - e := p.conns.Front() - if e == nil { - break - } - if err := p.remove(e.Value.(*conn)); err != nil { - log.Printf("cn.Close failed: %s", err) - retErr = err - } - } - return retErr -} - -//------------------------------------------------------------------------------ - -type singleConnPool struct { - pool pool - - cnMtx sync.Mutex - cn *conn - - reusable bool - - closed bool -} - -func newSingleConnPool(pool pool, reusable bool) *singleConnPool { - return &singleConnPool{ - pool: pool, - reusable: reusable, - } -} - -func (p *singleConnPool) SetConn(cn *conn) { - p.cnMtx.Lock() - p.cn = cn - p.cnMtx.Unlock() -} - -func (p *singleConnPool) Get() (*conn, bool, error) { - defer p.cnMtx.Unlock() - p.cnMtx.Lock() - - if p.closed { - return nil, false, errClosed - } - if p.cn != nil { - return p.cn, false, nil - } - - cn, isNew, err := p.pool.Get() - if err != nil { - return nil, false, err - } - p.cn = cn - - return p.cn, isNew, nil -} - -func (p *singleConnPool) Put(cn *conn) error { - defer p.cnMtx.Unlock() - p.cnMtx.Lock() - if p.cn != cn { - panic("p.cn != cn") - } - if p.closed { - return errClosed - } - return nil -} - -func (p *singleConnPool) put() error { - err := p.pool.Put(p.cn) - p.cn = nil - return err -} - -func (p *singleConnPool) Remove(cn *conn) error { - defer p.cnMtx.Unlock() - p.cnMtx.Lock() - if p.cn == nil { - panic("p.cn == nil") - } - if p.cn != cn { - panic("p.cn != cn") - } - if p.closed { - return errClosed - } - return p.remove() -} - -func (p *singleConnPool) remove() error { - err := p.pool.Remove(p.cn) - p.cn = nil - return err -} - -func (p *singleConnPool) Len() int { - defer p.cnMtx.Unlock() - p.cnMtx.Lock() - if p.cn == nil { - return 0 - } - return 1 -} - -func (p *singleConnPool) Size() int { - defer p.cnMtx.Unlock() - p.cnMtx.Lock() - if p.cn == nil { - return 0 - } - return 1 -} - -func (p *singleConnPool) Filter(f func(*conn) bool) { - p.cnMtx.Lock() - if p.cn != nil { - if !f(p.cn) { - p.remove() - } - } - p.cnMtx.Unlock() -} - -func (p *singleConnPool) Close() error { - defer p.cnMtx.Unlock() - p.cnMtx.Lock() - if p.closed { - return nil - } - p.closed = true - var err error - if p.cn != nil { - if p.reusable { - err = p.put() - } else { - err = p.remove() - } - } - return err -} diff --git a/vendor/gopkg.in/redis.v2/pubsub.go b/vendor/gopkg.in/redis.v2/pubsub.go deleted file mode 100644 index 6ac130bac4582..0000000000000 --- a/vendor/gopkg.in/redis.v2/pubsub.go +++ /dev/null @@ -1,134 +0,0 @@ -package redis - -import ( - "fmt" - "time" -) - -// Not thread-safe. -type PubSub struct { - *baseClient -} - -func (c *Client) PubSub() *PubSub { - return &PubSub{ - baseClient: &baseClient{ - opt: c.opt, - connPool: newSingleConnPool(c.connPool, false), - }, - } -} - -func (c *Client) Publish(channel, message string) *IntCmd { - req := NewIntCmd("PUBLISH", channel, message) - c.Process(req) - return req -} - -type Message struct { - Channel string - Payload string -} - -func (m *Message) String() string { - return fmt.Sprintf("Message<%s: %s>", m.Channel, m.Payload) -} - -type PMessage struct { - Channel string - Pattern string - Payload string -} - -func (m *PMessage) String() string { - return fmt.Sprintf("PMessage<%s: %s>", m.Channel, m.Payload) -} - -type Subscription struct { - Kind string - Channel string - Count int -} - -func (m *Subscription) String() string { - return fmt.Sprintf("%s: %s", m.Kind, m.Channel) -} - -func (c *PubSub) Receive() (interface{}, error) { - return c.ReceiveTimeout(0) -} - -func (c *PubSub) ReceiveTimeout(timeout time.Duration) (interface{}, error) { - cn, err := c.conn() - if err != nil { - return nil, err - } - cn.readTimeout = timeout - - cmd := NewSliceCmd() - if err := cmd.parseReply(cn.rd); err != nil { - return nil, err - } - - reply := cmd.Val() - - msgName := reply[0].(string) - switch msgName { - case "subscribe", "unsubscribe", "psubscribe", "punsubscribe": - return &Subscription{ - Kind: msgName, - Channel: reply[1].(string), - Count: int(reply[2].(int64)), - }, nil - case "message": - return &Message{ - Channel: reply[1].(string), - Payload: reply[2].(string), - }, nil - case "pmessage": - return &PMessage{ - Pattern: reply[1].(string), - Channel: reply[2].(string), - Payload: reply[3].(string), - }, nil - } - return nil, fmt.Errorf("redis: unsupported message name: %q", msgName) -} - -func (c *PubSub) subscribe(cmd string, channels ...string) error { - cn, err := c.conn() - if err != nil { - return err - } - - args := append([]string{cmd}, channels...) - req := NewSliceCmd(args...) - return c.writeCmd(cn, req) -} - -func (c *PubSub) Subscribe(channels ...string) error { - return c.subscribe("SUBSCRIBE", channels...) -} - -func (c *PubSub) PSubscribe(patterns ...string) error { - return c.subscribe("PSUBSCRIBE", patterns...) -} - -func (c *PubSub) unsubscribe(cmd string, channels ...string) error { - cn, err := c.conn() - if err != nil { - return err - } - - args := append([]string{cmd}, channels...) - req := NewSliceCmd(args...) - return c.writeCmd(cn, req) -} - -func (c *PubSub) Unsubscribe(channels ...string) error { - return c.unsubscribe("UNSUBSCRIBE", channels...) -} - -func (c *PubSub) PUnsubscribe(patterns ...string) error { - return c.unsubscribe("PUNSUBSCRIBE", patterns...) -} diff --git a/vendor/gopkg.in/redis.v2/rate_limit.go b/vendor/gopkg.in/redis.v2/rate_limit.go deleted file mode 100644 index 20d85127077ae..0000000000000 --- a/vendor/gopkg.in/redis.v2/rate_limit.go +++ /dev/null @@ -1,53 +0,0 @@ -package redis - -import ( - "sync/atomic" - "time" -) - -type rateLimiter struct { - v int64 - - _closed int64 -} - -func newRateLimiter(limit time.Duration, bucketSize int) *rateLimiter { - rl := &rateLimiter{ - v: int64(bucketSize), - } - go rl.loop(limit, int64(bucketSize)) - return rl -} - -func (rl *rateLimiter) loop(limit time.Duration, bucketSize int64) { - for { - if rl.closed() { - break - } - if v := atomic.LoadInt64(&rl.v); v < bucketSize { - atomic.AddInt64(&rl.v, 1) - } - time.Sleep(limit) - } -} - -func (rl *rateLimiter) Check() bool { - for { - if v := atomic.LoadInt64(&rl.v); v > 0 { - if atomic.CompareAndSwapInt64(&rl.v, v, v-1) { - return true - } - } else { - return false - } - } -} - -func (rl *rateLimiter) Close() error { - atomic.StoreInt64(&rl._closed, 1) - return nil -} - -func (rl *rateLimiter) closed() bool { - return atomic.LoadInt64(&rl._closed) == 1 -} diff --git a/vendor/gopkg.in/redis.v2/redis.go b/vendor/gopkg.in/redis.v2/redis.go deleted file mode 100644 index 0d15dc8f8541c..0000000000000 --- a/vendor/gopkg.in/redis.v2/redis.go +++ /dev/null @@ -1,231 +0,0 @@ -package redis - -import ( - "log" - "net" - "time" -) - -type baseClient struct { - connPool pool - opt *options - cmds []Cmder -} - -func (c *baseClient) writeCmd(cn *conn, cmds ...Cmder) error { - buf := cn.buf[:0] - for _, cmd := range cmds { - buf = appendArgs(buf, cmd.args()) - } - - _, err := cn.Write(buf) - return err -} - -func (c *baseClient) conn() (*conn, error) { - cn, isNew, err := c.connPool.Get() - if err != nil { - return nil, err - } - - if isNew { - if err := c.initConn(cn); err != nil { - c.removeConn(cn) - return nil, err - } - } - - return cn, nil -} - -func (c *baseClient) initConn(cn *conn) error { - if c.opt.Password == "" && c.opt.DB == 0 { - return nil - } - - pool := newSingleConnPool(c.connPool, false) - pool.SetConn(cn) - - // Client is not closed because we want to reuse underlying connection. - client := &Client{ - baseClient: &baseClient{ - opt: c.opt, - connPool: pool, - }, - } - - if c.opt.Password != "" { - if err := client.Auth(c.opt.Password).Err(); err != nil { - return err - } - } - - if c.opt.DB > 0 { - if err := client.Select(c.opt.DB).Err(); err != nil { - return err - } - } - - return nil -} - -func (c *baseClient) freeConn(cn *conn, ei error) error { - if cn.rd.Buffered() > 0 { - return c.connPool.Remove(cn) - } - if _, ok := ei.(redisError); ok { - return c.connPool.Put(cn) - } - return c.connPool.Remove(cn) -} - -func (c *baseClient) removeConn(cn *conn) { - if err := c.connPool.Remove(cn); err != nil { - log.Printf("pool.Remove failed: %s", err) - } -} - -func (c *baseClient) putConn(cn *conn) { - if err := c.connPool.Put(cn); err != nil { - log.Printf("pool.Put failed: %s", err) - } -} - -func (c *baseClient) Process(cmd Cmder) { - if c.cmds == nil { - c.run(cmd) - } else { - c.cmds = append(c.cmds, cmd) - } -} - -func (c *baseClient) run(cmd Cmder) { - cn, err := c.conn() - if err != nil { - cmd.setErr(err) - return - } - - if timeout := cmd.writeTimeout(); timeout != nil { - cn.writeTimeout = *timeout - } else { - cn.writeTimeout = c.opt.WriteTimeout - } - - if timeout := cmd.readTimeout(); timeout != nil { - cn.readTimeout = *timeout - } else { - cn.readTimeout = c.opt.ReadTimeout - } - - if err := c.writeCmd(cn, cmd); err != nil { - c.freeConn(cn, err) - cmd.setErr(err) - return - } - - if err := cmd.parseReply(cn.rd); err != nil { - c.freeConn(cn, err) - return - } - - c.putConn(cn) -} - -// Close closes the client, releasing any open resources. -func (c *baseClient) Close() error { - return c.connPool.Close() -} - -//------------------------------------------------------------------------------ - -type options struct { - Password string - DB int64 - - DialTimeout time.Duration - ReadTimeout time.Duration - WriteTimeout time.Duration - - PoolSize int - IdleTimeout time.Duration -} - -type Options struct { - Network string - Addr string - - // Dialer creates new network connection and has priority over - // Network and Addr options. - Dialer func() (net.Conn, error) - - Password string - DB int64 - - DialTimeout time.Duration - ReadTimeout time.Duration - WriteTimeout time.Duration - - PoolSize int - IdleTimeout time.Duration -} - -func (opt *Options) getPoolSize() int { - if opt.PoolSize == 0 { - return 10 - } - return opt.PoolSize -} - -func (opt *Options) getDialTimeout() time.Duration { - if opt.DialTimeout == 0 { - return 5 * time.Second - } - return opt.DialTimeout -} - -func (opt *Options) options() *options { - return &options{ - DB: opt.DB, - Password: opt.Password, - - DialTimeout: opt.getDialTimeout(), - ReadTimeout: opt.ReadTimeout, - WriteTimeout: opt.WriteTimeout, - - PoolSize: opt.getPoolSize(), - IdleTimeout: opt.IdleTimeout, - } -} - -type Client struct { - *baseClient -} - -func NewClient(clOpt *Options) *Client { - opt := clOpt.options() - dialer := clOpt.Dialer - if dialer == nil { - dialer = func() (net.Conn, error) { - return net.DialTimeout(clOpt.Network, clOpt.Addr, opt.DialTimeout) - } - } - return &Client{ - baseClient: &baseClient{ - opt: opt, - connPool: newConnPool(newConnFunc(dialer), opt), - }, - } -} - -// Deprecated. Use NewClient instead. -func NewTCPClient(opt *Options) *Client { - opt.Network = "tcp" - return NewClient(opt) -} - -// Deprecated. Use NewClient instead. -func NewUnixClient(opt *Options) *Client { - opt.Network = "unix" - return NewClient(opt) -} diff --git a/vendor/gopkg.in/redis.v2/script.go b/vendor/gopkg.in/redis.v2/script.go deleted file mode 100644 index 96c35f5149e2a..0000000000000 --- a/vendor/gopkg.in/redis.v2/script.go +++ /dev/null @@ -1,52 +0,0 @@ -package redis - -import ( - "crypto/sha1" - "encoding/hex" - "io" - "strings" -) - -type scripter interface { - Eval(script string, keys []string, args []string) *Cmd - EvalSha(sha1 string, keys []string, args []string) *Cmd - ScriptExists(scripts ...string) *BoolSliceCmd - ScriptLoad(script string) *StringCmd -} - -type Script struct { - src, hash string -} - -func NewScript(src string) *Script { - h := sha1.New() - io.WriteString(h, src) - return &Script{ - src: src, - hash: hex.EncodeToString(h.Sum(nil)), - } -} - -func (s *Script) Load(c scripter) *StringCmd { - return c.ScriptLoad(s.src) -} - -func (s *Script) Exists(c scripter) *BoolSliceCmd { - return c.ScriptExists(s.src) -} - -func (s *Script) Eval(c scripter, keys []string, args []string) *Cmd { - return c.Eval(s.src, keys, args) -} - -func (s *Script) EvalSha(c scripter, keys []string, args []string) *Cmd { - return c.EvalSha(s.hash, keys, args) -} - -func (s *Script) Run(c *Client, keys []string, args []string) *Cmd { - r := s.EvalSha(c, keys, args) - if err := r.Err(); err != nil && strings.HasPrefix(err.Error(), "NOSCRIPT ") { - return s.Eval(c, keys, args) - } - return r -} diff --git a/vendor/gopkg.in/redis.v2/sentinel.go b/vendor/gopkg.in/redis.v2/sentinel.go deleted file mode 100644 index d3ffeca9a5999..0000000000000 --- a/vendor/gopkg.in/redis.v2/sentinel.go +++ /dev/null @@ -1,291 +0,0 @@ -package redis - -import ( - "errors" - "log" - "net" - "strings" - "sync" - "time" -) - -//------------------------------------------------------------------------------ - -type FailoverOptions struct { - MasterName string - SentinelAddrs []string - - Password string - DB int64 - - PoolSize int - - DialTimeout time.Duration - ReadTimeout time.Duration - WriteTimeout time.Duration - IdleTimeout time.Duration -} - -func (opt *FailoverOptions) getPoolSize() int { - if opt.PoolSize == 0 { - return 10 - } - return opt.PoolSize -} - -func (opt *FailoverOptions) getDialTimeout() time.Duration { - if opt.DialTimeout == 0 { - return 5 * time.Second - } - return opt.DialTimeout -} - -func (opt *FailoverOptions) options() *options { - return &options{ - DB: opt.DB, - Password: opt.Password, - - DialTimeout: opt.getDialTimeout(), - ReadTimeout: opt.ReadTimeout, - WriteTimeout: opt.WriteTimeout, - - PoolSize: opt.getPoolSize(), - IdleTimeout: opt.IdleTimeout, - } -} - -func NewFailoverClient(failoverOpt *FailoverOptions) *Client { - opt := failoverOpt.options() - failover := &sentinelFailover{ - masterName: failoverOpt.MasterName, - sentinelAddrs: failoverOpt.SentinelAddrs, - - opt: opt, - } - return &Client{ - baseClient: &baseClient{ - opt: opt, - connPool: failover.Pool(), - }, - } -} - -//------------------------------------------------------------------------------ - -type sentinelClient struct { - *baseClient -} - -func newSentinel(clOpt *Options) *sentinelClient { - opt := clOpt.options() - opt.Password = "" - opt.DB = 0 - dialer := func() (net.Conn, error) { - return net.DialTimeout("tcp", clOpt.Addr, opt.DialTimeout) - } - return &sentinelClient{ - baseClient: &baseClient{ - opt: opt, - connPool: newConnPool(newConnFunc(dialer), opt), - }, - } -} - -func (c *sentinelClient) PubSub() *PubSub { - return &PubSub{ - baseClient: &baseClient{ - opt: c.opt, - connPool: newSingleConnPool(c.connPool, false), - }, - } -} - -func (c *sentinelClient) GetMasterAddrByName(name string) *StringSliceCmd { - cmd := NewStringSliceCmd("SENTINEL", "get-master-addr-by-name", name) - c.Process(cmd) - return cmd -} - -func (c *sentinelClient) Sentinels(name string) *SliceCmd { - cmd := NewSliceCmd("SENTINEL", "sentinels", name) - c.Process(cmd) - return cmd -} - -type sentinelFailover struct { - masterName string - sentinelAddrs []string - - opt *options - - pool pool - poolOnce sync.Once - - lock sync.RWMutex - _sentinel *sentinelClient -} - -func (d *sentinelFailover) dial() (net.Conn, error) { - addr, err := d.MasterAddr() - if err != nil { - return nil, err - } - return net.DialTimeout("tcp", addr, d.opt.DialTimeout) -} - -func (d *sentinelFailover) Pool() pool { - d.poolOnce.Do(func() { - d.pool = newConnPool(newConnFunc(d.dial), d.opt) - }) - return d.pool -} - -func (d *sentinelFailover) MasterAddr() (string, error) { - defer d.lock.Unlock() - d.lock.Lock() - - // Try last working sentinel. - if d._sentinel != nil { - addr, err := d._sentinel.GetMasterAddrByName(d.masterName).Result() - if err != nil { - log.Printf("redis-sentinel: GetMasterAddrByName %q failed: %s", d.masterName, err) - d.resetSentinel() - } else { - addr := net.JoinHostPort(addr[0], addr[1]) - log.Printf("redis-sentinel: %q addr is %s", d.masterName, addr) - return addr, nil - } - } - - for i, sentinelAddr := range d.sentinelAddrs { - sentinel := newSentinel(&Options{ - Addr: sentinelAddr, - - DB: d.opt.DB, - Password: d.opt.Password, - - DialTimeout: d.opt.DialTimeout, - ReadTimeout: d.opt.ReadTimeout, - WriteTimeout: d.opt.WriteTimeout, - - PoolSize: d.opt.PoolSize, - IdleTimeout: d.opt.IdleTimeout, - }) - masterAddr, err := sentinel.GetMasterAddrByName(d.masterName).Result() - if err != nil { - log.Printf("redis-sentinel: GetMasterAddrByName %q failed: %s", d.masterName, err) - sentinel.Close() - continue - } - - // Push working sentinel to the top. - d.sentinelAddrs[0], d.sentinelAddrs[i] = d.sentinelAddrs[i], d.sentinelAddrs[0] - - d.setSentinel(sentinel) - addr := net.JoinHostPort(masterAddr[0], masterAddr[1]) - log.Printf("redis-sentinel: %q addr is %s", d.masterName, addr) - return addr, nil - } - - return "", errors.New("redis: all sentinels are unreachable") -} - -func (d *sentinelFailover) setSentinel(sentinel *sentinelClient) { - d.discoverSentinels(sentinel) - d._sentinel = sentinel - go d.listen() -} - -func (d *sentinelFailover) discoverSentinels(sentinel *sentinelClient) { - sentinels, err := sentinel.Sentinels(d.masterName).Result() - if err != nil { - log.Printf("redis-sentinel: Sentinels %q failed: %s", d.masterName, err) - return - } - for _, sentinel := range sentinels { - vals := sentinel.([]interface{}) - for i := 0; i < len(vals); i += 2 { - key := vals[i].(string) - if key == "name" { - sentinelAddr := vals[i+1].(string) - if !contains(d.sentinelAddrs, sentinelAddr) { - log.Printf( - "redis-sentinel: discovered new %q sentinel: %s", - d.masterName, sentinelAddr, - ) - d.sentinelAddrs = append(d.sentinelAddrs, sentinelAddr) - } - } - } - } -} - -func (d *sentinelFailover) listen() { - var pubsub *PubSub - for { - if pubsub == nil { - pubsub = d._sentinel.PubSub() - if err := pubsub.Subscribe("+switch-master"); err != nil { - log.Printf("redis-sentinel: Subscribe failed: %s", err) - d.lock.Lock() - d.resetSentinel() - d.lock.Unlock() - return - } - } - - msgIface, err := pubsub.Receive() - if err != nil { - log.Printf("redis-sentinel: Receive failed: %s", err) - pubsub.Close() - return - } - - switch msg := msgIface.(type) { - case *Message: - switch msg.Channel { - case "+switch-master": - parts := strings.Split(msg.Payload, " ") - if parts[0] != d.masterName { - log.Printf("redis-sentinel: ignore new %s addr", parts[0]) - continue - } - addr := net.JoinHostPort(parts[3], parts[4]) - log.Printf( - "redis-sentinel: new %q addr is %s", - d.masterName, addr, - ) - d.pool.Filter(func(cn *conn) bool { - if cn.RemoteAddr().String() != addr { - log.Printf( - "redis-sentinel: closing connection to old master %s", - cn.RemoteAddr(), - ) - return false - } - return true - }) - default: - log.Printf("redis-sentinel: unsupported message: %s", msg) - } - case *Subscription: - // Ignore. - default: - log.Printf("redis-sentinel: unsupported message: %s", msgIface) - } - } -} - -func (d *sentinelFailover) resetSentinel() { - d._sentinel.Close() - d._sentinel = nil -} - -func contains(slice []string, str string) bool { - for _, s := range slice { - if s == str { - return true - } - } - return false -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 26907b01c3de7..d1ae18c6d3cea 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,5 +1,17 @@ # cloud.google.com/go v0.37.4 cloud.google.com/go/civil +# gitea.com/macaron/cache v0.0.0-20190801013118-abcd497fea65 +gitea.com/macaron/cache +gitea.com/macaron/cache/memcache +gitea.com/macaron/cache/redis +# gitea.com/macaron/session v0.0.0-20190801013118-80603dfc0b9d +gitea.com/macaron/session +gitea.com/macaron/session/couchbase +gitea.com/macaron/session/memcache +gitea.com/macaron/session/mysql +gitea.com/macaron/session/nodb +gitea.com/macaron/session/postgres +gitea.com/macaron/session/redis # github.com/BurntSushi/toml v0.3.1 github.com/BurntSushi/toml # github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34 @@ -70,14 +82,14 @@ github.com/blevesearch/segment github.com/boombuler/barcode github.com/boombuler/barcode/qr github.com/boombuler/barcode/utils -# github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a +# github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 github.com/bradfitz/gomemcache/memcache # github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f github.com/chaseadamsio/goorgeous -# github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c +# github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d github.com/couchbase/gomemcached github.com/couchbase/gomemcached/client -# github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a +# github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b github.com/couchbase/goutils/logging github.com/couchbase/goutils/scramsha # github.com/couchbase/vellum v0.0.0-20190111184608-e91b68ff3efe @@ -85,7 +97,7 @@ github.com/couchbase/vellum github.com/couchbase/vellum/levenshtein2 github.com/couchbase/vellum/regexp github.com/couchbase/vellum/utf8 -# github.com/couchbaselabs/go-couchbase v0.0.0-20190117181324-d904413d884d +# github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7 github.com/couchbaselabs/go-couchbase # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew @@ -95,7 +107,7 @@ github.com/denisenkom/go-mssqldb/internal/cp github.com/denisenkom/go-mssqldb/internal/querytext # github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go -# github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 +# github.com/edsrzf/mmap-go v1.0.0 github.com/edsrzf/mmap-go # github.com/emirpasic/gods v1.12.0 github.com/emirpasic/gods/trees/binaryheap @@ -125,8 +137,6 @@ github.com/glycerine/go-unsnap-stream github.com/go-macaron/binding # github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 github.com/go-macaron/cache -github.com/go-macaron/cache/memcache -github.com/go-macaron/cache/redis # github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df github.com/go-macaron/captcha # github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 @@ -139,12 +149,6 @@ github.com/go-macaron/i18n github.com/go-macaron/inject # github.com/go-macaron/session v0.0.0-20190131233854-0a0a789bf193 github.com/go-macaron/session -github.com/go-macaron/session/couchbase -github.com/go-macaron/session/memcache -github.com/go-macaron/session/mysql -github.com/go-macaron/session/nodb -github.com/go-macaron/session/postgres -github.com/go-macaron/session/redis # github.com/go-macaron/toolbox v0.0.0-20180818072302-a77f45a7ce90 github.com/go-macaron/toolbox # github.com/go-redis/redis v6.15.2+incompatible @@ -213,7 +217,7 @@ github.com/klauspost/crc32 # github.com/lafriks/xormstore v1.1.0 github.com/lafriks/xormstore github.com/lafriks/xormstore/util -# github.com/lib/pq v1.1.0 +# github.com/lib/pq v1.2.0 github.com/lib/pq github.com/lib/pq/oid github.com/lib/pq/scram @@ -243,7 +247,7 @@ github.com/markbates/goth/providers/openidConnect github.com/markbates/goth/providers/twitter # github.com/mattn/go-isatty v0.0.7 github.com/mattn/go-isatty -# github.com/mattn/go-sqlite3 v1.10.0 +# github.com/mattn/go-sqlite3 v1.11.0 github.com/mattn/go-sqlite3 # github.com/matttproud/golang_protobuf_extensions v1.0.1 github.com/matttproud/golang_protobuf_extensions/pbutil @@ -310,7 +314,7 @@ github.com/steveyen/gtreap # github.com/stretchr/testify v1.3.0 github.com/stretchr/testify/assert github.com/stretchr/testify/require -# github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66 +# github.com/syndtr/goleveldb v1.0.0 github.com/syndtr/goleveldb/leveldb github.com/syndtr/goleveldb/leveldb/cache github.com/syndtr/goleveldb/leveldb/comparer @@ -399,7 +403,7 @@ golang.org/x/text/internal/language/compact golang.org/x/text/internal/utf8internal golang.org/x/text/runes golang.org/x/text/internal/tag -# google.golang.org/appengine v1.4.0 +# google.golang.org/appengine v1.6.1 google.golang.org/appengine/cloudsql google.golang.org/appengine/urlfetch google.golang.org/appengine/internal @@ -412,20 +416,16 @@ google.golang.org/appengine/internal/remote_api gopkg.in/alexcesaro/quotedprintable.v3 # gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 gopkg.in/asn1-ber.v1 -# gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e -gopkg.in/bufio.v1 # gopkg.in/editorconfig/editorconfig-core-go.v1 v1.2.0 gopkg.in/editorconfig/editorconfig-core-go.v1 # gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/gomail.v2 -# gopkg.in/ini.v1 v1.42.0 +# gopkg.in/ini.v1 v1.44.0 gopkg.in/ini.v1 # gopkg.in/ldap.v3 v3.0.2 gopkg.in/ldap.v3 # gopkg.in/macaron.v1 v1.3.2 gopkg.in/macaron.v1 -# gopkg.in/redis.v2 v2.3.2 -gopkg.in/redis.v2 # gopkg.in/src-d/go-billy.v4 v4.3.2 gopkg.in/src-d/go-billy.v4/osfs gopkg.in/src-d/go-billy.v4